diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3766adf794372..3929b064c26c5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -31,7 +31,7 @@ defaults: run: shell: bash concurrency: - group: "${{ ((github.ref == 'refs/heads/try' || github.ref == 'refs/heads/try-perf') && github.sha) || github.ref }}" + group: "${{ github.workflow }}-${{ ((github.ref == 'refs/heads/try' || github.ref == 'refs/heads/try-perf') && github.sha) || github.ref }}" cancel-in-progress: true jobs: pr: @@ -408,7 +408,7 @@ jobs: - name: dist-x86_64-msvc env: RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --host=x86_64-pc-windows-msvc --target=x86_64-pc-windows-msvc --enable-full-tools --enable-profiler" - SCRIPT: PGO_HOST=x86_64-pc-windows-msvc python src/ci/stage-build.py python x.py dist bootstrap --include-default-paths + SCRIPT: python x.py build --set rust.debug=true opt-dist && PGO_HOST=x86_64-pc-windows-msvc ./build/x86_64-pc-windows-msvc/stage0-tools-bin/opt-dist python x.py dist bootstrap --include-default-paths DIST_REQUIRE_ALL_TOOLS: 1 os: windows-2019-8core-32gb - name: dist-i686-msvc diff --git a/Cargo.lock b/Cargo.lock index 5c936ca40e167..96eda77abb279 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -172,6 +172,9 @@ name = "anyhow" version = "1.0.71" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8" +dependencies = [ + "backtrace", +] [[package]] name = "ar_archive_writer" @@ -258,6 +261,12 @@ dependencies = [ "rustc-demangle", ] +[[package]] +name = "base64" +version = "0.21.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" + [[package]] name = "basic-toml" version = "0.1.2" @@ -328,6 +337,10 @@ dependencies = [ [[package]] name = "build_helper" version = "0.1.0" +dependencies = [ + "serde", + "serde_derive", +] [[package]] name = "bump-stage0" @@ -685,6 +698,16 @@ dependencies = [ "rand_xorshift", ] +[[package]] +name = "core-foundation" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "core-foundation-sys" version = "0.8.4" @@ -985,6 +1008,15 @@ dependencies = [ "log", ] +[[package]] +name = "encoding_rs" +version = "0.8.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071a31f4ee85403370b58aca746f01041ede6f0da2730960ad001edc2b71b394" +dependencies = [ + "cfg-if", +] + [[package]] name = "env_logger" version = "0.7.1" @@ -1174,6 +1206,21 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + [[package]] name = "form_urlencoded" version = "1.2.0" @@ -1199,6 +1246,12 @@ version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0845fa252299212f0389d64ba26f34fa32cfe41588355f21ed507c59a0f64541" +[[package]] +name = "fs_extra" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" + [[package]] name = "futf" version = "0.1.5" @@ -1396,6 +1449,25 @@ dependencies = [ "serde", ] +[[package]] +name = "h2" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d357c7ae988e7d2182f7d7871d0b963962420b0678b0997ce7de72001aeab782" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap 1.9.3", + "slab", + "tokio", + "tokio-util", + "tracing", +] + [[package]] name = "handlebars" version = "4.3.7" @@ -1494,6 +1566,49 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "http" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" +dependencies = [ + "bytes", + "http", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" + +[[package]] +name = "httpdate" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" + +[[package]] +name = "humansize" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6cb51c9a029ddc91b07a787f1d86b53ccfa49b0e86688c946ebe8d3555685dd7" +dependencies = [ + "libm 0.2.7", +] + [[package]] name = "humantime" version = "1.3.0" @@ -1509,6 +1624,43 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" +[[package]] +name = "hyper" +version = "0.14.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abfba89e19b959ca163c7752ba59d737c1ceea53a5d31a149c805446fc958064" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper-tls" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +dependencies = [ + "bytes", + "hyper", + "native-tls", + "tokio", + "tokio-native-tls", +] + [[package]] name = "iana-time-zone" version = "0.1.57" @@ -1717,6 +1869,12 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "ipnet" +version = "2.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12b6ee2129af8d4fb011108c73d99a1b83a85977f23b82460c0ae2e25bb4b57f" + [[package]] name = "is-terminal" version = "0.4.8" @@ -1724,7 +1882,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24fddda5af7e54bf7da53067d6e802dbcc381d0a8eef629df528e3ebf68755cb" dependencies = [ "hermit-abi 0.3.1", - "rustix 0.38.1", + "rustix 0.38.2", "windows-sys 0.48.0", ] @@ -1866,6 +2024,12 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fc7aa29613bd6a620df431842069224d8bc9011086b1db4c0e0cd47fa03ec9a" +[[package]] +name = "libm" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4" + [[package]] name = "libz-sys" version = "1.1.9" @@ -2104,6 +2268,17 @@ dependencies = [ "rustc-std-workspace-core", ] +[[package]] +name = "mio" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" +dependencies = [ + "libc", + "wasi", + "windows-sys 0.48.0", +] + [[package]] name = "miow" version = "0.5.0" @@ -2141,6 +2316,24 @@ dependencies = [ "regex", ] +[[package]] +name = "native-tls" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" +dependencies = [ + "lazy_static", + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + [[package]] name = "new_debug_unreachable" version = "1.0.4" @@ -2169,6 +2362,15 @@ dependencies = [ "minimal-lexical", ] +[[package]] +name = "ntapi" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8a3895c6391c39d7fe7ebc444a87eb2991b2a0bc718fdabd071eec617fc68e4" +dependencies = [ + "winapi", +] + [[package]] name = "nu-ansi-term" version = "0.46.0" @@ -2240,6 +2442,32 @@ dependencies = [ "winapi", ] +[[package]] +name = "openssl" +version = "0.10.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "345df152bc43501c5eb9e4654ff05f794effb78d4efe3d53abc158baddc0703d" +dependencies = [ + "bitflags 1.3.2", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.8", +] + [[package]] name = "openssl-probe" version = "0.1.5" @@ -2258,6 +2486,28 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "opt-dist" +version = "0.1.0" +dependencies = [ + "anyhow", + "build_helper", + "camino", + "env_logger 0.10.0", + "fs_extra", + "glob", + "humansize", + "humantime 2.1.0", + "log", + "reqwest", + "serde", + "serde_json", + "sysinfo", + "tar", + "xz", + "zip", +] + [[package]] name = "overload" version = "0.1.1" @@ -2277,7 +2527,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1914cd452d8fccd6f9db48147b29fd4ae05bea9dc5d9ad578509f72415de282" dependencies = [ "cfg-if", - "libm", + "libm 0.1.4", ] [[package]] @@ -2730,6 +2980,43 @@ dependencies = [ "walkdir", ] +[[package]] +name = "reqwest" +version = "0.11.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cde824a14b7c14f85caff81225f411faacc04a2013f41670f41443742b1c1c55" +dependencies = [ + "base64", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "hyper", + "hyper-tls", + "ipnet", + "js-sys", + "log", + "mime", + "native-tls", + "once_cell", + "percent-encoding", + "pin-project-lite", + "serde", + "serde_json", + "serde_urlencoded", + "tokio", + "tokio-native-tls", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "winreg", +] + [[package]] name = "rls" version = "2.0.0" @@ -3159,7 +3446,6 @@ name = "rustc_driver" version = "0.0.0" dependencies = [ "rustc_driver_impl", - "rustix 0.37.11", ] [[package]] @@ -4218,9 +4504,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.37.11" +version = "0.37.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85597d61f83914ddeba6a47b3b8ffe7365107221c2e557ed94426489fefb5f77" +checksum = "8818fa822adcc98b18fedbb3632a6a33213c070556b5aa7c4c8cc21cff565c4c" dependencies = [ "bitflags 1.3.2", "errno", @@ -4232,9 +4518,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.1" +version = "0.38.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbc6396159432b5c8490d4e301d8c705f61860b8b6c863bf79942ce5401968f3" +checksum = "aabcb0461ebd01d6b79945797c27f8529082226cb630a9865a71870ff63532a4" dependencies = [ "bitflags 2.3.3", "errno", @@ -4296,6 +4582,29 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +[[package]] +name = "security-framework" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fc758eb7bffce5b308734e9b0c1468893cae9ff70ebf13e7090be8dcbcc83a8" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f51d0c0d83bec45f16480d0ce0058397a69e48fcdc52d1dc8855fb68acbd31a7" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "self_cell" version = "0.10.2" @@ -4352,6 +4661,18 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + [[package]] name = "sha1" version = "0.10.5" @@ -4630,6 +4951,20 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "sysinfo" +version = "0.29.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9557d0845b86eea8182f7b10dff120214fb6cd9fd937b6f4917714e546a38695" +dependencies = [ + "cfg-if", + "core-foundation-sys", + "libc", + "ntapi", + "once_cell", + "winapi", +] + [[package]] name = "sysroot" version = "0.0.0" @@ -4660,7 +4995,7 @@ dependencies = [ "cfg-if", "fastrand", "redox_syscall 0.3.5", - "rustix 0.37.11", + "rustix 0.37.22", "windows-sys 0.48.0", ] @@ -4701,7 +5036,7 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e6bf6f19e9f8ed8d4048dc22981458ebcf406d67e94cd422e5ecd73d63b3237" dependencies = [ - "rustix 0.37.11", + "rustix 0.37.22", "windows-sys 0.48.0", ] @@ -4849,7 +5184,36 @@ dependencies = [ "autocfg", "backtrace", "bytes", + "libc", + "mio", + "num_cpus", + "pin-project-lite", + "socket2", + "windows-sys 0.48.0", +] + +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f988a1a1adc2fb21f9c12aa96441da33a1728193ae0b95d2be22dbd17fcb4e5c" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", "pin-project-lite", + "tokio", + "tracing", ] [[package]] @@ -4901,6 +5265,12 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ea68304e134ecd095ac6c3574494fc62b909f416c4fca77e440530221e549d3d" +[[package]] +name = "tower-service" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" + [[package]] name = "tracing" version = "0.1.37" @@ -4986,6 +5356,12 @@ dependencies = [ "tracing-subscriber", ] +[[package]] +name = "try-lock" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" + [[package]] name = "twox-hash" version = "1.6.3" @@ -5030,9 +5406,9 @@ checksum = "9e79c4d996edb816c91e4308506774452e55e95c3c9de07b6729e17e15a5ef81" [[package]] name = "ui_test" -version = "0.11.6" +version = "0.11.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24a2e70adc9d18b9b4dd80ea57aeec447103c6fbb354a07c080adad451c645e1" +checksum = "c21899b59f53717dfad29e4f46e5b21a200a1b6888ab86532a07cfc8b48dd78c" dependencies = [ "bstr", "cargo-platform", @@ -5304,6 +5680,15 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -5340,6 +5725,18 @@ dependencies = [ "wasm-bindgen-shared", ] +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f219e0d211ba40266969f6dbdd90636da12f75bee4fc9d6c23d1260dadb51454" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + [[package]] name = "wasm-bindgen-macro" version = "0.2.87" @@ -5369,6 +5766,16 @@ version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" +[[package]] +name = "web-sys" +version = "0.3.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e33b99f4b23ba3eec1a53ac264e35a755f00e966e0065077d6027c0f575b0b97" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + [[package]] name = "winapi" version = "0.3.9" @@ -5563,6 +5970,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "winreg" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" +dependencies = [ + "winapi", +] + [[package]] name = "writeable" version = "0.5.2" @@ -5578,6 +5994,15 @@ dependencies = [ "libc", ] +[[package]] +name = "xz" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c887690ff2a2e233e8e49633461521f98ec57fbff9d59a884c9a4f04ec1da34" +dependencies = [ + "xz2", +] + [[package]] name = "xz2" version = "0.1.7" @@ -5683,3 +6108,15 @@ dependencies = [ "syn 1.0.109", "synstructure 0.12.6", ] + +[[package]] +name = "zip" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261" +dependencies = [ + "byteorder", + "crc32fast", + "crossbeam-utils", + "flate2", +] diff --git a/Cargo.toml b/Cargo.toml index 20b1c656d3558..53bf9a8af2c1b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,6 +43,7 @@ members = [ "src/tools/suggest-tests", "src/tools/generate-windows-sys", "src/tools/rustdoc-gui-test", + "src/tools/opt-dist", ] exclude = [ diff --git a/README.md b/README.md index 901213d2ca977..8a6c559b0b312 100644 --- a/README.md +++ b/README.md @@ -22,8 +22,9 @@ Read ["Installation"] from [The Book]. The Rust build system uses a Python script called `x.py` to build the compiler, which manages the bootstrapping process. It lives at the root of the project. -It also uses a file named `config.toml` to determine various configuration settings for the build. -You can see a full list of options in `config.example.toml`. +It also uses a file named `config.toml` to determine various configuration +settings for the build. You can see a full list of options in +`config.example.toml`. The `x.py` command can be run directly on most Unix systems in the following format: @@ -33,7 +34,8 @@ format: ``` This is how the documentation and examples assume you are running `x.py`. -See the [rustc dev guide][rustcguidebuild] if this does not work on your platform. +See the [rustc dev guide][rustcguidebuild] if this does not work on your +platform. More information about `x.py` can be found by running it with the `--help` flag or reading the [rustc dev guide][rustcguidebuild]. @@ -105,24 +107,26 @@ See [the rustc-dev-guide for more info][sysllvm]. When complete, `./x.py install` will place several programs into `$PREFIX/bin`: `rustc`, the Rust compiler, and `rustdoc`, the - API-documentation tool. By default, it will also include [Cargo], Rust's package manager. - You can disable this behavior by passing `--set build.extended=false` to `./configure`. + API-documentation tool. By default, it will also include [Cargo], Rust's + package manager. You can disable this behavior by passing + `--set build.extended=false` to `./configure`. [Cargo]: https://github.com/rust-lang/cargo #### Configure and Make -This project provides a configure script and makefile (the latter of which just invokes `x.py`). -`./configure` is the recommended way to programatically generate a `config.toml`. `make` is not -recommended (we suggest using `x.py` directly), but it is supported and we try not to break it -unnecessarily. +This project provides a configure script and makefile (the latter of which just +invokes `x.py`). `./configure` is the recommended way to programatically +generate a `config.toml`. `make` is not recommended (we suggest using `x.py` +directly), but it is supported and we try not to break it unnecessarily. ```sh ./configure make && sudo make install ``` -`configure` generates a `config.toml` which can also be used with normal `x.py` invocations. +`configure` generates a `config.toml` which can also be used with normal `x.py` +invocations. ### Building on Windows @@ -193,7 +197,7 @@ toolchain. #### MSVC MSVC builds of Rust additionally require an installation of Visual Studio 2017 -(or later) so `rustc` can use its linker. The simplest way is to get +(or later) so `rustc` can use its linker. The simplest way is to get [Visual Studio], check the "C++ build tools" and "Windows 10 SDK" workload. [Visual Studio]: https://visualstudio.microsoft.com/downloads/ @@ -234,7 +238,8 @@ Windows build triples are: The build triple can be specified by either specifying `--build=` when invoking `x.py` commands, or by creating a `config.toml` file (as described in -[Building on a Unix-like system](#building-on-a-unix-like-system)), and passing `--set build.build=` to `./configure`. +[Building on a Unix-like system](#building-on-a-unix-like-system)), and passing +`--set build.build=` to `./configure`. ## Building Documentation diff --git a/RELEASES.md b/RELEASES.md index fa95df685aaa4..419c20b9071bf 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,3 +1,146 @@ +Version 1.71.0 (2023-07-13) +========================== + + + +Language +-------- + +- [Stabilize `raw-dylib`, `link_ordinal`, `import_name_type` and `-Cdlltool`.](https://github.com/rust-lang/rust/pull/109677/) +- [Uplift `clippy::{drop,forget}_{ref,copy}` lints.](https://github.com/rust-lang/rust/pull/109732/) +- [Type inference is more conservative around constrained vars.](https://github.com/rust-lang/rust/pull/110100/) +- [Use fulfillment to check `Drop` impl compatibility](https://github.com/rust-lang/rust/pull/110577/) + + + +Compiler +-------- + +- [Evaluate place expression in `PlaceMention`](https://github.com/rust-lang/rust/pull/104844/), + making `let _ =` patterns more consistent with respect to the borrow checker. +- [Add `--print deployment-target` flag for Apple targets.](https://github.com/rust-lang/rust/pull/105354/) +- [Stabilize `extern "C-unwind"` and friends.](https://github.com/rust-lang/rust/pull/106075/) + The existing `extern "C"` etc. may change behavior for cross-language unwinding in a future release. +- [Update the version of musl used on `*-linux-musl` targets to 1.2.3](https://github.com/rust-lang/rust/pull/107129/), + enabling [time64](https://musl.libc.org/time64.html) on 32-bit systems. +- [Stabilize `debugger_visualizer`](https://github.com/rust-lang/rust/pull/108668/) + for embedding metadata like Microsoft's Natvis. +- [Enable flatten-format-args by default.](https://github.com/rust-lang/rust/pull/109999/) +- [Make `Self` respect tuple constructor privacy.](https://github.com/rust-lang/rust/pull/111245/) +- [Improve niche placement by trying two strategies and picking the better result.](https://github.com/rust-lang/rust/pull/108106/) +- [Use `apple-m1` as the target CPU for `aarch64-apple-darwin`.](https://github.com/rust-lang/rust/pull/109899/) +- [Add Tier 3 support for the `x86_64h-apple-darwin` target.](https://github.com/rust-lang/rust/pull/108795/) +- [Promote `loongarch64-unknown-linux-gnu` to Tier 2 with host tools.](https://github.com/rust-lang/rust/pull/110936/) + +Refer to Rust's [platform support page][platform-support-doc] +for more information on Rust's tiered platform support. + + + +Libraries +--------- +- [Rework handling of recursive panics.](https://github.com/rust-lang/rust/pull/110975/) + Additional panics are allowed while unwinding, as long as they are caught before escaping + a `Drop` implementation, but panicking within a panic hook is now an immediate abort. +- [Loosen `From<&[T]> for Box<[T]>` bound to `T: Clone`.](https://github.com/rust-lang/rust/pull/103406/) +- [Remove unnecessary `T: Send` bound](https://github.com/rust-lang/rust/pull/111134/) + in `Error for mpsc::SendError` and `TrySendError`. +- [Fix docs for `alloc::realloc`](https://github.com/rust-lang/rust/pull/108630/) + to match `Layout` requirements that the size must not exceed `isize::MAX`. +- [Document `const {}` syntax for `std::thread_local`.](https://github.com/rust-lang/rust/pull/110620/) + This syntax was stabilized in Rust 1.59, but not previously mentioned in release notes. + + + +Stabilized APIs +--------------- + +- [`CStr::is_empty`](https://doc.rust-lang.org/stable/std/ffi/struct.CStr.html#method.is_empty) +- [`BuildHasher::hash_one`](https://doc.rust-lang.org/stable/std/hash/trait.BuildHasher.html#method.hash_one) +- [`NonZeroI*::is_positive`](https://doc.rust-lang.org/stable/std/num/struct.NonZeroI32.html#method.is_positive) +- [`NonZeroI*::is_negative`](https://doc.rust-lang.org/stable/std/num/struct.NonZeroI32.html#method.is_negative) +- [`NonZeroI*::checked_neg`](https://doc.rust-lang.org/stable/std/num/struct.NonZeroI32.html#method.checked_neg) +- [`NonZeroI*::overflowing_neg`](https://doc.rust-lang.org/stable/std/num/struct.NonZeroI32.html#method.overflowing_neg) +- [`NonZeroI*::saturating_neg`](https://doc.rust-lang.org/stable/std/num/struct.NonZeroI32.html#method.saturating_neg) +- [`NonZeroI*::wrapping_neg`](https://doc.rust-lang.org/stable/std/num/struct.NonZeroI32.html#method.wrapping_neg) +- [`Neg for NonZeroI*`](https://doc.rust-lang.org/stable/std/num/struct.NonZeroI32.html#impl-Neg-for-NonZeroI32) +- [`Neg for &NonZeroI*`](https://doc.rust-lang.org/stable/std/num/struct.NonZeroI32.html#impl-Neg-for-%26NonZeroI32) +- [`From<[T; N]> for (T...)`](https://doc.rust-lang.org/stable/std/primitive.array.html#impl-From%3C%5BT;+1%5D%3E-for-(T,)) + (array to N-tuple for N in 1..=12) +- [`From<(T...)> for [T; N]`](https://doc.rust-lang.org/stable/std/primitive.array.html#impl-From%3C(T,)%3E-for-%5BT;+1%5D) + (N-tuple to array for N in 1..=12) +- [`windows::io::AsHandle for Box`](https://doc.rust-lang.org/stable/std/os/windows/io/trait.AsHandle.html#impl-AsHandle-for-Box%3CT%3E) +- [`windows::io::AsHandle for Rc`](https://doc.rust-lang.org/stable/std/os/windows/io/trait.AsHandle.html#impl-AsHandle-for-Rc%3CT%3E) +- [`windows::io::AsHandle for Arc`](https://doc.rust-lang.org/stable/std/os/windows/io/trait.AsHandle.html#impl-AsHandle-for-Arc%3CT%3E) +- [`windows::io::AsSocket for Box`](https://doc.rust-lang.org/stable/std/os/windows/io/trait.AsSocket.html#impl-AsSocket-for-Box%3CT%3E) +- [`windows::io::AsSocket for Rc`](https://doc.rust-lang.org/stable/std/os/windows/io/trait.AsSocket.html#impl-AsSocket-for-Rc%3CT%3E) +- [`windows::io::AsSocket for Arc`](https://doc.rust-lang.org/stable/std/os/windows/io/trait.AsSocket.html#impl-AsSocket-for-Arc%3CT%3E) + +These APIs are now stable in const contexts: + +- [`<*const T>::read`](https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.read) +- [`<*const T>::read_unaligned`](https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.read_unaligned) +- [`<*mut T>::read`](https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.read-1) +- [`<*mut T>::read_unaligned`](https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.read_unaligned-1) +- [`ptr::read`](https://doc.rust-lang.org/stable/std/ptr/fn.read.html) +- [`ptr::read_unaligned`](https://doc.rust-lang.org/stable/std/ptr/fn.read_unaligned.html) +- [`<[T]>::split_at`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.split_at) + + + +Cargo +----- +- [Allow named debuginfo options in `Cargo.toml`.](https://github.com/rust-lang/cargo/pull/11958/) +- [Add `workspace_default_members` to the output of `cargo metadata`.](https://github.com/rust-lang/cargo/pull/11978/) +- [`cargo add` now considers `rust-version` when selecting packages.](https://github.com/rust-lang/cargo/pull/12078/) +- [Automatically inherit workspace fields when running `cargo new`/`cargo init`.](https://github.com/rust-lang/cargo/pull/12069/) + + + +Rustdoc +------- + +- [Add a new `rustdoc::unescaped_backticks` lint for broken inline code.](https://github.com/rust-lang/rust/pull/105848/) +- [Support strikethrough with single tildes.](https://github.com/rust-lang/rust/pull/111152/) (`~~old~~` vs. `~new~`) + + + +Misc +---- + + + +Compatibility Notes +------------------- + +- [Remove structural match from `TypeId`.](https://github.com/rust-lang/rust/pull/103291/) + Code that uses a constant `TypeId` in a pattern will potentially be broken. + Known cases have already been fixed -- in particular, users of the `log` + crate's `kv_unstable` feature should update to `log v0.4.18` or later. +- [Add a `sysroot` crate to represent the standard library crates.](https://github.com/rust-lang/rust/pull/108865/) + This does not affect stable users, but may require adjustment in tools that build their own standard library. +- [Cargo optimizes its usage under `rustup`.](https://github.com/rust-lang/cargo/pull/11917/) When + Cargo detects it will run `rustc` pointing to a rustup proxy, it'll try bypassing the proxy and + use the underlying binary directly. There are assumptions around the interaction with rustup and + `RUSTUP_TOOLCHAIN`. However, it's not expected to affect normal users. +- [When querying a package, Cargo tries only the original name, all hyphens, and all underscores to + handle misspellings.](https://github.com/rust-lang/cargo/pull/12083/) Previously, Cargo tried each + combination of hyphens and underscores, causing excessive requests to crates.io. +- Cargo now [disallows `RUSTUP_HOME`](https://github.com/rust-lang/cargo/pull/12101/) and + [`RUSTUP_TOOLCHAIN`](https://github.com/rust-lang/cargo/pull/12107/) in the `[env]` configuration + table. This is considered to be not a use case Cargo would like to support, since it will likely + cause problems or lead to confusion. + + + +Internal Changes +---------------- + +These changes do not affect any public interfaces of Rust, but they represent +significant improvements to the performance or internals of rustc and related +tools. + + Version 1.70.0 (2023-06-01) ========================== diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs index 73f9deb3143a7..f6875d895d302 100644 --- a/compiler/rustc_abi/src/layout.rs +++ b/compiler/rustc_abi/src/layout.rs @@ -134,7 +134,7 @@ pub trait LayoutCalculator { scalar_valid_range: (Bound, Bound), discr_range_of_repr: impl Fn(i128, i128) -> (Integer, bool), discriminants: impl Iterator, - niche_optimize_enum: bool, + dont_niche_optimize_enum: bool, always_sized: bool, ) -> Option { let dl = self.current_data_layout(); @@ -183,10 +183,10 @@ pub trait LayoutCalculator { // (Typechecking will reject discriminant-sizing attrs.) let v = present_first; - let kind = if is_enum || variants[v].is_empty() { + let kind = if is_enum || variants[v].is_empty() || always_sized { StructKind::AlwaysSized } else { - if !always_sized { StructKind::MaybeUnsized } else { StructKind::AlwaysSized } + StructKind::MaybeUnsized }; let mut st = self.univariant(dl, &variants[v], repr, kind)?; @@ -280,7 +280,7 @@ pub trait LayoutCalculator { } let calculate_niche_filling_layout = || -> Option { - if niche_optimize_enum { + if dont_niche_optimize_enum { return None; } diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index a7198fbf88768..aeb91f82fd3e3 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -2942,6 +2942,7 @@ pub struct StaticItem { #[derive(Clone, Encodable, Decodable, Debug)] pub struct ConstItem { pub defaultness: Defaultness, + pub generics: Generics, pub ty: P, pub expr: Option>, } @@ -3053,6 +3054,7 @@ impl ItemKind { match self { Self::Fn(box Fn { generics, .. }) | Self::TyAlias(box TyAlias { generics, .. }) + | Self::Const(box ConstItem { generics, .. }) | Self::Enum(_, generics) | Self::Struct(_, generics) | Self::Union(_, generics) diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 53a9c9a046ea0..84b56efd3259a 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -1149,10 +1149,11 @@ pub fn noop_flat_map_assoc_item( } fn visit_const_item( - ConstItem { defaultness, ty, expr }: &mut ConstItem, + ConstItem { defaultness, generics, ty, expr }: &mut ConstItem, visitor: &mut T, ) { visit_defaultness(defaultness, visitor); + visitor.visit_generics(generics); visitor.visit_ty(ty); visit_opt(expr, |expr| visitor.visit_expr(expr)); } diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index d9de5b8e197db..83d88718cc223 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -308,8 +308,12 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) { match &item.kind { ItemKind::ExternCrate(_) => {} ItemKind::Use(use_tree) => visitor.visit_use_tree(use_tree, item.id, false), - ItemKind::Static(box StaticItem { ty, mutability: _, expr }) - | ItemKind::Const(box ConstItem { ty, expr, .. }) => { + ItemKind::Static(box StaticItem { ty, mutability: _, expr }) => { + visitor.visit_ty(ty); + walk_list!(visitor, visit_expr, expr); + } + ItemKind::Const(box ConstItem { generics, ty, expr, .. }) => { + visitor.visit_generics(generics); visitor.visit_ty(ty); walk_list!(visitor, visit_expr, expr); } @@ -677,7 +681,8 @@ pub fn walk_assoc_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a AssocItem, visitor.visit_ident(ident); walk_list!(visitor, visit_attribute, attrs); match kind { - AssocItemKind::Const(box ConstItem { ty, expr, .. }) => { + AssocItemKind::Const(box ConstItem { generics, ty, expr, .. }) => { + visitor.visit_generics(generics); visitor.visit_ty(ty); walk_list!(visitor, visit_expr, expr); } diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index ab68436c0939d..26635cab6ef8c 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -231,9 +231,15 @@ impl<'hir> LoweringContext<'_, 'hir> { let (ty, body_id) = self.lower_const_item(t, span, e.as_deref()); hir::ItemKind::Static(ty, *m, body_id) } - ItemKind::Const(box ast::ConstItem { ty, expr, .. }) => { - let (ty, body_id) = self.lower_const_item(ty, span, expr.as_deref()); - hir::ItemKind::Const(ty, body_id) + ItemKind::Const(box ast::ConstItem { generics, ty, expr, .. }) => { + let (generics, (ty, body_id)) = self.lower_generics( + generics, + Const::No, + id, + &ImplTraitContext::Disallowed(ImplTraitPosition::Generic), + |this| this.lower_const_item(ty, span, expr.as_deref()), + ); + hir::ItemKind::Const(ty, generics, body_id) } ItemKind::Fn(box Fn { sig: FnSig { decl, header, span: fn_sig_span }, @@ -723,11 +729,24 @@ impl<'hir> LoweringContext<'_, 'hir> { let trait_item_def_id = hir_id.expect_owner(); let (generics, kind, has_default) = match &i.kind { - AssocItemKind::Const(box ConstItem { ty, expr, .. }) => { - let ty = - self.lower_ty(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy)); - let body = expr.as_ref().map(|x| self.lower_const_body(i.span, Some(x))); - (hir::Generics::empty(), hir::TraitItemKind::Const(ty, body), body.is_some()) + AssocItemKind::Const(box ConstItem { generics, ty, expr, .. }) => { + let (generics, kind) = self.lower_generics( + &generics, + Const::No, + i.id, + &ImplTraitContext::Disallowed(ImplTraitPosition::Generic), + |this| { + let ty = this.lower_ty( + ty, + // FIXME(generic_consts): Should we create `AssocConstTy` and use it here? + &ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy), + ); + let body = expr.as_ref().map(|x| this.lower_const_body(i.span, Some(x))); + + hir::TraitItemKind::Const(ty, body) + }, + ); + (generics, kind, expr.is_some()) } AssocItemKind::Fn(box Fn { sig, generics, body: None, .. }) => { let asyncness = sig.header.asyncness; @@ -825,14 +844,19 @@ impl<'hir> LoweringContext<'_, 'hir> { self.lower_attrs(hir_id, &i.attrs); let (generics, kind) = match &i.kind { - AssocItemKind::Const(box ConstItem { ty, expr, .. }) => { - let ty = - self.lower_ty(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy)); - ( - hir::Generics::empty(), - hir::ImplItemKind::Const(ty, self.lower_const_body(i.span, expr.as_deref())), - ) - } + AssocItemKind::Const(box ConstItem { generics, ty, expr, .. }) => self.lower_generics( + &generics, + Const::No, + i.id, + &ImplTraitContext::Disallowed(ImplTraitPosition::Generic), + |this| { + let ty = this + .lower_ty(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy)); + let body = this.lower_const_body(i.span, expr.as_deref()); + + hir::ImplItemKind::Const(ty, body) + }, + ), AssocItemKind::Fn(box Fn { sig, generics, body, .. }) => { self.current_item = Some(i.span); let asyncness = sig.header.asyncness; diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 096cea945b029..f64ba42aba82a 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -1338,6 +1338,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { self.check_item_named(item.ident, "const"); } + // FIXME(generic_consts): Pretty sure we need to visit the generics of consts here, too. match &item.kind { AssocItemKind::Type(box TyAlias { generics, bounds, ty, .. }) if ctxt == AssocCtxt::Trait => diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index b0dbc2c23403e..c9359349bd69a 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -556,6 +556,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) { gate_all!(const_closures, "const closures are experimental"); gate_all!(builtin_syntax, "`builtin #` syntax is unstable"); gate_all!(explicit_tail_calls, "`become` expression is experimental"); + gate_all!(generic_consts, "generic consts are experimental"); if !visitor.features.negative_bounds { for &span in spans.get(&sym::negative_bounds).iter().copied().flatten() { diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs index 5c01b7ea70a13..8e5de317f2c39 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs @@ -32,7 +32,7 @@ impl<'a> State<'a> { } ast::ForeignItemKind::Static(ty, mutbl, body) => { let def = ast::Defaultness::Final; - self.print_item_const(ident, Some(*mutbl), ty, body.as_deref(), vis, def); + self.print_item_const(ident, Some(*mutbl), None, ty, body.as_deref(), vis, def); } ast::ForeignItemKind::TyAlias(box ast::TyAlias { defaultness, @@ -67,6 +67,7 @@ impl<'a> State<'a> { &mut self, ident: Ident, mutbl: Option, + generics: Option<&ast::Generics>, ty: &ast::Ty, body: Option<&ast::Expr>, vis: &ast::Visibility, @@ -82,6 +83,9 @@ impl<'a> State<'a> { }; self.word_space(leading); self.print_ident(ident); + if let Some(generics) = generics { + self.print_generic_params(&generics.params); + } self.word_space(":"); self.print_type(ty); if body.is_some() { @@ -92,6 +96,9 @@ impl<'a> State<'a> { self.word_space("="); self.print_expr(body); } + if let Some(generics) = generics { + self.print_where_clause(&generics.where_clause); + } self.word(";"); self.end(); // end the outer cbox } @@ -162,16 +169,18 @@ impl<'a> State<'a> { self.print_item_const( item.ident, Some(*mutbl), + None, ty, body.as_deref(), &item.vis, def, ); } - ast::ItemKind::Const(box ast::ConstItem { defaultness, ty, expr }) => { + ast::ItemKind::Const(box ast::ConstItem { defaultness, generics, ty, expr }) => { self.print_item_const( item.ident, None, + Some(generics), ty, expr.as_deref(), &item.vis, @@ -515,8 +524,16 @@ impl<'a> State<'a> { ast::AssocItemKind::Fn(box ast::Fn { defaultness, sig, generics, body }) => { self.print_fn_full(sig, ident, generics, vis, *defaultness, body.as_deref(), attrs); } - ast::AssocItemKind::Const(box ast::ConstItem { defaultness, ty, expr }) => { - self.print_item_const(ident, None, ty, expr.as_deref(), vis, *defaultness); + ast::AssocItemKind::Const(box ast::ConstItem { defaultness, generics, ty, expr }) => { + self.print_item_const( + ident, + None, + Some(generics), + ty, + expr.as_deref(), + vis, + *defaultness, + ); } ast::AssocItemKind::Type(box ast::TyAlias { defaultness, diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs index 6c01fd63b1ec7..225c38efb2cdc 100644 --- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs +++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs @@ -9,7 +9,7 @@ use rustc_middle::mir::{ Body, CallSource, CastKind, ConstraintCategory, FakeReadCause, Local, LocalInfo, Location, Operand, Place, Rvalue, Statement, StatementKind, TerminatorKind, }; -use rustc_middle::ty::adjustment::PointerCast; +use rustc_middle::ty::adjustment::PointerCoercion; use rustc_middle::ty::{self, RegionVid, TyCtxt}; use rustc_span::symbol::{kw, Symbol}; use rustc_span::{sym, DesugaringKind, Span}; @@ -584,7 +584,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { }, // If we see an unsized cast, then if it is our data we should check // whether it is being cast to a trait object. - Rvalue::Cast(CastKind::Pointer(PointerCast::Unsize), operand, ty) => { + Rvalue::Cast( + CastKind::PointerCoercion(PointerCoercion::Unsize), + operand, + ty, + ) => { match operand { Operand::Copy(place) | Operand::Move(place) => { if let Some(from) = place.as_local() { diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 7ed7e125b3cb9..a15e1065c815c 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -28,7 +28,7 @@ use rustc_middle::mir::AssertKind; use rustc_middle::mir::*; use rustc_middle::traits::query::NoSolution; use rustc_middle::traits::ObligationCause; -use rustc_middle::ty::adjustment::PointerCast; +use rustc_middle::ty::adjustment::PointerCoercion; use rustc_middle::ty::cast::CastTy; use rustc_middle::ty::subst::{SubstsRef, UserSubsts}; use rustc_middle::ty::visit::TypeVisitableExt; @@ -1908,7 +1908,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { self.check_operand(op, location); match cast_kind { - CastKind::Pointer(PointerCast::ReifyFnPointer) => { + CastKind::PointerCoercion(PointerCoercion::ReifyFnPointer) => { let fn_sig = op.ty(body, tcx).fn_sig(tcx); // The type that we see in the fcx is like @@ -1937,7 +1937,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } - CastKind::Pointer(PointerCast::ClosureFnPointer(unsafety)) => { + CastKind::PointerCoercion(PointerCoercion::ClosureFnPointer(unsafety)) => { let sig = match op.ty(body, tcx).kind() { ty::Closure(_, substs) => substs.as_closure().sig(), _ => bug!(), @@ -1962,7 +1962,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } - CastKind::Pointer(PointerCast::UnsafeFnPointer) => { + CastKind::PointerCoercion(PointerCoercion::UnsafeFnPointer) => { let fn_sig = op.ty(body, tcx).fn_sig(tcx); // The type that we see in the fcx is like @@ -1991,7 +1991,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } - CastKind::Pointer(PointerCast::Unsize) => { + CastKind::PointerCoercion(PointerCoercion::Unsize) => { let &ty = ty; let trait_ref = ty::TraitRef::from_lang_item( tcx, @@ -2038,7 +2038,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { ); } - CastKind::Pointer(PointerCast::MutToConstPointer) => { + CastKind::PointerCoercion(PointerCoercion::MutToConstPointer) => { let ty::RawPtr(ty::TypeAndMut { ty: ty_from, mutbl: hir::Mutability::Mut, @@ -2080,7 +2080,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } - CastKind::Pointer(PointerCast::ArrayToPointer) => { + CastKind::PointerCoercion(PointerCoercion::ArrayToPointer) => { let ty_from = op.ty(body, tcx); let opt_ty_elem_mut = match ty_from.kind() { diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs index 6bc4f6fc1fcfc..1580a6f6dd3ca 100644 --- a/compiler/rustc_builtin_macros/src/test.rs +++ b/compiler/rustc_builtin_macros/src/test.rs @@ -255,6 +255,7 @@ pub fn expand_test_or_bench( ast::ItemKind::Const( ast::ConstItem { defaultness: ast::Defaultness::Final, + generics: ast::Generics::default(), ty: cx.ty(sp, ast::TyKind::Path(None, test_path("TestDescAndFn"))), // test::TestDescAndFn { expr: Some( diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index 826ce60ed139f..334b2780b499b 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -2,7 +2,7 @@ use rustc_ast::InlineAsmOptions; use rustc_index::IndexVec; -use rustc_middle::ty::adjustment::PointerCast; +use rustc_middle::ty::adjustment::PointerCoercion; use rustc_middle::ty::layout::FnAbiOf; use rustc_middle::ty::print::with_no_trimmed_paths; @@ -571,7 +571,7 @@ fn codegen_stmt<'tcx>( lval.write_cvalue(fx, res); } Rvalue::Cast( - CastKind::Pointer(PointerCast::ReifyFnPointer), + CastKind::PointerCoercion(PointerCoercion::ReifyFnPointer), ref operand, to_ty, ) => { @@ -596,17 +596,17 @@ fn codegen_stmt<'tcx>( } } Rvalue::Cast( - CastKind::Pointer(PointerCast::UnsafeFnPointer), + CastKind::PointerCoercion(PointerCoercion::UnsafeFnPointer), ref operand, to_ty, ) | Rvalue::Cast( - CastKind::Pointer(PointerCast::MutToConstPointer), + CastKind::PointerCoercion(PointerCoercion::MutToConstPointer), ref operand, to_ty, ) | Rvalue::Cast( - CastKind::Pointer(PointerCast::ArrayToPointer), + CastKind::PointerCoercion(PointerCoercion::ArrayToPointer), ref operand, to_ty, ) => { @@ -662,7 +662,7 @@ fn codegen_stmt<'tcx>( } } Rvalue::Cast( - CastKind::Pointer(PointerCast::ClosureFnPointer(_)), + CastKind::PointerCoercion(PointerCoercion::ClosureFnPointer(_)), ref operand, _to_ty, ) => { @@ -684,7 +684,11 @@ fn codegen_stmt<'tcx>( _ => bug!("{} cannot be cast to a fn ptr", operand.layout().ty), } } - Rvalue::Cast(CastKind::Pointer(PointerCast::Unsize), ref operand, _to_ty) => { + Rvalue::Cast( + CastKind::PointerCoercion(PointerCoercion::Unsize), + ref operand, + _to_ty, + ) => { let operand = codegen_operand(fx, operand); crate::unsize::coerce_unsized_into(fx, operand, lval); } diff --git a/compiler/rustc_codegen_cranelift/src/unsize.rs b/compiler/rustc_codegen_cranelift/src/unsize.rs index ff0e12410e703..6aeba13f63949 100644 --- a/compiler/rustc_codegen_cranelift/src/unsize.rs +++ b/compiler/rustc_codegen_cranelift/src/unsize.rs @@ -1,6 +1,6 @@ -//! Codegen of the [`PointerCast::Unsize`] operation. +//! Codegen of the [`PointerCoercion::Unsize`] operation. //! -//! [`PointerCast::Unsize`]: `rustc_middle::ty::adjustment::PointerCast::Unsize` +//! [`PointerCoercion::Unsize`]: `rustc_middle::ty::adjustment::PointerCoercion::Unsize` use crate::prelude::*; diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs index 1ee89b3d5e898..4b27b64962d01 100644 --- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs +++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs @@ -328,8 +328,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let local_ref = &self.locals[local]; - // FIXME Should the return place be named? - let name = if bx.sess().fewer_names() || local == mir::RETURN_PLACE { + let name = if bx.sess().fewer_names() { None } else { Some(match whole_local_var.or(fallback_var.clone()) { diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index ab9eb421c5a9a..956f03d257835 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -11,7 +11,7 @@ use rustc_middle::mir; use rustc_middle::mir::Operand; use rustc_middle::ty::cast::{CastTy, IntTy}; use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, TyAndLayout}; -use rustc_middle::ty::{self, adjustment::PointerCast, Instance, Ty, TyCtxt}; +use rustc_middle::ty::{self, adjustment::PointerCoercion, Instance, Ty, TyCtxt}; use rustc_session::config::OptLevel; use rustc_span::source_map::{Span, DUMMY_SP}; use rustc_target::abi::{self, FIRST_VARIANT}; @@ -32,7 +32,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { cg_operand.val.store(bx, dest); } - mir::Rvalue::Cast(mir::CastKind::Pointer(PointerCast::Unsize), ref source, _) => { + mir::Rvalue::Cast( + mir::CastKind::PointerCoercion(PointerCoercion::Unsize), + ref source, + _, + ) => { // The destination necessarily contains a fat pointer, so if // it's a scalar pair, it's a fat pointer or newtype thereof. if bx.cx().is_backend_scalar_pair(dest.layout) { @@ -411,7 +415,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let lladdr = bx.ptrtoint(llptr, llcast_ty); OperandValue::Immediate(lladdr) } - mir::CastKind::Pointer(PointerCast::ReifyFnPointer) => { + mir::CastKind::PointerCoercion(PointerCoercion::ReifyFnPointer) => { match *operand.layout.ty.kind() { ty::FnDef(def_id, substs) => { let instance = ty::Instance::resolve_for_fn_ptr( @@ -427,7 +431,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { _ => bug!("{} cannot be reified to a fn ptr", operand.layout.ty), } } - mir::CastKind::Pointer(PointerCast::ClosureFnPointer(_)) => { + mir::CastKind::PointerCoercion(PointerCoercion::ClosureFnPointer(_)) => { match *operand.layout.ty.kind() { ty::Closure(def_id, substs) => { let instance = Instance::resolve_closure( @@ -443,11 +447,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { _ => bug!("{} cannot be cast to a fn ptr", operand.layout.ty), } } - mir::CastKind::Pointer(PointerCast::UnsafeFnPointer) => { + mir::CastKind::PointerCoercion(PointerCoercion::UnsafeFnPointer) => { // This is a no-op at the LLVM level. operand.val } - mir::CastKind::Pointer(PointerCast::Unsize) => { + mir::CastKind::PointerCoercion(PointerCoercion::Unsize) => { assert!(bx.cx().is_backend_scalar_pair(cast)); let (lldata, llextra) = match operand.val { OperandValue::Pair(lldata, llextra) => { @@ -470,7 +474,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { base::unsize_ptr(bx, lldata, operand.layout.ty, cast.ty, llextra); OperandValue::Pair(lldata, llextra) } - mir::CastKind::Pointer(PointerCast::MutToConstPointer) + mir::CastKind::PointerCoercion(PointerCoercion::MutToConstPointer) | mir::CastKind::PtrToPtr if bx.cx().is_backend_scalar_pair(operand.layout) => { @@ -504,8 +508,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { base::cast_to_dyn_star(bx, lldata, operand.layout, cast.ty, llextra); OperandValue::Pair(lldata, llextra) } - mir::CastKind::Pointer( - PointerCast::MutToConstPointer | PointerCast::ArrayToPointer, + mir::CastKind::PointerCoercion( + PointerCoercion::MutToConstPointer | PointerCoercion::ArrayToPointer, ) | mir::CastKind::IntToInt | mir::CastKind::FloatToInt diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs index b4db3dff3ffc2..83a072d6f8b62 100644 --- a/compiler/rustc_const_eval/src/interpret/cast.rs +++ b/compiler/rustc_const_eval/src/interpret/cast.rs @@ -4,7 +4,7 @@ use rustc_apfloat::ieee::{Double, Single}; use rustc_apfloat::{Float, FloatConvert}; use rustc_middle::mir::interpret::{InterpResult, PointerArithmetic, Scalar}; use rustc_middle::mir::CastKind; -use rustc_middle::ty::adjustment::PointerCast; +use rustc_middle::ty::adjustment::PointerCoercion; use rustc_middle::ty::layout::{IntegerExt, LayoutOf, TyAndLayout}; use rustc_middle::ty::{self, FloatTy, Ty, TypeAndMut}; use rustc_target::abi::Integer; @@ -24,51 +24,52 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { cast_ty: Ty<'tcx>, dest: &PlaceTy<'tcx, M::Provenance>, ) -> InterpResult<'tcx> { - use rustc_middle::mir::CastKind::*; // FIXME: In which cases should we trigger UB when the source is uninit? match cast_kind { - Pointer(PointerCast::Unsize) => { + CastKind::PointerCoercion(PointerCoercion::Unsize) => { let cast_ty = self.layout_of(cast_ty)?; self.unsize_into(src, cast_ty, dest)?; } - PointerExposeAddress => { + CastKind::PointerExposeAddress => { let src = self.read_immediate(src)?; let res = self.pointer_expose_address_cast(&src, cast_ty)?; self.write_immediate(res, dest)?; } - PointerFromExposedAddress => { + CastKind::PointerFromExposedAddress => { let src = self.read_immediate(src)?; let res = self.pointer_from_exposed_address_cast(&src, cast_ty)?; self.write_immediate(res, dest)?; } - IntToInt | IntToFloat => { + CastKind::IntToInt | CastKind::IntToFloat => { let src = self.read_immediate(src)?; let res = self.int_to_int_or_float(&src, cast_ty)?; self.write_immediate(res, dest)?; } - FloatToFloat | FloatToInt => { + CastKind::FloatToFloat | CastKind::FloatToInt => { let src = self.read_immediate(src)?; let res = self.float_to_float_or_int(&src, cast_ty)?; self.write_immediate(res, dest)?; } - FnPtrToPtr | PtrToPtr => { + CastKind::FnPtrToPtr | CastKind::PtrToPtr => { let src = self.read_immediate(&src)?; let res = self.ptr_to_ptr(&src, cast_ty)?; self.write_immediate(res, dest)?; } - Pointer(PointerCast::MutToConstPointer | PointerCast::ArrayToPointer) => { + CastKind::PointerCoercion( + PointerCoercion::MutToConstPointer | PointerCoercion::ArrayToPointer, + ) => { // These are NOPs, but can be wide pointers. let v = self.read_immediate(src)?; self.write_immediate(*v, dest)?; } - Pointer(PointerCast::ReifyFnPointer) => { + CastKind::PointerCoercion(PointerCoercion::ReifyFnPointer) => { // All reifications must be monomorphic, bail out otherwise. ensure_monomorphic_enough(*self.tcx, src.layout.ty)?; @@ -90,7 +91,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } } - Pointer(PointerCast::UnsafeFnPointer) => { + CastKind::PointerCoercion(PointerCoercion::UnsafeFnPointer) => { let src = self.read_immediate(src)?; match cast_ty.kind() { ty::FnPtr(_) => { @@ -101,7 +102,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } } - Pointer(PointerCast::ClosureFnPointer(_)) => { + CastKind::PointerCoercion(PointerCoercion::ClosureFnPointer(_)) => { // All reifications must be monomorphic, bail out otherwise. ensure_monomorphic_enough(*self.tcx, src.layout.ty)?; @@ -122,7 +123,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } } - DynStar => { + CastKind::DynStar => { if let ty::Dynamic(data, _, ty::DynStar) = cast_ty.kind() { // Initial cast from sized to dyn trait let vtable = self.get_vtable_ptr(src.layout.ty, data.principal())?; @@ -136,7 +137,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } } - Transmute => { + CastKind::Transmute => { assert!(src.layout.is_sized()); assert!(dest.layout.is_sized()); if src.layout.size != dest.layout.size { diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index 24c1fe43d0c68..ca1106384fd33 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -700,8 +700,13 @@ where assert_eq!(src.layout.size, dest.layout.size); } + // Setting `nonoverlapping` here only has an effect when we don't hit the fast-path above, + // but that should at least match what LLVM does where `memcpy` is also only used when the + // type does not have Scalar/ScalarPair layout. + // (Or as the `Assign` docs put it, assignments "not producing primitives" must be + // non-overlapping.) self.mem_copy( - src.ptr, src.align, dest.ptr, dest.align, dest_size, /*nonoverlapping*/ false, + src.ptr, src.align, dest.ptr, dest.align, dest_size, /*nonoverlapping*/ true, ) } diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs index b4f2ae5ca7769..14540e8dfe753 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -9,7 +9,7 @@ use rustc_infer::traits::{ImplSource, Obligation, ObligationCause}; use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::*; use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts}; -use rustc_middle::ty::{self, adjustment::PointerCast, Instance, InstanceDef, Ty, TyCtxt}; +use rustc_middle::ty::{self, adjustment::PointerCoercion, Instance, InstanceDef, Ty, TyCtxt}; use rustc_middle::ty::{TraitRef, TypeVisitableExt}; use rustc_mir_dataflow::{self, Analysis}; use rustc_span::{sym, Span, Symbol}; @@ -521,12 +521,12 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { } Rvalue::Cast( - CastKind::Pointer( - PointerCast::MutToConstPointer - | PointerCast::ArrayToPointer - | PointerCast::UnsafeFnPointer - | PointerCast::ClosureFnPointer(_) - | PointerCast::ReifyFnPointer, + CastKind::PointerCoercion( + PointerCoercion::MutToConstPointer + | PointerCoercion::ArrayToPointer + | PointerCoercion::UnsafeFnPointer + | PointerCoercion::ClosureFnPointer(_) + | PointerCoercion::ReifyFnPointer, ), _, _, @@ -534,7 +534,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { // These are all okay; they only change the type, not the data. } - Rvalue::Cast(CastKind::Pointer(PointerCast::Unsize), _, _) => { + Rvalue::Cast(CastKind::PointerCoercion(PointerCoercion::Unsize), _, _) => { // Unsizing is implemented for CTFE. } diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs index 2a6c341b662c1..4cc923cd93593 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -650,7 +650,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { // FIXME: Add Checks for these CastKind::PointerFromExposedAddress | CastKind::PointerExposeAddress - | CastKind::Pointer(_) => {} + | CastKind::PointerCoercion(_) => {} CastKind::IntToInt | CastKind::IntToFloat => { let input_valid = op_ty.is_integral() || op_ty.is_char() || op_ty.is_bool(); let target_valid = target_type.is_numeric() || target_type.is_char(); diff --git a/compiler/rustc_driver/Cargo.toml b/compiler/rustc_driver/Cargo.toml index 86a54f6befd7c..d7c295418ba6d 100644 --- a/compiler/rustc_driver/Cargo.toml +++ b/compiler/rustc_driver/Cargo.toml @@ -8,6 +8,3 @@ crate-type = ["dylib"] [dependencies] rustc_driver_impl = { path = "../rustc_driver_impl" } -# FIXME(Nilstrieb): 0.37.12 adds eventfd support for FreeBSD, -# but FreeBSD 12 does not support it: https://github.com/bytecodealliance/rustix/issues/716 -rustix = "=0.37.11" diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs index f3ee83fd4d218..51e1fe531dd1f 100644 --- a/compiler/rustc_error_messages/src/lib.rs +++ b/compiler/rustc_error_messages/src/lib.rs @@ -226,7 +226,7 @@ fn register_functions(bundle: &mut FluentBundle) { pub type LazyFallbackBundle = Lrc FluentBundle>>; /// Return the default `FluentBundle` with standard "en-US" diagnostic messages. -#[instrument(level = "trace")] +#[instrument(level = "trace", skip(resources))] pub fn fallback_fluent_bundle( resources: Vec<&'static str>, with_directionality_markers: bool, @@ -242,7 +242,6 @@ pub fn fallback_fluent_bundle( for resource in resources { let resource = FluentResource::try_new(resource.to_string()) .expect("failed to parse fallback fluent resource"); - trace!(?resource); fallback_bundle.add_resource_overriding(resource); } diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs index 264f30fb10a12..96bc127fa5d1a 100644 --- a/compiler/rustc_expand/src/build.rs +++ b/compiler/rustc_expand/src/build.rs @@ -643,7 +643,16 @@ impl<'a> ExtCtxt<'a> { span, name, AttrVec::new(), - ast::ItemKind::Const(ast::ConstItem { defaultness, ty, expr: Some(expr) }.into()), + ast::ItemKind::Const( + ast::ConstItem { + defaultness, + // FIXME(generic_consts): Pass the generics as a parameter. + generics: ast::Generics::default(), + ty, + expr: Some(expr), + } + .into(), + ), ) } diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index 5185820a7276f..df8d27935a80a 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -422,6 +422,9 @@ declare_features! ( (incomplete, generic_associated_types_extended, "1.61.0", Some(95451), None), /// Allows non-trivial generic constants which have to have wfness manually propagated to callers (incomplete, generic_const_exprs, "1.56.0", Some(76560), None), + /// Allows generic parameters and where-clauses on free & associated const items. + // FIXME(fmease): #prePR Fake tracking issue to somewhat please tidy atm + (incomplete, generic_consts, "CURRENT_RUSTC_VERSION", Some(4294967295), None), /// Allows using `..=X` as a patterns in slices. (active, half_open_range_patterns_in_slices, "1.66.0", Some(67264), None), /// Allows `if let` guard in match arms. diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 6c419471de1b4..a69fdb8bf7079 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -3122,9 +3122,9 @@ impl<'hir> Item<'hir> { } /// Expect an [`ItemKind::Const`] or panic. #[track_caller] - pub fn expect_const(&self) -> (&'hir Ty<'hir>, BodyId) { - let ItemKind::Const(ty, body) = self.kind else { self.expect_failed("a constant") }; - (ty, body) + pub fn expect_const(&self) -> (&'hir Ty<'hir>, &'hir Generics<'hir>, BodyId) { + let ItemKind::Const(ty, gen, body) = self.kind else { self.expect_failed("a constant") }; + (ty, gen, body) } /// Expect an [`ItemKind::Fn`] or panic. #[track_caller] @@ -3305,7 +3305,7 @@ pub enum ItemKind<'hir> { /// A `static` item. Static(&'hir Ty<'hir>, Mutability, BodyId), /// A `const` item. - Const(&'hir Ty<'hir>, BodyId), + Const(&'hir Ty<'hir>, &'hir Generics<'hir>, BodyId), /// A function declaration. Fn(FnSig<'hir>, &'hir Generics<'hir>, BodyId), /// A MBE macro definition (`macro_rules!` or `macro`). @@ -3358,6 +3358,7 @@ impl ItemKind<'_> { Some(match *self { ItemKind::Fn(_, ref generics, _) | ItemKind::TyAlias(_, ref generics) + | ItemKind::Const(_, ref generics, _) | ItemKind::OpaqueTy(OpaqueTy { ref generics, .. }) | ItemKind::Enum(_, ref generics) | ItemKind::Struct(_, ref generics) @@ -3553,7 +3554,9 @@ impl<'hir> OwnerNode<'hir> { match self { OwnerNode::Item(Item { kind: - ItemKind::Static(_, _, body) | ItemKind::Const(_, body) | ItemKind::Fn(_, _, body), + ItemKind::Static(_, _, body) + | ItemKind::Const(_, _, body) + | ItemKind::Fn(_, _, body), .. }) | OwnerNode::TraitItem(TraitItem { @@ -3756,9 +3759,9 @@ impl<'hir> Node<'hir> { pub fn ty(self) -> Option<&'hir Ty<'hir>> { match self { Node::Item(it) => match it.kind { - ItemKind::TyAlias(ty, _) | ItemKind::Static(ty, _, _) | ItemKind::Const(ty, _) => { - Some(ty) - } + ItemKind::TyAlias(ty, _) + | ItemKind::Static(ty, _, _) + | ItemKind::Const(ty, _, _) => Some(ty), _ => None, }, Node::TraitItem(it) => match it.kind { @@ -3786,7 +3789,9 @@ impl<'hir> Node<'hir> { match self { Node::Item(Item { kind: - ItemKind::Static(_, _, body) | ItemKind::Const(_, body) | ItemKind::Fn(_, _, body), + ItemKind::Static(_, _, body) + | ItemKind::Const(_, _, body) + | ItemKind::Fn(_, _, body), .. }) | Node::TraitItem(TraitItem { diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 347c1f4637f17..a8a94e6a47687 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -467,11 +467,17 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) { ItemKind::Use(ref path, _) => { visitor.visit_use(path, item.hir_id()); } - ItemKind::Static(ref typ, _, body) | ItemKind::Const(ref typ, body) => { + ItemKind::Static(ref typ, _, body) => { visitor.visit_id(item.hir_id()); visitor.visit_ty(typ); visitor.visit_nested_body(body); } + ItemKind::Const(ref typ, ref generics, body) => { + visitor.visit_id(item.hir_id()); + visitor.visit_ty(typ); + visitor.visit_generics(generics); + visitor.visit_nested_body(body); + } ItemKind::Fn(ref sig, ref generics, body_id) => { visitor.visit_id(item.hir_id()); visitor.visit_fn( diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index 0738961d6ce48..166760166c108 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -248,6 +248,9 @@ hir_analysis_static_specialize = cannot specialize on `'static` lifetime hir_analysis_substs_on_overridden_impl = could not resolve substs on overridden impl +hir_analysis_tait_forward_compat = item constrains opaque type that is not in its signature + .note = this item must mention the opaque type in its signature in order to be able to register hidden types + hir_analysis_target_feature_on_main = `main` function is not allowed to have `#[target_feature]` hir_analysis_too_large_static = extern static is too large for the current architecture diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 270b90fa6b210..a5213f8c7f930 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -518,6 +518,9 @@ fn check_item_type(tcx: TyCtxt<'_>, id: hir::ItemId) { check_static_inhabited(tcx, id.owner_id.def_id); check_static_linkage(tcx, id.owner_id.def_id); } + // FIXME(generic_consts): Do we want to enforce that type params are used? I don't think so. + // Can unused params lead to unsoundness or unwanted behavior though? + // FIXME(generic_consts): Do we correctly compute the variances of type params? DefKind::Const => { tcx.ensure().typeck(id.owner_id.def_id); } @@ -722,7 +725,14 @@ pub(super) fn check_specialization_validity<'tcx>( let result = opt_result.unwrap_or(Ok(())); if let Err(parent_impl) = result { - report_forbidden_specialization(tcx, impl_item, parent_impl); + if !tcx.is_impl_trait_in_trait(impl_item) { + report_forbidden_specialization(tcx, impl_item, parent_impl); + } else { + tcx.sess.delay_span_bug( + DUMMY_SP, + format!("parent item: {:?} not marked as default", parent_impl), + ); + } } } @@ -1485,7 +1495,9 @@ fn opaque_type_cycle_error( } for closure_def_id in visitor.closures { - let Some(closure_local_did) = closure_def_id.as_local() else { continue; }; + let Some(closure_local_did) = closure_def_id.as_local() else { + continue; + }; let typeck_results = tcx.typeck(closure_local_did); let mut label_match = |ty: Ty<'_>, span| { diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index 22e576e345e1f..7d4641477927b 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -76,7 +76,7 @@ fn check_method_is_structurally_compatible<'tcx>( Ok(()) } -/// This function is best explained by example. Consider a trait with it's implementation: +/// This function is best explained by example. Consider a trait with its implementation: /// /// ```rust /// trait Trait<'t, T> { @@ -120,7 +120,7 @@ fn check_method_is_structurally_compatible<'tcx>( /// types: /// /// ```rust,ignore (pseudo-Rust) -/// <'b> fn(t: &'i0 U0, m: &'b) -> Foo +/// <'b> fn(t: &'i0 U0, m: &'b N0) -> Foo /// ``` /// /// We now want to extract and substitute the type of the *trait* @@ -137,7 +137,7 @@ fn check_method_is_structurally_compatible<'tcx>( /// Applying this to the trait method type yields: /// /// ```rust,ignore (pseudo-Rust) -/// <'a> fn(t: &'i0 U0, m: &'a) -> Foo +/// <'a> fn(t: &'i0 U0, m: &'a N0) -> Foo /// ``` /// /// This type is also the same but the name of the bound region (`'a` @@ -262,8 +262,6 @@ fn compare_method_predicate_entailment<'tcx>( // type. // Compute placeholder form of impl and trait method tys. - let tcx = infcx.tcx; - let mut wf_tys = FxIndexSet::default(); let unnormalized_impl_sig = infcx.instantiate_binder_with_fresh_vars( @@ -1669,19 +1667,19 @@ fn compare_synthetic_generics<'tcx>( /// ```rust,ignore (pseudo-Rust) /// trait Foo { /// fn foo(); -/// type bar; +/// type Bar; /// fn baz(); -/// type blah; +/// type Blah; /// } /// /// impl Foo for () { /// fn foo() {} /// //~^ error -/// type bar {} +/// type Bar = (); /// //~^ error /// fn baz() {} /// //~^ error -/// type blah = u32; +/// type Blah = u32; /// //~^ error /// } /// ``` @@ -1770,12 +1768,29 @@ pub(super) fn compare_impl_const_raw( let trait_const_item = tcx.associated_item(trait_const_item_def); let impl_trait_ref = tcx.impl_trait_ref(impl_const_item.container_id(tcx)).unwrap().subst_identity(); - debug!("compare_const_impl(impl_trait_ref={:?})", impl_trait_ref); - let impl_c_span = tcx.def_span(impl_const_item_def.to_def_id()); + debug!("compare_impl_const(impl_trait_ref={:?})", impl_trait_ref); + + compare_number_of_generics(tcx, impl_const_item, trait_const_item, false)?; + compare_generic_param_kinds(tcx, impl_const_item, trait_const_item, false)?; + compare_const_predicate_entailment(tcx, impl_const_item, trait_const_item, impl_trait_ref) +} + +/// The equivalent of [compare_method_predicate_entailment], but for associated constants +/// instead of associated functions. +// FIXME(generic_consts): If possible extract the common parts of `compare_{type,const}_predicate_entailment`. +// FIXME(fmease): This can probably be simplified by a lot. +fn compare_const_predicate_entailment<'tcx>( + tcx: TyCtxt<'tcx>, + impl_ct: ty::AssocItem, + trait_ct: ty::AssocItem, + impl_trait_ref: ty::TraitRef<'tcx>, +) -> Result<(), ErrorGuaranteed> { + let impl_ct_def_id = impl_ct.def_id.expect_local(); + let impl_ct_span = tcx.def_span(impl_ct_def_id); let infcx = tcx.infer_ctxt().build(); - let param_env = tcx.param_env(impl_const_item_def.to_def_id()); + let param_env = tcx.param_env(impl_ct.def_id); let ocx = ObligationCtxt::new(&infcx); // The below is for the most part highly similar to the procedure @@ -1783,22 +1798,22 @@ pub(super) fn compare_impl_const_raw( // because we shouldn't really have to deal with lifetimes or // predicates. In fact some of this should probably be put into // shared functions because of DRY violations... - let trait_to_impl_substs = impl_trait_ref.substs; + let impl_substs = InternalSubsts::identity_for_item(tcx, impl_ct.def_id); + let trait_to_impl_substs = + impl_substs.rebase_onto(tcx, impl_ct.container_id(tcx), impl_trait_ref.substs); // Create a parameter environment that represents the implementation's // method. // Compute placeholder form of impl and trait const tys. - let impl_ty = tcx.type_of(impl_const_item_def.to_def_id()).subst_identity(); - let trait_ty = tcx.type_of(trait_const_item_def).subst(tcx, trait_to_impl_substs); - let mut cause = ObligationCause::new( - impl_c_span, - impl_const_item_def, - ObligationCauseCode::CompareImplItemObligation { - impl_item_def_id: impl_const_item_def, - trait_item_def_id: trait_const_item_def, - kind: impl_const_item.kind, - }, - ); + let impl_ty = tcx.type_of(impl_ct_def_id).subst_identity(); + + let trait_ty = tcx.type_of(trait_ct.def_id).subst(tcx, trait_to_impl_substs); + let code = ObligationCauseCode::CompareImplItemObligation { + impl_item_def_id: impl_ct_def_id, + trait_item_def_id: trait_ct.def_id, + kind: impl_ct.kind, + }; + let mut cause = ObligationCause::new(impl_ct_span, impl_ct_def_id, code.clone()); // There is no "body" here, so just pass dummy id. let impl_ty = ocx.normalize(&cause, param_env, impl_ty); @@ -1818,7 +1833,7 @@ pub(super) fn compare_impl_const_raw( ); // Locate the Span containing just the type of the offending impl - let (ty, _) = tcx.hir().expect_impl_item(impl_const_item_def).expect_const(); + let (ty, _) = tcx.hir().expect_impl_item(impl_ct_def_id).expect_const(); cause.span = ty.span; let mut diag = struct_span_err!( @@ -1826,12 +1841,12 @@ pub(super) fn compare_impl_const_raw( cause.span, E0326, "implemented const `{}` has an incompatible type for trait", - trait_const_item.name + trait_ct.name ); - let trait_c_span = trait_const_item_def.as_local().map(|trait_c_def_id| { + let trait_c_span = trait_ct.def_id.as_local().map(|trait_ct_def_id| { // Add a label to the Span containing just the type of the const - let (ty, _) = tcx.hir().expect_trait_item(trait_c_def_id).expect_const(); + let (ty, _) = tcx.hir().expect_trait_item(trait_ct_def_id).expect_const(); ty.span }); @@ -1850,6 +1865,46 @@ pub(super) fn compare_impl_const_raw( return Err(diag.emit()); }; + let impl_ct_predicates = tcx.predicates_of(impl_ct.def_id); + let trait_ct_predicates = tcx.predicates_of(trait_ct.def_id); + + // FIXME(generic_consts): Is this correct? We already have an ocx... + check_region_bounds_on_impl_item(tcx, impl_ct, trait_ct, false)?; + + // FIXME(generic_consts): It'd be nice if we added a fast-path if the own bounds are empty + // similar to cmp_impl_ty_pred_entail without intro'ing unsoundness. + let impl_ct_own_bounds = impl_ct_predicates.instantiate_own(tcx, impl_substs); + + // The predicates declared by the impl definition, the trait and the + // associated const in the trait are assumed. + let impl_predicates = tcx.predicates_of(impl_ct_predicates.parent.unwrap()); + let mut hybrid_preds = impl_predicates.instantiate_identity(tcx); + hybrid_preds.predicates.extend( + trait_ct_predicates + .instantiate_own(tcx, trait_to_impl_substs) + .map(|(predicate, _)| predicate), + ); + + let hybrid_param_env = ty::ParamEnv::new( + tcx.mk_clauses(&hybrid_preds.predicates), + Reveal::UserFacing, + hir::Constness::Const, + ); + let hybrid_param_env = traits::normalize_param_env_or_error( + tcx, + hybrid_param_env, + ObligationCause::misc(impl_ct_span, impl_ct_def_id), + ); + + // FIXME(generic_consts): Is this correct? We already have an ocx... + for (predicate, span) in impl_ct_own_bounds { + let cause = ObligationCause::misc(span, impl_ct_def_id); + let predicate = ocx.normalize(&cause, hybrid_param_env, predicate); + + let cause = ObligationCause::new(span, impl_ct_def_id, code.clone()); + ocx.register_obligation(traits::Obligation::new(tcx, cause, hybrid_param_env, predicate)); + } + // Check that all obligations are satisfied by the implementation's // version. let errors = ocx.select_all_or_error(); @@ -1858,7 +1913,7 @@ pub(super) fn compare_impl_const_raw( } let outlives_env = OutlivesEnvironment::new(param_env); - ocx.resolve_regions_and_report_errors(impl_const_item_def, &outlives_env) + ocx.resolve_regions_and_report_errors(impl_ct_def_id, &outlives_env) } pub(super) fn compare_impl_ty<'tcx>( @@ -1900,7 +1955,7 @@ fn compare_type_predicate_entailment<'tcx>( return Ok(()); } - // This `HirId` should be used for the `body_id` field on each + // This `DefId` should be used for the `body_id` field on each // `ObligationCause` (and the `FnCtxt`). This is what // `regionck_item` expects. let impl_ty_def_id = impl_ty.def_id.expect_local(); @@ -1919,7 +1974,7 @@ fn compare_type_predicate_entailment<'tcx>( debug!("compare_type_predicate_entailment: bounds={:?}", hybrid_preds); let impl_ty_span = tcx.def_span(impl_ty_def_id); - let normalize_cause = traits::ObligationCause::misc(impl_ty_span, impl_ty_def_id); + let normalize_cause = ObligationCause::misc(impl_ty_span, impl_ty_def_id); let param_env = ty::ParamEnv::new( tcx.mk_clauses(&hybrid_preds.predicates), Reveal::UserFacing, @@ -1968,7 +2023,7 @@ fn compare_type_predicate_entailment<'tcx>( /// /// trait X { type Y: Copy } impl X for T { type Y = S; } /// -/// We are able to normalize `::U` to `S`, and so when we check the +/// We are able to normalize `::Y` to `S`, and so when we check the /// impl is well-formed we have to prove `S: Copy`. /// /// For default associated types the normalization is not possible (the value diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 7a625dd593214..3ecb10e2b01c2 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -300,6 +300,7 @@ fn check_trait_item(tcx: TyCtxt<'_>, trait_item: &hir::TraitItem<'_>) { /// fn into_iter<'a>(&'a self) -> Self::Iter<'a>; /// } /// ``` +// FIXME(generic_consts): This is not relevant to generic consts at all, right? fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRef]) { // Associates every GAT's def_id to a list of possibly missing bounds detected by this lint. let mut required_bounds_by_item = FxHashMap::default(); @@ -981,7 +982,7 @@ fn check_type_defn<'tcx>(tcx: TyCtxt<'tcx>, item: &hir::Item<'tcx>, all_sized: b // intermediate types must be sized. let needs_drop_copy = || { packed && { - let ty = tcx.type_of(variant.fields.raw.last().unwrap().did).subst_identity(); + let ty = tcx.type_of(variant.tail().did).subst_identity(); let ty = tcx.erase_regions(ty); if ty.has_infer() { tcx.sess diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index f47df4f215b3f..18da1d4ed1683 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -256,6 +256,7 @@ fn reject_placeholder_type_signatures_in_item<'tcx>( hir::ItemKind::OpaqueTy(hir::OpaqueTy { generics, .. }) | hir::ItemKind::TyAlias(_, generics) => (generics, false), // `static`, `fn` and `const` are handled elsewhere to suggest appropriate type. + // FIXME(generic_consts): Does "elsewhere" ^^^^^^^ handle `generic_consts` properly? _ => return, }; diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index ccc9f808411c3..2b7c316f30a08 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -209,6 +209,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { | ItemKind::Struct(..) | ItemKind::OpaqueTy(..) | ItemKind::Union(..) => (None, Defaults::Allowed), + ItemKind::Const(..) => (None, Defaults::Deny), _ => (None, Defaults::FutureCompatDisallowed), } } diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index 12936664130da..af0fadf813eb8 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -153,6 +153,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen } ItemKind::Fn(.., generics, _) | ItemKind::TyAlias(_, generics) + | ItemKind::Const(_, generics, _) | ItemKind::Enum(_, generics) | ItemKind::Struct(_, generics) | ItemKind::Union(_, generics) => generics, @@ -757,6 +758,7 @@ pub(super) fn type_param_predicates( ItemKind::Fn(.., generics, _) | ItemKind::Impl(&hir::Impl { generics, .. }) | ItemKind::TyAlias(_, generics) + | ItemKind::Const(_, generics, _) | ItemKind::OpaqueTy(&OpaqueTy { generics, origin: hir::OpaqueTyOrigin::TyAlias { .. }, diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index 97a3e01c52a31..5d242a9af493b 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -22,7 +22,7 @@ use rustc_middle::ty::{self, TyCtxt, TypeSuperVisitable, TypeVisitor}; use rustc_session::lint; use rustc_span::def_id::DefId; use rustc_span::symbol::{sym, Ident}; -use rustc_span::Span; +use rustc_span::{Span, DUMMY_SP}; use std::fmt; use crate::errors; @@ -338,7 +338,17 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { Scope::TraitRefBoundary { .. } => { // We should only see super trait lifetimes if there is a `Binder` above - assert!(supertrait_bound_vars.is_empty()); + // though this may happen when we call `poly_trait_ref_binder_info` with + // an (erroneous, #113423) associated return type bound in an impl header. + if !supertrait_bound_vars.is_empty() { + self.tcx.sess.delay_span_bug( + DUMMY_SP, + format!( + "found supertrait lifetimes without a binder to append \ + them to: {supertrait_bound_vars:?}" + ), + ); + } break (vec![], BinderScopeType::Normal); } @@ -520,12 +530,33 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { // These sorts of items have no lifetime parameters at all. intravisit::walk_item(self, item); } - hir::ItemKind::Static(..) | hir::ItemKind::Const(..) => { + hir::ItemKind::Static(..) => { // No lifetime parameters, but implied 'static. self.with(Scope::Elision { s: self.scope }, |this| { intravisit::walk_item(this, item) }); } + // FIXME(generic_consts): Somehow merge this branch with the `TypeAlias` one below? + hir::ItemKind::Const(_, generics, _) => { + self.with(Scope::Elision { s: self.scope }, |this| { + // These kinds of items have only early-bound lifetime parameters. + let bound_vars = generics.params.iter().map(ResolvedArg::early).collect(); + this.record_late_bound_vars(item.hir_id(), vec![]); + let scope = Scope::Binder { + hir_id: item.hir_id(), + bound_vars, + scope_type: BinderScopeType::Normal, + s: this.scope, + where_bound_origin: None, + }; + this.with(scope, |this| { + let scope = Scope::TraitRefBoundary { s: this.scope }; + this.with(scope, |this| { + intravisit::walk_item(this, item); + }); + }); + }); + } hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin: hir::OpaqueTyOrigin::TyAlias { .. }, .. @@ -819,10 +850,22 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { }) }); } + // FIXME(generic_consts): Somehow deduplicate with the branch above? Const(_, _) => { - // Only methods and types support generics. - assert!(trait_item.generics.params.is_empty()); - intravisit::walk_trait_item(self, trait_item); + let bound_vars = + (&trait_item.generics).params.iter().map(ResolvedArg::early).collect(); + self.record_late_bound_vars(trait_item.hir_id(), vec![]); + let scope = Scope::Binder { + hir_id: trait_item.hir_id(), + bound_vars, + s: self.scope, + scope_type: BinderScopeType::Normal, + where_bound_origin: None, + }; + self.with(scope, |this| { + let scope = Scope::TraitRefBoundary { s: this.scope }; + this.with(scope, |this| intravisit::walk_trait_item(this, trait_item)) + }); } } } @@ -854,10 +897,22 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { }) }); } + // FIXME(generic_consts): Somehow deduplicate with the branch above? Const(_, _) => { - // Only methods and types support generics. - assert!(impl_item.generics.params.is_empty()); - intravisit::walk_impl_item(self, impl_item); + let bound_vars: FxIndexMap = + (&impl_item.generics).params.iter().map(ResolvedArg::early).collect(); + self.record_late_bound_vars(impl_item.hir_id(), vec![]); + let scope = Scope::Binder { + hir_id: impl_item.hir_id(), + bound_vars, + s: self.scope, + scope_type: BinderScopeType::Normal, + where_bound_origin: None, + }; + self.with(scope, |this| { + let scope = Scope::TraitRefBoundary { s: this.scope }; + this.with(scope, |this| intravisit::walk_impl_item(this, impl_item)) + }); } } } diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index 3755342aef5df..64e61aab9f041 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -405,7 +405,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder { + ItemKind::Const(ty, _, body_id) => { if is_suggestable_infer_ty(ty) { infer_placeholder_type( tcx, def_id, body_id, ty.span, item.ident, "constant", diff --git a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs index f4779a3f26533..957a6bb348109 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs @@ -6,7 +6,7 @@ use rustc_middle::hir::nested_filter; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt}; use rustc_span::DUMMY_SP; -use crate::errors::UnconstrainedOpaqueType; +use crate::errors::{TaitForwardCompat, UnconstrainedOpaqueType}; /// Checks "defining uses" of opaque `impl Trait` types to ensure that they meet the restrictions /// laid for "higher-order pattern unification". @@ -139,6 +139,15 @@ impl TaitConstraintLocator<'_> { continue; } constrained = true; + if !self.tcx.opaque_types_defined_by(item_def_id).contains(&self.def_id) { + self.tcx.sess.emit_err(TaitForwardCompat { + span: hidden_type.span, + item_span: self + .tcx + .def_ident_span(item_def_id) + .unwrap_or_else(|| self.tcx.def_span(item_def_id)), + }); + } let concrete_type = self.tcx.erase_regions(hidden_type.remap_generic_params_to_declaration_params( opaque_type_key, diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 205e26d0edaac..c2d2e5f7e50f6 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -184,6 +184,16 @@ pub struct UnconstrainedOpaqueType { pub what: &'static str, } +#[derive(Diagnostic)] +#[diag(hir_analysis_tait_forward_compat)] +#[note] +pub struct TaitForwardCompat { + #[primary_span] + pub span: Span, + #[note] + pub item_span: Span, +} + pub struct MissingTypeParams { pub span: Span, pub def_span: Span, diff --git a/compiler/rustc_hir_analysis/src/hir_wf_check.rs b/compiler/rustc_hir_analysis/src/hir_wf_check.rs index f1765174d79de..ca7679cfba06e 100644 --- a/compiler/rustc_hir_analysis/src/hir_wf_check.rs +++ b/compiler/rustc_hir_analysis/src/hir_wf_check.rs @@ -130,7 +130,7 @@ fn diagnostic_hir_wf_check<'tcx>( hir::Node::Item(item) => match item.kind { hir::ItemKind::TyAlias(ty, _) | hir::ItemKind::Static(ty, _, _) - | hir::ItemKind::Const(ty, _) => vec![ty], + | hir::ItemKind::Const(ty, _, _) => vec![ty], hir::ItemKind::Impl(impl_) => match &impl_.of_trait { Some(t) => t .path diff --git a/compiler/rustc_hir_analysis/src/variance/mod.rs b/compiler/rustc_hir_analysis/src/variance/mod.rs index 49aee6b59a28c..066e7449189ea 100644 --- a/compiler/rustc_hir_analysis/src/variance/mod.rs +++ b/compiler/rustc_hir_analysis/src/variance/mod.rs @@ -7,7 +7,7 @@ use rustc_arena::DroplessArena; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::query::Providers; -use rustc_middle::ty::{self, CrateVariancesMap, ImplTraitInTraitData, SubstsRef, Ty, TyCtxt}; +use rustc_middle::ty::{self, CrateVariancesMap, SubstsRef, Ty, TyCtxt}; use rustc_middle::ty::{TypeSuperVisitable, TypeVisitable}; use std::ops::ControlFlow; @@ -59,13 +59,6 @@ fn variances_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Variance] { DefKind::OpaqueTy | DefKind::ImplTraitPlaceholder => { return variance_of_opaque(tcx, item_def_id); } - DefKind::AssocTy => { - if let Some(ImplTraitInTraitData::Trait { .. }) = - tcx.opt_rpitit_info(item_def_id.to_def_id()) - { - return variance_of_opaque(tcx, item_def_id); - } - } _ => {} } @@ -125,7 +118,8 @@ fn variance_of_opaque(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Varianc // FIXME(-Zlower-impl-trait-in-trait-to-assoc-ty) check whether this is necessary // at all for RPITITs. ty::Alias(_, ty::AliasTy { def_id, substs, .. }) - if self.tcx.is_impl_trait_in_trait(*def_id) => + if self.tcx.is_impl_trait_in_trait(*def_id) + && !self.tcx.lower_impl_trait_in_trait_to_assoc_ty() => { self.visit_opaque(*def_id, substs) } diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index a699cd6c942eb..2d8b956771bb6 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -420,12 +420,13 @@ impl<'a> State<'a> { fn print_associated_const( &mut self, ident: Ident, + generics: &hir::Generics<'_>, ty: &hir::Ty<'_>, default: Option, ) { - self.head(""); self.word_space("const"); self.print_ident(ident); + self.print_generic_params(generics.params); self.word_space(":"); self.print_type(ty); if let Some(expr) = default { @@ -433,6 +434,7 @@ impl<'a> State<'a> { self.word_space("="); self.ann.nested(self, Nested::Body(expr)); } + self.print_where_clause(generics); self.word(";") } @@ -532,9 +534,10 @@ impl<'a> State<'a> { self.word(";"); self.end(); // end the outer cbox } - hir::ItemKind::Const(ty, expr) => { + hir::ItemKind::Const(ty, generics, expr) => { self.head("const"); self.print_ident(item.ident); + self.print_generic_params(generics.params); self.word_space(":"); self.print_type(ty); self.space(); @@ -542,6 +545,7 @@ impl<'a> State<'a> { self.word_space("="); self.ann.nested(self, Nested::Body(expr)); + self.print_where_clause(generics); self.word(";"); self.end(); // end the outer cbox } @@ -836,7 +840,7 @@ impl<'a> State<'a> { self.print_outer_attributes(self.attrs(ti.hir_id())); match ti.kind { hir::TraitItemKind::Const(ty, default) => { - self.print_associated_const(ti.ident, ty, default); + self.print_associated_const(ti.ident, ti.generics, ty, default); } hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Required(arg_names)) => { self.print_method_sig(ti.ident, sig, ti.generics, arg_names, None); @@ -865,7 +869,7 @@ impl<'a> State<'a> { match ii.kind { hir::ImplItemKind::Const(ty, expr) => { - self.print_associated_const(ii.ident, ty, Some(expr)); + self.print_associated_const(ii.ident, ii.generics, ty, Some(expr)); } hir::ImplItemKind::Fn(ref sig, body) => { self.head(""); diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index 71799387458df..633933317c0b5 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -103,15 +103,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Ok(match *t.kind() { ty::Slice(_) | ty::Str => Some(PointerKind::Length), ty::Dynamic(ref tty, _, ty::Dyn) => Some(PointerKind::VTable(tty.principal_def_id())), - ty::Adt(def, substs) if def.is_struct() => { - match def.non_enum_variant().fields.raw.last() { - None => Some(PointerKind::Thin), - Some(f) => { - let field_ty = self.field_ty(span, f, substs); - self.pointer_kind(field_ty, span)? - } + ty::Adt(def, substs) if def.is_struct() => match def.non_enum_variant().tail_opt() { + None => Some(PointerKind::Thin), + Some(f) => { + let field_ty = self.field_ty(span, f, substs); + self.pointer_kind(field_ty, span)? } - } + }, ty::Tuple(fields) => match fields.last() { None => Some(PointerKind::Thin), Some(&f) => self.pointer_kind(f, span)?, diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 108e20ed145a5..dc58d99ed9d74 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -47,7 +47,7 @@ use rustc_infer::infer::{Coercion, DefineOpaqueTypes, InferOk, InferResult}; use rustc_infer::traits::{Obligation, PredicateObligation}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::adjustment::{ - Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, PointerCast, + Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, PointerCoercion, }; use rustc_middle::ty::error::TypeError; use rustc_middle::ty::relate::RelateResult; @@ -592,7 +592,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { }; let coerce_target = self.next_ty_var(origin); let mut coercion = self.unify_and(coerce_target, target, |target| { - let unsize = Adjustment { kind: Adjust::Pointer(PointerCast::Unsize), target }; + let unsize = Adjustment { kind: Adjust::Pointer(PointerCoercion::Unsize), target }; match reborrow { None => vec![unsize], Some((ref deref, ref autoref)) => vec![deref.clone(), autoref.clone(), unsize], @@ -849,7 +849,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { a, fn_ty_a, b, - simple(Adjust::Pointer(PointerCast::UnsafeFnPointer)), + simple(Adjust::Pointer(PointerCoercion::UnsafeFnPointer)), identity, ) } @@ -893,16 +893,16 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { |unsafe_ty| { vec![ Adjustment { - kind: Adjust::Pointer(PointerCast::ReifyFnPointer), + kind: Adjust::Pointer(PointerCoercion::ReifyFnPointer), target: a_fn_pointer, }, Adjustment { - kind: Adjust::Pointer(PointerCast::UnsafeFnPointer), + kind: Adjust::Pointer(PointerCoercion::UnsafeFnPointer), target: unsafe_ty, }, ] }, - simple(Adjust::Pointer(PointerCast::ReifyFnPointer)), + simple(Adjust::Pointer(PointerCoercion::ReifyFnPointer)), )?; obligations.extend(o2); @@ -952,7 +952,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { self.unify_and( pointer_ty, b, - simple(Adjust::Pointer(PointerCast::ClosureFnPointer(unsafety))), + simple(Adjust::Pointer(PointerCoercion::ClosureFnPointer(unsafety))), ) } _ => self.unify_and(a, b, identity), @@ -987,7 +987,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { ] }) } else if mt_a.mutbl != mutbl_b { - self.unify_and(a_unsafe, b, simple(Adjust::Pointer(PointerCast::MutToConstPointer))) + self.unify_and(a_unsafe, b, simple(Adjust::Pointer(PointerCoercion::MutToConstPointer))) } else { self.unify_and(a_unsafe, b, identity) } @@ -1187,13 +1187,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Reify both sides and return the reified fn pointer type. let fn_ptr = Ty::new_fn_ptr(self.tcx, sig); let prev_adjustment = match prev_ty.kind() { - ty::Closure(..) => Adjust::Pointer(PointerCast::ClosureFnPointer(a_sig.unsafety())), - ty::FnDef(..) => Adjust::Pointer(PointerCast::ReifyFnPointer), + ty::Closure(..) => { + Adjust::Pointer(PointerCoercion::ClosureFnPointer(a_sig.unsafety())) + } + ty::FnDef(..) => Adjust::Pointer(PointerCoercion::ReifyFnPointer), _ => unreachable!(), }; let next_adjustment = match new_ty.kind() { - ty::Closure(..) => Adjust::Pointer(PointerCast::ClosureFnPointer(b_sig.unsafety())), - ty::FnDef(..) => Adjust::Pointer(PointerCast::ReifyFnPointer), + ty::Closure(..) => { + Adjust::Pointer(PointerCoercion::ClosureFnPointer(b_sig.unsafety())) + } + ty::FnDef(..) => Adjust::Pointer(PointerCoercion::ReifyFnPointer), _ => unreachable!(), }; for expr in exprs.iter().map(|e| e.as_coercion_site()) { diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 72b29f7b6e906..521dc30982a0c 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -1392,7 +1392,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }); let Some((_, hir::Node::Local(hir::Local { ty: Some(ty), .. }) - | hir::Node::Item(hir::Item { kind: hir::ItemKind::Const(ty, _), .. })) + | hir::Node::Item(hir::Item { kind: hir::ItemKind::Const(ty, _, _), .. })) ) = parent_node else { return }; diff --git a/compiler/rustc_hir_typeck/src/inherited.rs b/compiler/rustc_hir_typeck/src/inherited.rs index 05e5db9f0f3a3..d5619af2aae17 100644 --- a/compiler/rustc_hir_typeck/src/inherited.rs +++ b/compiler/rustc_hir_typeck/src/inherited.rs @@ -80,7 +80,7 @@ impl<'tcx> Inherited<'tcx> { let infcx = tcx .infer_ctxt() .ignoring_regions() - .with_opaque_type_inference(DefiningAnchor::Bind(hir_owner.def_id)) + .with_opaque_type_inference(DefiningAnchor::Bind(def_id)) .build(); let typeck_results = RefCell::new(ty::TypeckResults::new(hir_owner)); diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index 6f82ffcfe4ae4..eaa4d6857735e 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -102,7 +102,7 @@ fn primary_body_of( ) -> Option<(hir::BodyId, Option<&hir::Ty<'_>>, Option<&hir::FnSig<'_>>)> { match node { Node::Item(item) => match item.kind { - hir::ItemKind::Const(ty, body) | hir::ItemKind::Static(ty, _, body) => { + hir::ItemKind::Const(ty, _, body) | hir::ItemKind::Static(ty, _, body) => { Some((body, Some(ty), None)) } hir::ItemKind::Fn(ref sig, .., body) => Some((body, None, Some(sig))), diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs index 55ad99e55af82..87edb80314805 100644 --- a/compiler/rustc_hir_typeck/src/method/confirm.rs +++ b/compiler/rustc_hir_typeck/src/method/confirm.rs @@ -10,7 +10,7 @@ use rustc_hir_analysis::astconv::generics::{ use rustc_hir_analysis::astconv::{AstConv, CreateSubstsForGenericArgsCtxt, IsMethodCall}; use rustc_infer::infer::{self, DefineOpaqueTypes, InferOk}; use rustc_middle::traits::{ObligationCauseCode, UnifyReceiverContext}; -use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCast}; +use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCoercion}; use rustc_middle::ty::adjustment::{AllowTwoPhase, AutoBorrow, AutoBorrowMutability}; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::subst::{self, SubstsRef}; @@ -212,8 +212,10 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { region, ty::TypeAndMut { mutbl: mutbl.into(), ty: unsized_ty }, ); - adjustments - .push(Adjustment { kind: Adjust::Pointer(PointerCast::Unsize), target }); + adjustments.push(Adjustment { + kind: Adjust::Pointer(PointerCoercion::Unsize), + target, + }); } } Some(probe::AutorefOrPtrAdjustment::ToConstPtr) => { @@ -226,7 +228,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { }; adjustments.push(Adjustment { - kind: Adjust::Pointer(PointerCast::MutToConstPointer), + kind: Adjust::Pointer(PointerCoercion::MutToConstPointer), target, }); } diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 19f82fbd3bf73..16410fe97bc46 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -394,8 +394,8 @@ 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_resolve_type(span, expected); - if let ty::Ref(_, inner_ty, _) = expected.kind() - && matches!(inner_ty.kind(), ty::Slice(_)) + if let ty::Ref(_, inner_ty, _) = *expected.kind() + && self.try_structurally_resolve_type(span, inner_ty).is_slice() { let tcx = self.tcx; trace!(?lt.hir_id.local_id, "polymorphic byte string lit"); @@ -922,7 +922,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { 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), .. + 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) { diff --git a/compiler/rustc_hir_typeck/src/place_op.rs b/compiler/rustc_hir_typeck/src/place_op.rs index 826cee3f98202..fd43b475e3af4 100644 --- a/compiler/rustc_hir_typeck/src/place_op.rs +++ b/compiler/rustc_hir_typeck/src/place_op.rs @@ -6,7 +6,7 @@ use rustc_hir as hir; use rustc_hir_analysis::autoderef::Autoderef; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::InferOk; -use rustc_middle::ty::adjustment::{Adjust, Adjustment, OverloadedDeref, PointerCast}; +use rustc_middle::ty::adjustment::{Adjust, Adjustment, OverloadedDeref, PointerCoercion}; use rustc_middle::ty::adjustment::{AllowTwoPhase, AutoBorrow, AutoBorrowMutability}; use rustc_middle::ty::{self, Ty}; use rustc_span::symbol::{sym, Ident}; @@ -173,7 +173,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } if unsize { adjustments.push(Adjustment { - kind: Adjust::Pointer(PointerCast::Unsize), + kind: Adjust::Pointer(PointerCoercion::Unsize), target: method.sig.inputs()[0], }); } @@ -441,7 +441,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let [ .., Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(..)), .. }, - Adjustment { kind: Adjust::Pointer(PointerCast::Unsize), ref mut target }, + Adjustment { kind: Adjust::Pointer(PointerCoercion::Unsize), ref mut target }, ] = adjustments[..] { *target = method.sig.inputs()[0]; diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index 01332483a06db..10645753609a0 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -11,7 +11,7 @@ use rustc_hir::intravisit::{self, Visitor}; use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282; use rustc_middle::hir::place::Place as HirPlace; use rustc_middle::mir::FakeReadCause; -use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCast}; +use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCoercion}; use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt}; use rustc_middle::ty::{self, ClosureSizeProfileData, Ty, TyCtxt}; @@ -251,7 +251,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { // Since this is "after" the other adjustment to be // discarded, we do an extra `pop()` if let Some(Adjustment { - kind: Adjust::Pointer(PointerCast::Unsize), .. + kind: Adjust::Pointer(PointerCoercion::Unsize), .. }) = a.pop() { // So the borrow discard actually happens here diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index b826ced045340..2ec190577fa29 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -2069,7 +2069,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { visitor.visit_body(body); visitor.result.map(|r| &r.peel_refs().kind) } - Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Const(ty, _), .. })) => { + Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Const(ty, _, _), .. })) => { Some(&ty.peel_refs().kind) } _ => None, diff --git a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs index c9a8f8131dffb..63613b59020fb 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs @@ -257,7 +257,7 @@ impl Trait for X { ); } } - (ty::Alias(ty::Opaque, alias), _) | (_, ty::Alias(ty::Opaque, alias)) if alias.def_id.is_local() && matches!(tcx.def_kind(body_owner_def_id), DefKind::AssocFn | DefKind::AssocConst) => { + (ty::Alias(ty::Opaque, alias), _) | (_, ty::Alias(ty::Opaque, alias)) if alias.def_id.is_local() && matches!(tcx.def_kind(body_owner_def_id), DefKind::Fn | DefKind::Static(_) | DefKind::Const | DefKind::AssocFn | DefKind::AssocConst) => { if tcx.is_type_alias_impl_trait(alias.def_id) { if !tcx.opaque_types_defined_by(body_owner_def_id.expect_local()).contains(&alias.def_id.expect_local()) { let sp = tcx.def_ident_span(body_owner_def_id).unwrap_or_else(|| tcx.def_span(body_owner_def_id)); diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs index 3098b8bc2f9b2..5927f79a18333 100644 --- a/compiler/rustc_infer/src/infer/opaque_types.rs +++ b/compiler/rustc_infer/src/infer/opaque_types.rs @@ -473,17 +473,6 @@ where } } - ty::Alias(ty::Projection, proj) if self.tcx.is_impl_trait_in_trait(proj.def_id) => { - // Skip lifetime parameters that are not captures. - let variances = self.tcx.variances_of(proj.def_id); - - for (v, s) in std::iter::zip(variances, proj.substs.iter()) { - if *v != ty::Variance::Bivariant { - s.visit_with(self); - } - } - } - _ => { ty.super_visit_with(self); } diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index b821933e9086f..bf9a1b0627aea 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -1531,9 +1531,10 @@ declare_lint_pass!( impl<'tcx> LateLintPass<'tcx> for UnusedBrokenConst { fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) { match it.kind { - hir::ItemKind::Const(_, body_id) => { + hir::ItemKind::Const(_, _, 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(generic_consts): Does this work properly with generic consts? cx.tcx.ensure().const_eval_poly(def_id); } hir::ItemKind::Static(_, _, body_id) => { diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 5f2eb890c4eba..b2e7b8551e8a8 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -24,7 +24,7 @@ pub fn associated_body(node: Node<'_>) -> Option<(LocalDefId, BodyId)> { match node { Node::Item(Item { owner_id, - kind: ItemKind::Const(_, body) | ItemKind::Static(.., body) | ItemKind::Fn(.., body), + kind: ItemKind::Const(_, _, body) | ItemKind::Static(.., body) | ItemKind::Fn(.., body), .. }) | Node::TraitItem(TraitItem { diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index efb01b0faba17..28c50587800c0 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -2014,7 +2014,7 @@ impl<'tcx> Rvalue<'tcx> { | CastKind::IntToFloat | CastKind::FnPtrToPtr | CastKind::PtrToPtr - | CastKind::Pointer(_) + | CastKind::PointerCoercion(_) | CastKind::PointerFromExposedAddress | CastKind::DynStar | CastKind::Transmute, diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index abb3b3d953be0..7f1d3820341b4 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -7,7 +7,7 @@ use super::{BasicBlock, Constant, Local, SwitchTargets, UserTypeProjection}; use crate::mir::coverage::{CodeRegion, CoverageKind}; use crate::traits::Reveal; -use crate::ty::adjustment::PointerCast; +use crate::ty::adjustment::PointerCoercion; use crate::ty::subst::SubstsRef; use crate::ty::{self, List, Ty}; use crate::ty::{Region, UserTypeAnnotationIndex}; @@ -1230,9 +1230,9 @@ pub enum CastKind { /// An address-to-pointer cast that picks up an exposed provenance. /// See the docs on `from_exposed_addr` for more details. PointerFromExposedAddress, - /// All sorts of pointer-to-pointer casts. Note that reference-to-raw-ptr casts are + /// Pointer related casts that are done by coercions. Note that reference-to-raw-ptr casts are /// translated into `&raw mut/const *r`, i.e., they are not actually casts. - Pointer(PointerCast), + PointerCoercion(PointerCoercion), /// Cast into a dyn* object. DynStar, IntToInt, diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index 0f3ad6d0151d1..e9af5070e5e81 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -18,7 +18,7 @@ use rustc_index::IndexVec; use rustc_middle::middle::region; use rustc_middle::mir::interpret::AllocId; use rustc_middle::mir::{self, BinOp, BorrowKind, FakeReadCause, Mutability, UnOp}; -use rustc_middle::ty::adjustment::PointerCast; +use rustc_middle::ty::adjustment::PointerCoercion; use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::{self, AdtDef, FnSig, List, Ty, UpvarSubsts}; use rustc_middle::ty::{CanonicalUserType, CanonicalUserTypeAnnotation}; @@ -329,9 +329,10 @@ pub enum ExprKind<'tcx> { NeverToAny { source: ExprId, }, - /// A pointer cast. More information can be found in [`PointerCast`]. - Pointer { - cast: PointerCast, + /// A pointer coercion. More information can be found in [`PointerCoercion`]. + /// Pointer casts that cannot be done by coercions are represented by [`ExprKind::Cast`]. + PointerCoercion { + cast: PointerCoercion, source: ExprId, }, /// A `loop` expression. diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs index 9cc07677e0e36..14bc1ac0ce75f 100644 --- a/compiler/rustc_middle/src/thir/visit.rs +++ b/compiler/rustc_middle/src/thir/visit.rs @@ -65,7 +65,7 @@ pub fn walk_expr<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, expr: &Exp Cast { source } => visitor.visit_expr(&visitor.thir()[source]), Use { source } => visitor.visit_expr(&visitor.thir()[source]), NeverToAny { source } => visitor.visit_expr(&visitor.thir()[source]), - Pointer { source, cast: _ } => visitor.visit_expr(&visitor.thir()[source]), + PointerCoercion { source, cast: _ } => visitor.visit_expr(&visitor.thir()[source]), Let { expr, .. } => { visitor.visit_expr(&visitor.thir()[expr]); } diff --git a/compiler/rustc_middle/src/ty/adjustment.rs b/compiler/rustc_middle/src/ty/adjustment.rs index a4893684bc856..76931ceaa69fa 100644 --- a/compiler/rustc_middle/src/ty/adjustment.rs +++ b/compiler/rustc_middle/src/ty/adjustment.rs @@ -6,7 +6,7 @@ use rustc_span::Span; use rustc_target::abi::FieldIdx; #[derive(Clone, Copy, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)] -pub enum PointerCast { +pub enum PointerCoercion { /// Go from a fn-item type to a fn-pointer type. ReifyFnPointer, @@ -99,7 +99,7 @@ pub enum Adjust<'tcx> { /// Take the address and produce either a `&` or `*` pointer. Borrow(AutoBorrow<'tcx>), - Pointer(PointerCast), + Pointer(PointerCoercion), /// Cast into a dyn* object. DynStar, diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 0fe801ad2ed1a..d95b05ef75408 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -1110,12 +1110,11 @@ where /// /// This takes two primary parameters: /// -/// * `codegen_fn_attr_flags` - these are flags calculated as part of the -/// codegen attrs for a defined function. For function pointers this set of -/// flags is the empty set. This is only applicable for Rust-defined -/// functions, and generally isn't needed except for small optimizations where -/// we try to say a function which otherwise might look like it could unwind -/// doesn't actually unwind (such as for intrinsics and such). +/// * `fn_def_id` - the `DefId` of the function. If this is provided then we can +/// determine more precisely if the function can unwind. If this is not provided +/// then we will only infer whether the function can unwind or not based on the +/// ABI of the function. For example, a function marked with `#[rustc_nounwind]` +/// is known to not unwind even if it's using Rust ABI. /// /// * `abi` - this is the ABI that the function is defined with. This is the /// primary factor for determining whether a function can unwind or not. @@ -1147,11 +1146,6 @@ where /// aborts the process. /// * This affects whether functions have the LLVM `nounwind` attribute, which /// affects various optimizations and codegen. -/// -/// FIXME: this is actually buggy with respect to Rust functions. Rust functions -/// compiled with `-Cpanic=unwind` and referenced from another crate compiled -/// with `-Cpanic=abort` will look like they can't unwind when in fact they -/// might (from a foreign exception or similar). #[inline] #[tracing::instrument(level = "debug", skip(tcx))] pub fn fn_can_unwind(tcx: TyCtxt<'_>, fn_def_id: Option, abi: SpecAbi) -> bool { diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 938b901c2f794..aa8bfd3178ce0 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -2035,6 +2035,22 @@ impl VariantDef { &self.fields[FieldIdx::from_u32(0)] } + + /// Returns the last field in this variant, if present. + #[inline] + pub fn tail_opt(&self) -> Option<&FieldDef> { + self.fields.raw.last() + } + + /// Returns the last field in this variant. + /// + /// # Panics + /// + /// Panics, if the variant has no fields. + #[inline] + pub fn tail(&self) -> &FieldDef { + self.tail_opt().expect("expected unsized ADT to have a tail field") + } } impl PartialEq for VariantDef { diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 4a639a2a0fe6e..7220d133f68c5 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -332,7 +332,7 @@ TrivialTypeTraversalAndLiftImpls! { crate::ty::IntVarValue, crate::ty::ParamConst, crate::ty::ParamTy, - crate::ty::adjustment::PointerCast, + crate::ty::adjustment::PointerCoercion, crate::ty::RegionVid, crate::ty::UniverseIndex, crate::ty::Variance, diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 720d770eed4d6..e2e4a2dbdc88a 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -230,7 +230,7 @@ impl<'tcx> TyCtxt<'tcx> { if !def.is_struct() { break; } - match def.non_enum_variant().fields.raw.last() { + match def.non_enum_variant().tail_opt() { Some(field) => { f(); ty = field.ty(self, substs); @@ -304,7 +304,7 @@ impl<'tcx> TyCtxt<'tcx> { (&ty::Adt(a_def, a_substs), &ty::Adt(b_def, b_substs)) if a_def == b_def && a_def.is_struct() => { - if let Some(f) = a_def.non_enum_variant().fields.raw.last() { + if let Some(f) = a_def.non_enum_variant().tail_opt() { a = f.ty(self, a_substs); b = f.ty(self, b_substs); } else { diff --git a/compiler/rustc_mir_build/src/build/expr/as_place.rs b/compiler/rustc_mir_build/src/build/expr/as_place.rs index ac2d099be508f..60acd279f9ebb 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_place.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs @@ -535,7 +535,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { | ExprKind::Cast { .. } | ExprKind::Use { .. } | ExprKind::NeverToAny { .. } - | ExprKind::Pointer { .. } + | ExprKind::PointerCoercion { .. } | ExprKind::Repeat { .. } | ExprKind::Borrow { .. } | ExprKind::AddressOf { .. } diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs index 5c886ac4d9b0b..32ffb990be61f 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs @@ -300,7 +300,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let cast_kind = mir_cast_kind(ty, expr.ty); block.and(Rvalue::Cast(cast_kind, source, expr.ty)) } - ExprKind::Pointer { cast, source } => { + ExprKind::PointerCoercion { cast, source } => { let source = unpack!( block = this.as_operand( block, @@ -310,7 +310,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { NeedsTemporary::No ) ); - block.and(Rvalue::Cast(CastKind::Pointer(cast), source, expr.ty)) + block.and(Rvalue::Cast(CastKind::PointerCoercion(cast), source, expr.ty)) } ExprKind::Array { ref fields } => { // (*) We would (maybe) be closer to codegen if we diff --git a/compiler/rustc_mir_build/src/build/expr/category.rs b/compiler/rustc_mir_build/src/build/expr/category.rs index 2fe9cac637808..e07ba6b6e9383 100644 --- a/compiler/rustc_mir_build/src/build/expr/category.rs +++ b/compiler/rustc_mir_build/src/build/expr/category.rs @@ -63,7 +63,7 @@ impl Category { | ExprKind::Binary { .. } | ExprKind::Box { .. } | ExprKind::Cast { .. } - | ExprKind::Pointer { .. } + | ExprKind::PointerCoercion { .. } | ExprKind::Repeat { .. } | ExprKind::Assign { .. } | ExprKind::AssignOp { .. } diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs index 91c464252f1cc..e30fdcbbe185b 100644 --- a/compiler/rustc_mir_build/src/build/expr/into.rs +++ b/compiler/rustc_mir_build/src/build/expr/into.rs @@ -556,7 +556,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { | ExprKind::Binary { .. } | ExprKind::Box { .. } | ExprKind::Cast { .. } - | ExprKind::Pointer { .. } + | ExprKind::PointerCoercion { .. } | ExprKind::Repeat { .. } | ExprKind::Array { .. } | ExprKind::Tuple { .. } diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs index 3a2c506bb9879..e6806177dec75 100644 --- a/compiler/rustc_mir_build/src/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -16,7 +16,7 @@ use rustc_middle::mir::*; use rustc_middle::thir::*; use rustc_middle::ty::util::IntTypeExt; use rustc_middle::ty::GenericArg; -use rustc_middle::ty::{self, adjustment::PointerCast, Ty, TyCtxt}; +use rustc_middle::ty::{self, adjustment::PointerCoercion, Ty, TyCtxt}; use rustc_span::def_id::DefId; use rustc_span::symbol::{sym, Symbol}; use rustc_span::Span; @@ -423,7 +423,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { source_info, temp, Rvalue::Cast( - CastKind::Pointer(PointerCast::Unsize), + CastKind::PointerCoercion(PointerCoercion::Unsize), Operand::Copy(val), ty, ), @@ -436,7 +436,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block, source_info, slice, - Rvalue::Cast(CastKind::Pointer(PointerCast::Unsize), expect, ty), + Rvalue::Cast( + CastKind::PointerCoercion(PointerCoercion::Unsize), + expect, + ty, + ), ); expect = Operand::Move(slice); } diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index d828e71c7ac0b..b54122fba8bd1 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -562,7 +562,7 @@ fn construct_const<'a, 'tcx>( // Figure out what primary body this item has. let (span, const_ty_span) = match tcx.hir().get(hir_id) { Node::Item(hir::Item { - kind: hir::ItemKind::Static(ty, _, _) | hir::ItemKind::Const(ty, _), + kind: hir::ItemKind::Static(ty, _, _) | hir::ItemKind::Const(ty, _, _), span, .. }) diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index 105564b787428..6b2b140fa2584 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -303,7 +303,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { | ExprKind::NeverToAny { .. } | ExprKind::PlaceTypeAscription { .. } | ExprKind::ValueTypeAscription { .. } - | ExprKind::Pointer { .. } + | ExprKind::PointerCoercion { .. } | ExprKind::Repeat { .. } | ExprKind::StaticRef { .. } | ExprKind::ThreadLocalRef { .. } diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index a5c141b71f67a..37537683f0dd7 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -13,7 +13,7 @@ use rustc_middle::middle::region; use rustc_middle::mir::{self, BinOp, BorrowKind, UnOp}; use rustc_middle::thir::*; use rustc_middle::ty::adjustment::{ - Adjust, Adjustment, AutoBorrow, AutoBorrowMutability, PointerCast, + Adjust, Adjustment, AutoBorrow, AutoBorrowMutability, PointerCoercion, }; use rustc_middle::ty::subst::InternalSubsts; use rustc_middle::ty::{ @@ -125,11 +125,16 @@ impl<'tcx> Cx<'tcx> { }; let kind = match adjustment.kind { - Adjust::Pointer(PointerCast::Unsize) => { + Adjust::Pointer(PointerCoercion::Unsize) => { adjust_span(&mut expr); - ExprKind::Pointer { cast: PointerCast::Unsize, source: self.thir.exprs.push(expr) } + ExprKind::PointerCoercion { + cast: PointerCoercion::Unsize, + source: self.thir.exprs.push(expr), + } + } + Adjust::Pointer(cast) => { + ExprKind::PointerCoercion { cast, source: self.thir.exprs.push(expr) } } - Adjust::Pointer(cast) => ExprKind::Pointer { cast, source: self.thir.exprs.push(expr) }, Adjust::NeverToAny if adjustment.target.is_never() => return expr, Adjust::NeverToAny => ExprKind::NeverToAny { source: self.thir.exprs.push(expr) }, Adjust::Deref(None) => { @@ -192,9 +197,9 @@ impl<'tcx> Cx<'tcx> { // Special cased so that we can type check that the element // type of the source matches the pointed to type of the // destination. - ExprKind::Pointer { + ExprKind::PointerCoercion { source: self.mirror_expr(source), - cast: PointerCast::ArrayToPointer, + cast: PointerCoercion::ArrayToPointer, } } else { // check whether this is casting an enum variant discriminant @@ -210,17 +215,18 @@ impl<'tcx> Cx<'tcx> { // so we wouldn't have to compute and store the actual value let hir::ExprKind::Path(ref qpath) = source.kind else { - return ExprKind::Cast { source: self.mirror_expr(source)}; + return ExprKind::Cast { source: self.mirror_expr(source) }; }; let res = self.typeck_results().qpath_res(qpath, source.hir_id); let ty = self.typeck_results().node_type(source.hir_id); let ty::Adt(adt_def, substs) = ty.kind() else { - return ExprKind::Cast { source: self.mirror_expr(source)}; + return ExprKind::Cast { source: self.mirror_expr(source) }; }; - let Res::Def(DefKind::Ctor(CtorOf::Variant, CtorKind::Const), variant_ctor_id) = res else { - return ExprKind::Cast { source: self.mirror_expr(source)}; + let Res::Def(DefKind::Ctor(CtorOf::Variant, CtorKind::Const), variant_ctor_id) = res + else { + return ExprKind::Cast { source: self.mirror_expr(source) }; }; let idx = adt_def.variant_index_with_ctor_id(variant_ctor_id); @@ -353,19 +359,35 @@ impl<'tcx> Cx<'tcx> { }); } } - let adt_data = - if let hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) = fun.kind { - // Tuple-like ADTs are represented as ExprKind::Call. We convert them here. - expr_ty.ty_adt_def().and_then(|adt_def| match path.res { - Res::Def(DefKind::Ctor(_, CtorKind::Fn), ctor_id) => { + + // Tuple-like ADTs are represented as ExprKind::Call. We convert them here. + let adt_data = if let hir::ExprKind::Path(ref qpath) = fun.kind + && let Some(adt_def) = expr_ty.ty_adt_def() { + match qpath { + hir::QPath::Resolved(_, ref path) => { + match path.res { + Res::Def(DefKind::Ctor(_, CtorKind::Fn), ctor_id) => { + Some((adt_def, adt_def.variant_index_with_ctor_id(ctor_id))) + } + Res::SelfCtor(..) => Some((adt_def, FIRST_VARIANT)), + _ => None, + } + } + hir::QPath::TypeRelative(_ty, _) => { + if let Some((DefKind::Ctor(_, CtorKind::Fn), ctor_id)) = + self.typeck_results().type_dependent_def(fun.hir_id) + { Some((adt_def, adt_def.variant_index_with_ctor_id(ctor_id))) + } else { + None } - Res::SelfCtor(..) => Some((adt_def, FIRST_VARIANT)), - _ => None, - }) - } else { - None - }; + + } + _ => None, + } + } else { + None + }; if let Some((adt_def, index)) = adt_data { let substs = self.typeck_results().node_substs(fun.hir_id); let user_provided_types = self.typeck_results().user_provided_types(); diff --git a/compiler/rustc_mir_build/src/thir/print.rs b/compiler/rustc_mir_build/src/thir/print.rs index 0b6029bf3882e..8d7c624a80560 100644 --- a/compiler/rustc_mir_build/src/thir/print.rs +++ b/compiler/rustc_mir_build/src/thir/print.rs @@ -301,7 +301,7 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> { self.print_expr(*source, depth_lvl + 2); print_indented!(self, "}", depth_lvl); } - Pointer { cast, source } => { + PointerCoercion { cast, source } => { print_indented!(self, "Pointer {", depth_lvl); print_indented!(self, format!("cast: {:?}", cast), depth_lvl + 1); print_indented!(self, "source:", depth_lvl + 1); diff --git a/compiler/rustc_mir_transform/src/normalize_array_len.rs b/compiler/rustc_mir_transform/src/normalize_array_len.rs index 3d61d33ce3536..6c3b7c58fab5e 100644 --- a/compiler/rustc_mir_transform/src/normalize_array_len.rs +++ b/compiler/rustc_mir_transform/src/normalize_array_len.rs @@ -41,7 +41,7 @@ fn compute_slice_length<'tcx>( for (local, rvalue, _) in ssa.assignments(body) { match rvalue { Rvalue::Cast( - CastKind::Pointer(ty::adjustment::PointerCast::Unsize), + CastKind::PointerCoercion(ty::adjustment::PointerCoercion::Unsize), operand, cast_ty, ) => { diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 4a5953c11492c..242269e9d1aa4 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -176,7 +176,7 @@ 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::query::TyCtxtAt; -use rustc_middle::ty::adjustment::{CustomCoerceUnsized, PointerCast}; +use rustc_middle::ty::adjustment::{CustomCoerceUnsized, PointerCoercion}; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts}; use rustc_middle::ty::{ @@ -231,8 +231,8 @@ impl<'tcx> UsageMap<'tcx> { assert!(self.used_map.insert(user_item, used_items).is_none()); } - pub fn get_user_items(&self, item: MonoItem<'tcx>) -> Option<&[MonoItem<'tcx>]> { - self.user_map.get(&item).map(|items| items.as_slice()) + pub fn get_user_items(&self, item: MonoItem<'tcx>) -> &[MonoItem<'tcx>] { + self.user_map.get(&item).map(|items| items.as_slice()).unwrap_or(&[]) } /// Internally iterate over all inlined items used by `item`. @@ -617,7 +617,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> { // have to instantiate all methods of the trait being cast to, so we // can build the appropriate vtable. mir::Rvalue::Cast( - mir::CastKind::Pointer(PointerCast::Unsize), + mir::CastKind::PointerCoercion(PointerCoercion::Unsize), ref operand, target_ty, ) @@ -643,7 +643,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> { } } mir::Rvalue::Cast( - mir::CastKind::Pointer(PointerCast::ReifyFnPointer), + mir::CastKind::PointerCoercion(PointerCoercion::ReifyFnPointer), ref operand, _, ) => { @@ -652,7 +652,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> { visit_fn_use(self.tcx, fn_ty, false, span, &mut self.output); } mir::Rvalue::Cast( - mir::CastKind::Pointer(PointerCast::ClosureFnPointer(_)), + mir::CastKind::PointerCoercion(PointerCoercion::ClosureFnPointer(_)), ref operand, _, ) => { diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs index f4535fbd58fa0..da76cf2236c70 100644 --- a/compiler/rustc_monomorphize/src/partitioning.rs +++ b/compiler/rustc_monomorphize/src/partitioning.rs @@ -427,9 +427,9 @@ fn merge_codegen_units<'tcx>( // zero-padded suffixes, which means they are automatically sorted by // names. The numeric suffix width depends on the number of CGUs, which // is always greater than zero: - // - [1,9] CGUS: `0`, `1`, `2`, ... - // - [10,99] CGUS: `00`, `01`, `02`, ... - // - [100,999] CGUS: `000`, `001`, `002`, ... + // - [1,9] CGUs: `0`, `1`, `2`, ... + // - [10,99] CGUs: `00`, `01`, `02`, ... + // - [100,999] CGUs: `000`, `001`, `002`, ... // - etc. // // If we didn't zero-pad the sorted-by-name order would be `XYZ-cgu.0`, @@ -458,7 +458,7 @@ fn internalize_symbols<'tcx>( /// used to keep track of that. #[derive(Clone, PartialEq, Eq, Debug)] enum MonoItemPlacement { - SingleCgu { cgu_name: Symbol }, + SingleCgu(Symbol), MultipleCgus, } @@ -466,7 +466,7 @@ fn internalize_symbols<'tcx>( let single_codegen_unit = codegen_units.len() == 1; if !single_codegen_unit { - for cgu in codegen_units.iter_mut() { + for cgu in codegen_units.iter() { for item in cgu.items().keys() { // If there is more than one codegen unit, we need to keep track // in which codegen units each monomorphization is placed. @@ -474,13 +474,13 @@ fn internalize_symbols<'tcx>( Entry::Occupied(e) => { let placement = e.into_mut(); debug_assert!(match *placement { - MonoItemPlacement::SingleCgu { cgu_name } => cgu_name != cgu.name(), + MonoItemPlacement::SingleCgu(cgu_name) => cgu_name != cgu.name(), MonoItemPlacement::MultipleCgus => true, }); *placement = MonoItemPlacement::MultipleCgus; } Entry::Vacant(e) => { - e.insert(MonoItemPlacement::SingleCgu { cgu_name: cgu.name() }); + e.insert(MonoItemPlacement::SingleCgu(cgu.name())); } } } @@ -490,7 +490,7 @@ fn internalize_symbols<'tcx>( // For each internalization candidates in each codegen unit, check if it is // used from outside its defining codegen unit. for cgu in codegen_units { - let home_cgu = MonoItemPlacement::SingleCgu { cgu_name: cgu.name() }; + let home_cgu = MonoItemPlacement::SingleCgu(cgu.name()); for (item, linkage_and_visibility) in cgu.items_mut() { if !internalization_candidates.contains(item) { @@ -501,20 +501,20 @@ fn internalize_symbols<'tcx>( if !single_codegen_unit { debug_assert_eq!(mono_item_placements[item], home_cgu); - if let Some(user_items) = cx.usage_map.get_user_items(*item) { - if user_items - .iter() - .filter_map(|user_item| { - // Some user mono items might not have been - // instantiated. We can safely ignore those. - mono_item_placements.get(user_item) - }) - .any(|placement| *placement != home_cgu) - { - // Found a user from another CGU, so skip to the next item - // without marking this one as internal. - continue; - } + if cx + .usage_map + .get_user_items(*item) + .iter() + .filter_map(|user_item| { + // Some user mono items might not have been + // instantiated. We can safely ignore those. + mono_item_placements.get(user_item) + }) + .any(|placement| *placement != home_cgu) + { + // Found a user from another CGU, so skip to the next item + // without marking this one as internal. + continue; } } diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index 9787d98c1a49a..9716c4f18d9e3 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -690,6 +690,10 @@ parse_single_colon_import_path = expected `::`, found `:` parse_single_colon_struct_type = found single colon in a struct field type path .suggestion = write a path separator here +parse_static_with_generics = static items may not have generic parameters + +parse_static_with_where_clause = static items may not have a where clause + parse_struct_literal_body_without_path = struct literal body without path .suggestion = you might have forgotten to add the struct literal inside the block @@ -847,6 +851,12 @@ parse_visibility_not_followed_by_item = visibility `{$vis}` is not followed by a .label = the visibility .help = you likely meant to define an item, e.g., `{$vis} fn foo() {"{}"}` +parse_where_clause_before_const_body = where clauses are not allowed before const item bodies + .label = unexpected where clause + .name_label = while parsing this const item + .body_label = the item body + .suggestion = move the body before the where clause + parse_where_clause_before_tuple_struct_body = where clauses are not allowed before tuple struct bodies .label = unexpected where clause .name_label = while parsing this tuple struct diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 96e1c0e3c6d9e..8be956208a540 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -2692,3 +2692,41 @@ pub(crate) struct ExpectedBuiltinIdent { #[primary_span] pub span: Span, } + +#[derive(Diagnostic)] +#[diag(parse_static_with_generics)] +pub(crate) struct StaticWithGenerics { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(parse_static_with_where_clause)] +pub(crate) struct StaticWithWhereClause { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(parse_where_clause_before_const_body)] +pub(crate) struct WhereClauseBeforeConstBody { + #[primary_span] + #[label] + pub span: Span, + #[label(parse_name_label)] + pub name: Span, + #[label(parse_body_label)] + pub body: Span, + #[subdiagnostic] + pub sugg: Option, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion(parse_suggestion, applicability = "machine-applicable")] +pub(crate) struct WhereClauseBeforeConstBodySugg { + #[suggestion_part(code = "= {snippet} ")] + pub left: Span, + pub snippet: String, + #[suggestion_part(code = "")] + pub right: Span, +} diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 1470180dea714..3d9d8c58beeef 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -227,7 +227,7 @@ impl<'a> Parser<'a> { // STATIC ITEM self.bump(); // `static` let m = self.parse_mutability(); - let (ident, ty, expr) = self.parse_item_global(Some(m))?; + let (ident, _, ty, expr) = self.parse_item_global(Some(m))?; (ident, ItemKind::Static(Box::new(StaticItem { ty, mutability: m, expr }))) } else if let Const::Yes(const_span) = self.parse_constness(Case::Sensitive) { // CONST ITEM @@ -236,8 +236,16 @@ impl<'a> Parser<'a> { self.recover_const_impl(const_span, attrs, def_())? } else { self.recover_const_mut(const_span); - let (ident, ty, expr) = self.parse_item_global(None)?; - (ident, ItemKind::Const(Box::new(ConstItem { defaultness: def_(), ty, expr }))) + let (ident, generics, ty, expr) = self.parse_item_global(None)?; + ( + ident, + ItemKind::Const(Box::new(ConstItem { + defaultness: def_(), + generics, + ty, + expr, + })), + ) } } else if self.check_keyword(kw::Trait) || self.check_auto_or_unsafe_trait_item() { // TRAIT ITEM @@ -878,6 +886,7 @@ impl<'a> Parser<'a> { self.sess.emit_err(errors::AssociatedStaticItemNotAllowed { span }); AssocItemKind::Const(Box::new(ConstItem { defaultness: Defaultness::Final, + generics: Generics::default(), ty, expr, })) @@ -892,7 +901,7 @@ impl<'a> Parser<'a> { /// Parses a `type` alias with the following grammar: /// ```ebnf - /// TypeAlias = "type" Ident Generics {":" GenericBounds}? {"=" Ty}? ";" ; + /// TypeAlias = "type" Ident Generics (":" GenericBounds)? WhereClause ("=" Ty)? WhereClause ";" ; /// ``` /// The `"type"` has already been eaten. fn parse_type_alias(&mut self, defaultness: Defaultness) -> PResult<'a, ItemInfo> { @@ -1220,28 +1229,103 @@ impl<'a> Parser<'a> { Ok(impl_info) } - /// Parse `["const" | ("static" "mut"?)] $ident ":" $ty (= $expr)?` with - /// `["const" | ("static" "mut"?)]` already parsed and stored in `m`. + /// Parse a static or const item with the prefix `"const" | "static" "mut"?` already parsed and stored in `m`. /// - /// When `m` is `"const"`, `$ident` may also be `"_"`. + /// ```ebnf + /// Static = "static" "mut"? $ident ":" $ty (= $expr)? ";" ; + /// Const = "const" ($ident | "_") Generics ":" $ty (= $expr)? WhereClause ";" ; + /// ``` + // FIXME(generic_consts): Should we forbid underscore identifiers if we have generic parameters? + // FIXME(fmease): The control-flow is a bit too hairy, simplify it if possible. fn parse_item_global( &mut self, m: Option, - ) -> PResult<'a, (Ident, P, Option>)> { + ) -> PResult<'a, (Ident, Generics, P, Option>)> { let id = if m.is_none() { self.parse_ident_or_underscore() } else { self.parse_ident() }?; + let mut generics = if m.is_none() || self.may_recover() { + let generics = self.parse_generics()?; + // Check the span for emptiness instead of the list of parameters in order to correctly + // recognize and subsequently flag empty parameter lists (`<>`) as unstable. + if !generics.span.is_empty() { + if m.is_none() { + self.sess.gated_spans.gate(sym::generic_consts, generics.span); + } else { + self.sess.emit_err(errors::StaticWithGenerics { span: generics.span }); + } + } + generics + } else { + Generics::default() + }; + // Parse the type of a `const` or `static mut?` item. // That is, the `":" $ty` fragment. - let ty = match (self.eat(&token::Colon), self.check(&token::Eq) | self.check(&token::Semi)) - { - // If there wasn't a `:` or the colon was followed by a `=` or `;` recover a missing type. + // FIXME: This could maybe benefit from `.may_recover()`? + let ty = match ( + self.eat(&token::Colon), + self.check(&token::Eq) | self.check(&token::Semi) | self.check_keyword(kw::Where), + ) { + // If there wasn't a `:` or the colon was followed by a `=`, `;` or `where`, recover a missing type. (true, false) => self.parse_ty()?, (colon, _) => self.recover_missing_const_type(colon, m), }; + let before_where_clause = + if self.may_recover() { self.parse_where_clause()? } else { WhereClause::default() }; + let expr = if self.eat(&token::Eq) { Some(self.parse_expr()?) } else { None }; + + let after_where_clause = if m.is_none() || self.may_recover() { + self.parse_where_clause()? + } else { + WhereClause::default() + }; + + if before_where_clause.has_where_token && m.is_none() && let Some(expr) = &expr { + self.sess.emit_err(errors::WhereClauseBeforeConstBody { + span: before_where_clause.span, + name: id.span, + body: expr.span, + sugg: if !after_where_clause.has_where_token { + self.sess.source_map().span_to_snippet(expr.span).ok().map(|body| { + errors::WhereClauseBeforeConstBodySugg { + left: before_where_clause.span.shrink_to_lo(), + snippet: body, + right: before_where_clause.span.shrink_to_hi().to(expr.span), + } + }) + } else { + // FIXME(generic_consts): Provide a structured suggestion to merge the first + // where-clause into the second one. + None + }, + }); + } + + let mut predicates = before_where_clause.predicates; + predicates.extend(after_where_clause.predicates); + let where_clause = WhereClause { + has_where_token: before_where_clause.has_where_token + || after_where_clause.has_where_token, + predicates, + span: if after_where_clause.has_where_token { + after_where_clause.span + } else { + before_where_clause.span + }, + }; + if where_clause.has_where_token { + if m.is_none() { + self.sess.gated_spans.gate(sym::generic_consts, where_clause.span); + } else { + self.sess.emit_err(errors::StaticWithWhereClause { span: where_clause.span }); + } + } + generics.where_clause = where_clause; + self.expect_semi()?; - Ok((id, ty, expr)) + Ok((id, generics, ty, expr)) } /// We were supposed to parse `":" $ty` but the `:` or the type was missing. diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs index 160528e4074d4..7dec5b0acc882 100644 --- a/compiler/rustc_passes/src/reachable.rs +++ b/compiler/rustc_passes/src/reachable.rs @@ -236,7 +236,7 @@ impl<'tcx> ReachableContext<'tcx> { // Reachable constants will be inlined into other crates // unconditionally, so we need to make sure that their // contents are also reachable. - hir::ItemKind::Const(_, init) | hir::ItemKind::Static(_, _, init) => { + hir::ItemKind::Const(_, _, init) | hir::ItemKind::Static(_, _, init) => { self.visit_nested_body(init); } diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 90cb312edd203..3f146d87c9f30 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -2401,25 +2401,19 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { }); } - ItemKind::Static(box ast::StaticItem { ref ty, ref expr, .. }) - | ItemKind::Const(box ast::ConstItem { ref ty, ref expr, .. }) => { + ItemKind::Static(box ast::StaticItem { ref ty, ref expr, .. }) => { self.with_static_rib(|this| { this.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Static), |this| { this.visit_ty(ty); }); this.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Infer), |this| { if let Some(expr) = expr { - let constant_item_kind = match item.kind { - ItemKind::Const(..) => ConstantItemKind::Const, - ItemKind::Static(..) => ConstantItemKind::Static, - _ => unreachable!(), - }; // We already forbid generic params because of the above item rib, // so it doesn't matter whether this is a trivial constant. this.with_constant_rib( IsRepeatExpr::No, ConstantHasGenerics::Yes, - Some((item.ident, constant_item_kind)), + Some((item.ident, ConstantItemKind::Static)), |this| this.visit_expr(expr), ); } @@ -2427,6 +2421,50 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { }); } + ItemKind::Const(box ast::ConstItem { ref generics, ref ty, ref expr, .. }) => { + // FIXME(generic_consts): Is the ordering of ribs correct? Right now, it's + // STATIC <- LIFETIME_ANON_REPORT <- GENERICS <- LIFETIME_ELIDED_STATIC {,<- CONSTANT} + self.with_static_rib(|this| { + this.with_lifetime_rib(LifetimeRibKind::AnonymousReportError, |this| { + this.with_generic_param_rib( + &generics.params, + RibKind::Item(HasGenericParams::Yes(generics.span)), + LifetimeRibKind::Generics { + binder: item.id, + kind: LifetimeBinderKind::Item, + span: generics.span, + }, + |this| { + this.with_lifetime_rib( + LifetimeRibKind::Elided(LifetimeRes::Static), + |this| { + this.visit_generics(generics); + this.visit_ty(ty); + }, + ); + + this.with_lifetime_rib( + LifetimeRibKind::Elided(LifetimeRes::Infer), + |this| { + let Some(expr) = expr else { return; }; + + // FIXME(generic_consts): Is this still true? + // > We already forbid generic params because of the above item rib, + // > so it doesn't matter whether this is a trivial constant. + this.with_constant_rib( + IsRepeatExpr::No, + ConstantHasGenerics::Yes, + Some((item.ident, ConstantItemKind::Const)), + |this| this.visit_expr(expr), + ) + }, + ); + }, + ); + }) + }) + } + ItemKind::Use(ref use_tree) => { self.future_proof_import(use_tree); } @@ -2688,28 +2726,42 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { for item in trait_items { self.resolve_doc_links(&item.attrs, MaybeExported::Ok(item.id)); match &item.kind { - AssocItemKind::Const(box ast::ConstItem { ty, expr, .. }) => { - self.visit_ty(ty); - // Only impose the restrictions of `ConstRibKind` for an - // actual constant expression in a provided default. - if let Some(expr) = expr { - // We allow arbitrary const expressions inside of associated consts, - // even if they are potentially not const evaluatable. - // - // Type parameters can already be used and as associated consts are - // not used as part of the type system, this is far less surprising. - self.with_lifetime_rib( - LifetimeRibKind::Elided(LifetimeRes::Infer), - |this| { - this.with_constant_rib( - IsRepeatExpr::No, - ConstantHasGenerics::Yes, - None, - |this| this.visit_expr(expr), - ) - }, - ); - } + // FIXME(generic_consts): Reuse `walk_assoc_item` here somehow? + AssocItemKind::Const(box ast::ConstItem { generics, ty, expr, .. }) => { + self.with_generic_param_rib( + &generics.params, + RibKind::AssocItem, + LifetimeRibKind::Generics { + binder: item.id, + span: generics.span, + kind: LifetimeBinderKind::Item, + }, + |this| { + this.visit_generics(generics); + this.visit_ty(ty); + + // Only impose the restrictions of `ConstRibKind` for an + // actual constant expression in a provided default. + if let Some(expr) = expr { + // We allow arbitrary const expressions inside of associated consts, + // even if they are potentially not const evaluatable. + // + // Type parameters can already be used and as associated consts are + // not used as part of the type system, this is far less surprising. + this.with_lifetime_rib( + LifetimeRibKind::Elided(LifetimeRes::Infer), + |this| { + this.with_constant_rib( + IsRepeatExpr::No, + ConstantHasGenerics::Yes, + None, + |this| this.visit_expr(expr), + ) + }, + ); + } + }, + ); } AssocItemKind::Fn(box Fn { generics, .. }) => { walk_assoc_item(self, generics, LifetimeBinderKind::Function, item); @@ -2864,36 +2916,53 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { use crate::ResolutionError::*; self.resolve_doc_links(&item.attrs, MaybeExported::ImplItem(trait_id.ok_or(&item.vis))); match &item.kind { - AssocItemKind::Const(box ast::ConstItem { ty, expr, .. }) => { + // FIXME(generic_consts): Reuse `walk_assoc_item` here somehow? + AssocItemKind::Const(box ast::ConstItem { generics, ty, expr, .. }) => { debug!("resolve_implementation AssocItemKind::Const"); - // If this is a trait impl, ensure the const - // exists in trait - self.check_trait_item( - item.id, - item.ident, - &item.kind, - ValueNS, - item.span, - seen_trait_items, - |i, s, c| ConstNotMemberOfTrait(i, s, c), - ); - self.visit_ty(ty); - if let Some(expr) = expr { - // We allow arbitrary const expressions inside of associated consts, - // even if they are potentially not const evaluatable. - // - // Type parameters can already be used and as associated consts are - // not used as part of the type system, this is far less surprising. - self.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Infer), |this| { - this.with_constant_rib( - IsRepeatExpr::No, - ConstantHasGenerics::Yes, - None, - |this| this.visit_expr(expr), - ) - }); - } + self.with_generic_param_rib( + &generics.params, + RibKind::AssocItem, + LifetimeRibKind::Generics { + binder: item.id, + span: generics.span, + kind: LifetimeBinderKind::Item, + }, + |this| { + // If this is a trait impl, ensure the const + // exists in trait + this.check_trait_item( + item.id, + item.ident, + &item.kind, + ValueNS, + item.span, + seen_trait_items, + |i, s, c| ConstNotMemberOfTrait(i, s, c), + ); + + this.visit_generics(generics); + this.visit_ty(ty); + if let Some(expr) = expr { + // We allow arbitrary const expressions inside of associated consts, + // even if they are potentially not const evaluatable. + // + // Type parameters can already be used and as associated consts are + // not used as part of the type system, this is far less surprising. + this.with_lifetime_rib( + LifetimeRibKind::Elided(LifetimeRes::Infer), + |this| { + this.with_constant_rib( + IsRepeatExpr::No, + ConstantHasGenerics::Yes, + None, + |this| this.visit_expr(expr), + ) + }, + ); + } + }, + ); } AssocItemKind::Fn(box Fn { generics, .. }) => { debug!("resolve_implementation AssocItemKind::Fn"); @@ -4430,6 +4499,7 @@ impl<'ast> Visitor<'ast> for LifetimeCountVisitor<'_, '_, '_> { fn visit_item(&mut self, item: &'ast Item) { match &item.kind { ItemKind::TyAlias(box TyAlias { ref generics, .. }) + | ItemKind::Const(box ConstItem { ref generics, .. }) | ItemKind::Fn(box Fn { ref generics, .. }) | ItemKind::Enum(_, ref generics) | ItemKind::Struct(_, ref generics) @@ -4449,7 +4519,6 @@ impl<'ast> Visitor<'ast> for LifetimeCountVisitor<'_, '_, '_> { ItemKind::Mod(..) | ItemKind::ForeignMod(..) | ItemKind::Static(..) - | ItemKind::Const(..) | ItemKind::Use(..) | ItemKind::ExternCrate(..) | ItemKind::MacroDef(..) diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index f97cb3440d25f..593983f117d03 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -2524,6 +2524,8 @@ pub fn build_session_options( let error_format = parse_error_format(handler, matches, color, json_rendered); + handler.abort_if_error_and_set_error_format(error_format); + let diagnostic_width = matches.opt_get("diagnostic-width").unwrap_or_else(|_| { handler.early_error("`--diagnostic-width` must be an positive integer"); }); diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs index 874e34bef60f0..85d5bb00c4e10 100644 --- a/compiler/rustc_smir/src/rustc_smir/mod.rs +++ b/compiler/rustc_smir/src/rustc_smir/mod.rs @@ -7,7 +7,8 @@ //! //! For now, we are developing everything inside `rustc`, thus, we keep this module private. -use crate::stable_mir::{self, ty::TyKind, Context}; +use crate::stable_mir::ty::{FloatTy, IntTy, RigidTy, TyKind, UintTy}; +use crate::stable_mir::{self, Context}; use rustc_middle::mir; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::def_id::{CrateNum, DefId, LOCAL_CRATE}; @@ -69,11 +70,28 @@ pub struct Tables<'tcx> { impl<'tcx> Tables<'tcx> { fn rustc_ty_to_ty(&mut self, ty: Ty<'tcx>) -> TyKind { match ty.kind() { - ty::Bool => TyKind::Bool, - ty::Char => todo!(), - ty::Int(_) => todo!(), - ty::Uint(_) => todo!(), - ty::Float(_) => todo!(), + ty::Bool => TyKind::RigidTy(RigidTy::Bool), + ty::Char => TyKind::RigidTy(RigidTy::Char), + ty::Int(int_ty) => match int_ty { + ty::IntTy::Isize => TyKind::RigidTy(RigidTy::Int(IntTy::Isize)), + ty::IntTy::I8 => TyKind::RigidTy(RigidTy::Int(IntTy::I8)), + ty::IntTy::I16 => TyKind::RigidTy(RigidTy::Int(IntTy::I16)), + ty::IntTy::I32 => TyKind::RigidTy(RigidTy::Int(IntTy::I32)), + ty::IntTy::I64 => TyKind::RigidTy(RigidTy::Int(IntTy::I64)), + ty::IntTy::I128 => TyKind::RigidTy(RigidTy::Int(IntTy::I128)), + }, + ty::Uint(uint_ty) => match uint_ty { + ty::UintTy::Usize => TyKind::RigidTy(RigidTy::Uint(UintTy::Usize)), + ty::UintTy::U8 => TyKind::RigidTy(RigidTy::Uint(UintTy::U8)), + ty::UintTy::U16 => TyKind::RigidTy(RigidTy::Uint(UintTy::U16)), + ty::UintTy::U32 => TyKind::RigidTy(RigidTy::Uint(UintTy::U32)), + ty::UintTy::U64 => TyKind::RigidTy(RigidTy::Uint(UintTy::U64)), + ty::UintTy::U128 => TyKind::RigidTy(RigidTy::Uint(UintTy::U128)), + }, + ty::Float(float_ty) => match float_ty { + ty::FloatTy::F32 => TyKind::RigidTy(RigidTy::Float(FloatTy::F32)), + ty::FloatTy::F64 => TyKind::RigidTy(RigidTy::Float(FloatTy::F64)), + }, ty::Adt(_, _) => todo!(), ty::Foreign(_) => todo!(), ty::Str => todo!(), @@ -90,9 +108,9 @@ impl<'tcx> Tables<'tcx> { ty::GeneratorWitness(_) => todo!(), ty::GeneratorWitnessMIR(_, _) => todo!(), ty::Never => todo!(), - ty::Tuple(fields) => { - TyKind::Tuple(fields.iter().map(|ty| self.intern_ty(ty)).collect()) - } + ty::Tuple(fields) => TyKind::RigidTy(RigidTy::Tuple( + fields.iter().map(|ty| self.intern_ty(ty)).collect(), + )), ty::Alias(_, _) => todo!(), ty::Param(_) => todo!(), ty::Bound(_, _) => todo!(), diff --git a/compiler/rustc_smir/src/stable_mir/ty.rs b/compiler/rustc_smir/src/stable_mir/ty.rs index f27801b0f6cae..3181af46e9cb3 100644 --- a/compiler/rustc_smir/src/stable_mir/ty.rs +++ b/compiler/rustc_smir/src/stable_mir/ty.rs @@ -9,7 +9,43 @@ impl Ty { } } +#[derive(Clone, Debug)] pub enum TyKind { + RigidTy(RigidTy), +} + +#[derive(Clone, Debug)] +pub enum RigidTy { Bool, + Char, + Int(IntTy), + Uint(UintTy), + Float(FloatTy), Tuple(Vec), } + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum IntTy { + Isize, + I8, + I16, + I32, + I64, + I128, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum UintTy { + Usize, + U8, + U16, + U32, + U64, + U128, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum FloatTy { + F32, + F64, +} diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 66a627d5aac7c..62c1553ddc14d 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -759,7 +759,6 @@ symbols! { from_desugaring, from_fn, from_iter, - from_method, from_output, from_residual, from_size_align_unchecked, @@ -782,6 +781,7 @@ symbols! { generic_associated_types, generic_associated_types_extended, generic_const_exprs, + generic_consts, generic_param_attrs, get_context, global_allocator, diff --git a/compiler/rustc_trait_selection/src/solve/normalize.rs b/compiler/rustc_trait_selection/src/solve/normalize.rs index c0ee1a576e5fb..c388850d831e2 100644 --- a/compiler/rustc_trait_selection/src/solve/normalize.rs +++ b/compiler/rustc_trait_selection/src/solve/normalize.rs @@ -167,9 +167,7 @@ impl<'tcx> FallibleTypeFolder> for NormalizationFolder<'_, 'tcx> { // We don't normalize opaque types unless we have // `Reveal::All`, even if we're in the defining scope. let data = match *ty.kind() { - ty::Alias(kind, alias_ty) if kind != ty::Opaque || reveal == Reveal::UserFacing => { - alias_ty - } + ty::Alias(kind, alias_ty) if kind != ty::Opaque || reveal == Reveal::All => alias_ty, _ => return ty.try_super_fold_with(self), }; diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs index aa69071997000..e53b784a756b8 100644 --- a/compiler/rustc_trait_selection/src/solve/project_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs @@ -366,7 +366,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { } ty::Adt(def, substs) if def.is_struct() => { - match def.non_enum_variant().fields.raw.last() { + match def.non_enum_variant().tail_opt() { None => tcx.types.unit, Some(field_def) => { let self_ty = field_def.ty(tcx, substs); diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index cd68626bed1ae..ef5f25b1f7f5f 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -425,12 +425,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { return Err(NoSolution); } - let tail_field = a_def - .non_enum_variant() - .fields - .raw - .last() - .expect("expected unsized ADT to have a tail field"); + let tail_field = a_def.non_enum_variant().tail(); let tail_field_ty = tcx.type_of(tail_field.did); let a_tail_ty = tail_field_ty.subst(tcx, a_substs); diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 5b875e1999690..f342180590f93 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -12,7 +12,6 @@ use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use crate::infer::{self, InferCtxt}; use crate::solve::{GenerateProofTree, InferCtxtEvalExt, UseGlobalCache}; use crate::traits::query::evaluate_obligation::InferCtxtExt as _; -use crate::traits::query::normalize::QueryNormalizeExt as _; use crate::traits::specialize::to_pretty_impl_header; use crate::traits::NormalizeExt; use on_unimplemented::{AppendConstMessage, OnUnimplementedNote, TypeErrCtxtExt as _}; @@ -33,7 +32,7 @@ use rustc_middle::traits::solve::Goal; use rustc_middle::traits::{DefiningAnchor, SelectionOutputTypeParameterMismatch}; use rustc_middle::ty::abstract_const::NotConstEvaluatable; use rustc_middle::ty::error::{ExpectedFound, TypeError}; -use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable}; +use rustc_middle::ty::fold::{BottomUpFolder, TypeFolder, TypeSuperFoldable}; use rustc_middle::ty::print::{with_forced_trimmed_paths, FmtPrinter, Print}; use rustc_middle::ty::{ self, SubtypePredicate, ToPolyTraitRef, ToPredicate, TraitRef, Ty, TyCtxt, TypeFoldable, @@ -63,7 +62,7 @@ pub enum CandidateSimilarity { Fuzzy { ignoring_lifetimes: bool }, } -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct ImplCandidate<'tcx> { pub trait_ref: ty::TraitRef<'tcx>, pub similarity: CandidateSimilarity, @@ -1941,10 +1940,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { other: bool, ) -> bool { let other = if other { "other " } else { "" }; - let report = |mut candidates: Vec>, err: &mut Diagnostic| { - candidates.sort(); - candidates.dedup(); - let len = candidates.len(); + let report = |candidates: Vec>, err: &mut Diagnostic| { if candidates.is_empty() { return false; } @@ -1973,11 +1969,14 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { candidates.iter().map(|c| c.print_only_trait_path().to_string()).collect(); traits.sort(); traits.dedup(); + // FIXME: this could use a better heuristic, like just checking + // that substs[1..] is the same. + let all_traits_equal = traits.len() == 1; - let mut candidates: Vec = candidates + let candidates: Vec = candidates .into_iter() .map(|c| { - if traits.len() == 1 { + if all_traits_equal { format!("\n {}", c.self_ty()) } else { format!("\n {}", c) @@ -1985,14 +1984,16 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { }) .collect(); - candidates.sort(); - candidates.dedup(); let end = if candidates.len() <= 9 { candidates.len() } else { 8 }; err.help(format!( "the following {other}types implement trait `{}`:{}{}", trait_ref.print_only_trait_path(), candidates[..end].join(""), - if len > 9 { format!("\nand {} others", len - 8) } else { String::new() } + if candidates.len() > 9 { + format!("\nand {} others", candidates.len() - 8) + } else { + String::new() + } )); true }; @@ -2006,7 +2007,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // Mentioning implementers of `Copy`, `Debug` and friends is not useful. return false; } - let normalized_impl_candidates: Vec<_> = self + let mut impl_candidates: Vec<_> = self .tcx .all_impls(def_id) // Ignore automatically derived impls and `!Trait` impls. @@ -2033,7 +2034,10 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } }) .collect(); - return report(normalized_impl_candidates, err); + + impl_candidates.sort(); + impl_candidates.dedup(); + return report(impl_candidates, err); } // Sort impl candidates so that ordering is consistent for UI tests. @@ -2042,27 +2046,25 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // // Prefer more similar candidates first, then sort lexicographically // by their normalized string representation. - let mut normalized_impl_candidates_and_similarities = impl_candidates + let mut impl_candidates: Vec<_> = impl_candidates .iter() - .copied() - .map(|ImplCandidate { trait_ref, similarity }| { - // FIXME(compiler-errors): This should be using `NormalizeExt::normalize` - let normalized = self - .at(&ObligationCause::dummy(), ty::ParamEnv::empty()) - .query_normalize(trait_ref) - .map_or(trait_ref, |normalized| normalized.value); - (similarity, normalized) + .cloned() + .map(|mut cand| { + // Fold the consts so that they shows up as, e.g., `10` + // instead of `core::::array::{impl#30}::{constant#0}`. + cand.trait_ref = cand.trait_ref.fold_with(&mut BottomUpFolder { + tcx: self.tcx, + ty_op: |ty| ty, + lt_op: |lt| lt, + ct_op: |ct| ct.eval(self.tcx, ty::ParamEnv::empty()), + }); + cand }) - .collect::>(); - normalized_impl_candidates_and_similarities.sort(); - normalized_impl_candidates_and_similarities.dedup(); - - let normalized_impl_candidates = normalized_impl_candidates_and_similarities - .into_iter() - .map(|(_, normalized)| normalized) - .collect::>(); + .collect(); + impl_candidates.sort_by_key(|cand| (cand.similarity, cand.trait_ref)); + impl_candidates.dedup(); - report(normalized_impl_candidates, err) + report(impl_candidates.into_iter().map(|cand| cand.trait_ref).collect(), err) } fn report_similar_impl_candidates_for_root_obligation( diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs index 1e4d30f48b2dc..b16d2eb5fc19e 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs @@ -41,7 +41,6 @@ pub trait TypeErrCtxtExt<'tcx> { static ALLOWED_FORMAT_SYMBOLS: &[Symbol] = &[ kw::SelfUpper, sym::ItemContext, - sym::from_method, sym::from_desugaring, sym::direct, sym::cause, @@ -172,23 +171,6 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } } - if let ObligationCauseCode::ItemObligation(item) - | ObligationCauseCode::BindingObligation(item, _) - | ObligationCauseCode::ExprItemObligation(item, ..) - | ObligationCauseCode::ExprBindingObligation(item, ..) = *obligation.cause.code() - { - // FIXME: maybe also have some way of handling methods - // from other traits? That would require name resolution, - // which we might want to be some sort of hygienic. - // - // Currently I'm leaving it for what I need for `try`. - if self.tcx.trait_of_item(item) == Some(trait_ref.def_id) { - let method = self.tcx.item_name(item); - flags.push((sym::from_method, None)); - flags.push((sym::from_method, Some(method.to_string()))); - } - } - if let Some(k) = obligation.cause.span.desugaring_kind() { flags.push((sym::from_desugaring, None)); flags.push((sym::from_desugaring, Some(format!("{:?}", k)))); @@ -672,7 +654,7 @@ impl<'tcx> OnUnimplementedFormatString { None => { if let Some(val) = options.get(&s) { val - } else if s == sym::from_desugaring || s == sym::from_method { + } else if s == sym::from_desugaring { // don't break messages using these two arguments incorrectly &empty_string } else if s == sym::ItemContext { diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 9ac1ba0275c19..61ce9f7c6226d 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -654,6 +654,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { | hir::ItemKind::Impl(hir::Impl { generics, .. }) | hir::ItemKind::Fn(_, generics, _) | hir::ItemKind::TyAlias(_, generics) + | hir::ItemKind::Const(_, generics, _) | hir::ItemKind::TraitAlias(generics, _) | hir::ItemKind::OpaqueTy(hir::OpaqueTy { generics, .. }), .. @@ -719,6 +720,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { | hir::ItemKind::Impl(hir::Impl { generics, .. }) | hir::ItemKind::Fn(_, generics, _) | hir::ItemKind::TyAlias(_, generics) + | hir::ItemKind::Const(_, generics, _) | hir::ItemKind::TraitAlias(generics, _) | hir::ItemKind::OpaqueTy(hir::OpaqueTy { generics, .. }), .. diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index e2ee347b639a1..1af8323b6e993 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -11,7 +11,7 @@ mod fulfill; pub mod misc; mod object_safety; pub mod outlives_bounds; -mod project; +pub mod project; pub mod query; #[cfg_attr(not(bootstrap), allow(hidden_glob_reexports))] mod select; diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 9deacd7ca92e6..7adc29bbba442 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -1125,12 +1125,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { return Err(Unimplemented); } - let tail_field = def - .non_enum_variant() - .fields - .raw - .last() - .expect("expected unsized ADT to have a tail field"); + let tail_field = def.non_enum_variant().tail(); let tail_field_ty = tcx.type_of(tail_field.did); // Extract `TailField` and `TailField` from `Struct` and `Struct`, diff --git a/compiler/rustc_ty_utils/src/consts.rs b/compiler/rustc_ty_utils/src/consts.rs index 8cc75a6e2e3e9..426c98012b3fb 100644 --- a/compiler/rustc_ty_utils/src/consts.rs +++ b/compiler/rustc_ty_utils/src/consts.rs @@ -221,7 +221,7 @@ fn recurse_build<'tcx>( maybe_supported_error(GenericConstantTooComplexSub::AdtNotSupported(node.span))? } // dont know if this is correct - ExprKind::Pointer { .. } => { + ExprKind::PointerCoercion { .. } => { error(GenericConstantTooComplexSub::PointerNotSupported(node.span))? } ExprKind::Yield { .. } => { @@ -324,7 +324,7 @@ impl<'a, 'tcx> IsThirPolymorphic<'a, 'tcx> { | thir::ExprKind::Cast { .. } | thir::ExprKind::Use { .. } | thir::ExprKind::NeverToAny { .. } - | thir::ExprKind::Pointer { .. } + | thir::ExprKind::PointerCoercion { .. } | thir::ExprKind::Loop { .. } | thir::ExprKind::Let { .. } | thir::ExprKind::Match { .. } diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index 9ef9120e294c9..b67cd96a7347c 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -463,38 +463,85 @@ fn layout_of_uncached<'tcx>( )); } - tcx.mk_layout( - cx.layout_of_struct_or_enum( + let get_discriminant_type = + |min, max| Integer::repr_discr(tcx, ty, &def.repr(), min, max); + + let discriminants_iter = || { + def.is_enum() + .then(|| def.discriminants(tcx).map(|(v, d)| (v, d.val as i128))) + .into_iter() + .flatten() + }; + + let dont_niche_optimize_enum = def.repr().inhibit_enum_layout_opt() + || def + .variants() + .iter_enumerated() + .any(|(i, v)| v.discr != ty::VariantDiscr::Relative(i.as_u32())); + + let maybe_unsized = def.is_struct() + && def.non_enum_variant().tail_opt().is_some_and(|last_field| { + let param_env = tcx.param_env(def.did()); + !tcx.type_of(last_field.did).subst_identity().is_sized(tcx, param_env) + }); + + let Some(layout) = cx.layout_of_struct_or_enum( + &def.repr(), + &variants, + def.is_enum(), + def.is_unsafe_cell(), + tcx.layout_scalar_valid_range(def.did()), + get_discriminant_type, + discriminants_iter(), + dont_niche_optimize_enum, + !maybe_unsized, + ) else { + return Err(error(cx, LayoutError::SizeOverflow(ty))); + }; + + // If the struct tail is sized and can be unsized, check that unsizing doesn't move the fields around. + if cfg!(debug_assertions) + && maybe_unsized + && def.non_enum_variant().tail().ty(tcx, substs).is_sized(tcx, cx.param_env) + { + let mut variants = variants; + let tail_replacement = cx.layout_of(Ty::new_slice(tcx, tcx.types.u8)).unwrap(); + *variants[FIRST_VARIANT].raw.last_mut().unwrap() = tail_replacement.layout; + + let Some(unsized_layout) = cx.layout_of_struct_or_enum( &def.repr(), &variants, def.is_enum(), def.is_unsafe_cell(), tcx.layout_scalar_valid_range(def.did()), - |min, max| Integer::repr_discr(tcx, ty, &def.repr(), min, max), - def.is_enum() - .then(|| def.discriminants(tcx).map(|(v, d)| (v, d.val as i128))) - .into_iter() - .flatten(), - def.repr().inhibit_enum_layout_opt() - || def - .variants() - .iter_enumerated() - .any(|(i, v)| v.discr != ty::VariantDiscr::Relative(i.as_u32())), - { - let param_env = tcx.param_env(def.did()); - def.is_struct() - && match def.variants().iter().next().and_then(|x| x.fields.raw.last()) - { - Some(last_field) => tcx - .type_of(last_field.did) - .subst_identity() - .is_sized(tcx, param_env), - None => false, - } - }, - ) - .ok_or_else(|| error(cx, LayoutError::SizeOverflow(ty)))?, - ) + get_discriminant_type, + discriminants_iter(), + dont_niche_optimize_enum, + !maybe_unsized, + ) else { + bug!("failed to compute unsized layout of {ty:?}"); + }; + + let FieldsShape::Arbitrary { offsets: sized_offsets, .. } = &layout.fields else { + bug!("unexpected FieldsShape for sized layout of {ty:?}: {:?}", layout.fields); + }; + let FieldsShape::Arbitrary { offsets: unsized_offsets, .. } = &unsized_layout.fields else { + bug!("unexpected FieldsShape for unsized layout of {ty:?}: {:?}", unsized_layout.fields); + }; + + let (sized_tail, sized_fields) = sized_offsets.raw.split_last().unwrap(); + let (unsized_tail, unsized_fields) = unsized_offsets.raw.split_last().unwrap(); + + if sized_fields != unsized_fields { + bug!("unsizing {ty:?} changed field order!\n{layout:?}\n{unsized_layout:?}"); + } + + if sized_tail < unsized_tail { + bug!("unsizing {ty:?} moved tail backwards!\n{layout:?}\n{unsized_layout:?}"); + } + } + + tcx.mk_layout(layout) } // Types with no meaningful known layout. diff --git a/compiler/rustc_ty_utils/src/opaque_types.rs b/compiler/rustc_ty_utils/src/opaque_types.rs index 29de8bf0e53f5..570c3b245cd41 100644 --- a/compiler/rustc_ty_utils/src/opaque_types.rs +++ b/compiler/rustc_ty_utils/src/opaque_types.rs @@ -1,5 +1,7 @@ use rustc_data_structures::fx::FxHashSet; +use rustc_hir::intravisit::Visitor; use rustc_hir::{def::DefKind, def_id::LocalDefId}; +use rustc_hir::{intravisit, CRATE_HIR_ID}; use rustc_middle::query::Providers; use rustc_middle::ty::util::{CheckRegions, NotUniqueParam}; use rustc_middle::ty::{self, Ty, TyCtxt}; @@ -51,7 +53,7 @@ impl<'tcx> OpaqueTypeCollector<'tcx> { fn parent(&self) -> Option { match self.tcx.def_kind(self.item) { - DefKind::Fn => None, + DefKind::AnonConst | DefKind::InlineConst | DefKind::Fn | DefKind::TyAlias => None, DefKind::AssocFn | DefKind::AssocTy | DefKind::AssocConst => { Some(self.tcx.local_parent(self.item)) } @@ -61,6 +63,73 @@ impl<'tcx> OpaqueTypeCollector<'tcx> { ), } } + + /// Returns `true` if `opaque_hir_id` is a sibling or a child of a sibling of `self.item`. + /// + /// Example: + /// ```ignore UNSOLVED (is this a bug?) + /// # #![feature(type_alias_impl_trait)] + /// pub mod foo { + /// pub mod bar { + /// pub trait Bar { /* ... */ } + /// pub type Baz = impl Bar; + /// + /// # impl Bar for () {} + /// fn f1() -> Baz { /* ... */ } + /// } + /// fn f2() -> bar::Baz { /* ... */ } + /// } + /// ``` + /// + /// and `opaque_def_id` is the `DefId` of the definition of the opaque type `Baz`. + /// For the above example, this function returns `true` for `f1` and `false` for `f2`. + #[instrument(level = "trace", skip(self), ret)] + fn check_tait_defining_scope(&self, opaque_def_id: LocalDefId) -> bool { + let mut hir_id = self.tcx.hir().local_def_id_to_hir_id(self.item); + let opaque_hir_id = self.tcx.hir().local_def_id_to_hir_id(opaque_def_id); + + // Named opaque types can be defined by any siblings or children of siblings. + let scope = self.tcx.hir().get_defining_scope(opaque_hir_id); + // We walk up the node tree until we hit the root or the scope of the opaque type. + while hir_id != scope && hir_id != CRATE_HIR_ID { + hir_id = self.tcx.hir().get_parent_item(hir_id).into(); + } + // Syntactically, we are allowed to define the concrete type if: + hir_id == scope + } + + fn collect_body_and_predicate_taits(&mut self) { + // Look at all where bounds. + self.tcx.predicates_of(self.item).instantiate_identity(self.tcx).visit_with(self); + // An item is allowed to constrain opaques declared within its own body (but not nested within + // nested functions). + self.collect_taits_declared_in_body(); + } + + #[instrument(level = "trace", skip(self))] + fn collect_taits_declared_in_body(&mut self) { + let body = self.tcx.hir().body(self.tcx.hir().body_owned_by(self.item)).value; + struct TaitInBodyFinder<'a, 'tcx> { + collector: &'a mut OpaqueTypeCollector<'tcx>, + } + impl<'v> intravisit::Visitor<'v> for TaitInBodyFinder<'_, '_> { + #[instrument(level = "trace", skip(self))] + fn visit_nested_item(&mut self, id: rustc_hir::ItemId) { + let id = id.owner_id.def_id; + if let DefKind::TyAlias = self.collector.tcx.def_kind(id) { + let items = self.collector.tcx.opaque_types_defined_by(id); + self.collector.opaques.extend(items); + } + } + #[instrument(level = "trace", skip(self))] + // Recurse into these, as they are type checked with their parent + fn visit_nested_body(&mut self, id: rustc_hir::BodyId) { + let body = self.collector.tcx.hir().body(id); + self.visit_body(body); + } + } + TaitInBodyFinder { collector: self }.visit_expr(body); + } } impl<'tcx> TypeVisitor> for OpaqueTypeCollector<'tcx> { @@ -73,6 +142,21 @@ impl<'tcx> TypeVisitor> for OpaqueTypeCollector<'tcx> { return ControlFlow::Continue(()); } + // TAITs outside their defining scopes are ignored. + let origin = self.tcx.opaque_type_origin(alias_ty.def_id.expect_local()); + trace!(?origin); + match origin { + rustc_hir::OpaqueTyOrigin::FnReturn(_) + | rustc_hir::OpaqueTyOrigin::AsyncFn(_) => {} + rustc_hir::OpaqueTyOrigin::TyAlias { in_assoc_ty } => { + if !in_assoc_ty { + if !self.check_tait_defining_scope(alias_ty.def_id.expect_local()) { + return ControlFlow::Continue(()); + } + } + } + } + self.opaques.push(alias_ty.def_id.expect_local()); match self.tcx.uses_unique_generic_params(alias_ty.substs, CheckRegions::Bound) { @@ -188,33 +272,36 @@ impl<'tcx> TypeVisitor> for OpaqueTypeCollector<'tcx> { fn opaque_types_defined_by<'tcx>(tcx: TyCtxt<'tcx>, item: LocalDefId) -> &'tcx [LocalDefId] { let kind = tcx.def_kind(item); trace!(?kind); - // FIXME(type_alias_impl_trait): This is definitely still wrong except for RPIT and impl trait in assoc types. + let mut collector = OpaqueTypeCollector::new(tcx, item); match kind { + // Walk over the signature of the function-like to find the opaques. + DefKind::AssocFn | DefKind::Fn => { + let ty_sig = tcx.fn_sig(item).subst_identity(); + let hir_sig = tcx.hir().get_by_def_id(item).fn_sig().unwrap(); + // Walk over the inputs and outputs manually in order to get good spans for them. + collector.visit_spanned(hir_sig.decl.output.span(), ty_sig.output()); + for (hir, ty) in hir_sig.decl.inputs.iter().zip(ty_sig.inputs().iter()) { + collector.visit_spanned(hir.span, ty.map_bound(|x| *x)); + } + collector.collect_body_and_predicate_taits(); + } + // Walk over the type of the item to find opaques. + DefKind::Static(_) | DefKind::Const | DefKind::AssocConst | DefKind::AnonConst => { + let span = match tcx.hir().get_by_def_id(item).ty() { + Some(ty) => ty.span, + _ => tcx.def_span(item), + }; + collector.visit_spanned(span, tcx.type_of(item).subst_identity()); + collector.collect_body_and_predicate_taits(); + } // We're also doing this for `AssocTy` for the wf checks in `check_opaque_meets_bounds` - DefKind::Fn | DefKind::AssocFn | DefKind::AssocTy | DefKind::AssocConst => { - let mut collector = OpaqueTypeCollector::new(tcx, item); - match kind { - // Walk over the signature of the function-like to find the opaques. - DefKind::AssocFn | DefKind::Fn => { - let ty_sig = tcx.fn_sig(item).subst_identity(); - let hir_sig = tcx.hir().get_by_def_id(item).fn_sig().unwrap(); - // Walk over the inputs and outputs manually in order to get good spans for them. - collector.visit_spanned(hir_sig.decl.output.span(), ty_sig.output()); - for (hir, ty) in hir_sig.decl.inputs.iter().zip(ty_sig.inputs().iter()) { - collector.visit_spanned(hir.span, ty.map_bound(|x| *x)); - } - } - // Walk over the type of the item to find opaques. - DefKind::AssocTy | DefKind::AssocConst => { - let span = match tcx.hir().get_by_def_id(item).ty() { - Some(ty) => ty.span, - _ => tcx.def_span(item), - }; - collector.visit_spanned(span, tcx.type_of(item).subst_identity()); - } - _ => unreachable!(), + DefKind::TyAlias | DefKind::AssocTy => { + tcx.type_of(item).subst_identity().visit_with(&mut collector); + } + DefKind::OpaqueTy => { + for (pred, span) in tcx.explicit_item_bounds(item).subst_identity_iter_copied() { + collector.visit_spanned(span, pred); } - tcx.arena.alloc_from_iter(collector.opaques) } DefKind::Mod | DefKind::Struct @@ -222,31 +309,26 @@ fn opaque_types_defined_by<'tcx>(tcx: TyCtxt<'tcx>, item: LocalDefId) -> &'tcx [ | DefKind::Enum | DefKind::Variant | DefKind::Trait - | DefKind::TyAlias | DefKind::ForeignTy | DefKind::TraitAlias | DefKind::TyParam - | DefKind::Const | DefKind::ConstParam - | DefKind::Static(_) | DefKind::Ctor(_, _) | DefKind::Macro(_) | DefKind::ExternCrate | DefKind::Use | DefKind::ForeignMod - | DefKind::AnonConst - | DefKind::InlineConst - | DefKind::OpaqueTy | DefKind::ImplTraitPlaceholder | DefKind::Field | DefKind::LifetimeParam | DefKind::GlobalAsm - | DefKind::Impl { .. } - | DefKind::Closure - | DefKind::Generator => { - span_bug!(tcx.def_span(item), "{kind:?} is type checked as part of its parent") + | DefKind::Impl { .. } => {} + // Closures and generators are type checked with their parent, so there is no difference here. + DefKind::Closure | DefKind::Generator | DefKind::InlineConst => { + return tcx.opaque_types_defined_by(tcx.local_parent(item)); } } + tcx.arena.alloc_from_iter(collector.opaques) } pub(super) fn provide(providers: &mut Providers) { diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index 466616cd22bd0..6e5c50492c696 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -103,7 +103,7 @@ fn adt_sized_constraint(tcx: TyCtxt<'_>, def_id: DefId) -> &[Ty<'_>] { let result = tcx.mk_type_list_from_iter( def.variants() .iter() - .filter_map(|v| v.fields.raw.last()) + .filter_map(|v| v.tail_opt()) .flat_map(|f| sized_constraint_for_ty(tcx, def, tcx.type_of(f.did).subst_identity())), ); diff --git a/config.example.toml b/config.example.toml index 0c65b25fe1389..367f95b156fed 100644 --- a/config.example.toml +++ b/config.example.toml @@ -400,10 +400,20 @@ changelog-seen = 2 # ============================================================================= [rust] -# Whether or not to optimize the compiler and standard library. +# Whether or not to optimize when compiling the compiler and standard library, +# and what level of optimization to use. # WARNING: Building with optimize = false is NOT SUPPORTED. Due to bootstrapping, # building without optimizations takes much longer than optimizing. Further, some platforms # fail to build without this optimization (c.f. #65352). +# The valid options are: +# true - Enable optimizations. +# false - Disable optimizations. +# 0 - Disable optimizations. +# 1 - Basic optimizations. +# 2 - Some optimizations. +# 3 - All optimizations. +# "s" - Optimize for binary size. +# "z" - Optimize for binary size, but also turn off loop vectorization. #optimize = true # Indicates that the build should be configured for debugging Rust. A @@ -757,7 +767,7 @@ changelog-seen = 2 # This option will override the same option under [build] section. #profiler = build.profiler (bool) -# This option supports enable `rpath` in each target independently, +# This option supports enable `rpath` in each target independently, # and will override the same option under [rust] section. It only works on Unix platforms #rpath = rust.rpath (bool) diff --git a/library/core/src/default.rs b/library/core/src/default.rs index 1f7be85d38ac7..5242e97eb9aed 100644 --- a/library/core/src/default.rs +++ b/library/core/src/default.rs @@ -133,51 +133,6 @@ pub trait Default: Sized { fn default() -> Self; } -/// Return the default value of a type according to the `Default` trait. -/// -/// The type to return is inferred from context; this is equivalent to -/// `Default::default()` but shorter to type. -/// -/// For example: -/// ``` -/// #![feature(default_free_fn)] -/// -/// use std::default::default; -/// -/// #[derive(Default)] -/// struct AppConfig { -/// foo: FooConfig, -/// bar: BarConfig, -/// } -/// -/// #[derive(Default)] -/// struct FooConfig { -/// foo: i32, -/// } -/// -/// #[derive(Default)] -/// struct BarConfig { -/// bar: f32, -/// baz: u8, -/// } -/// -/// fn main() { -/// let options = AppConfig { -/// foo: default(), -/// bar: BarConfig { -/// bar: 10.1, -/// ..default() -/// }, -/// }; -/// } -/// ``` -#[unstable(feature = "default_free_fn", issue = "73014")] -#[must_use] -#[inline] -pub fn default() -> T { - Default::default() -} - /// Derive macro generating an impl of the trait `Default`. #[rustc_builtin_macro(Default, attributes(default))] #[stable(feature = "builtin_macro_prelude", since = "1.38.0")] diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 5d6e7dcfcee87..e2a2428fbc244 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -851,6 +851,8 @@ impl [T] { /// Swaps two elements in the slice. /// + /// If `a` equals to `b`, it's guaranteed that elements won't change value. + /// /// # Arguments /// /// * a - The index of the first element diff --git a/library/std/src/io/copy.rs b/library/std/src/io/copy.rs index ef1f4031ef202..3322940d2452f 100644 --- a/library/std/src/io/copy.rs +++ b/library/std/src/io/copy.rs @@ -1,4 +1,8 @@ use super::{BorrowedBuf, BufReader, BufWriter, ErrorKind, Read, Result, Write, DEFAULT_BUF_SIZE}; +use crate::alloc::Allocator; +use crate::cmp; +use crate::collections::VecDeque; +use crate::io::IoSlice; use crate::mem::MaybeUninit; #[cfg(test)] @@ -86,7 +90,7 @@ where /// Specialization of the read-write loop that reuses the internal /// buffer of a BufReader. If there's no buffer then the writer side -/// should be used intead. +/// should be used instead. trait BufferedReaderSpec { fn buffer_size(&self) -> usize; @@ -104,7 +108,39 @@ where } default fn copy_to(&mut self, _to: &mut (impl Write + ?Sized)) -> Result { - unimplemented!("only called from specializations"); + unreachable!("only called from specializations") + } +} + +impl BufferedReaderSpec for &[u8] { + fn buffer_size(&self) -> usize { + // prefer this specialization since the source "buffer" is all we'll ever need, + // even if it's small + usize::MAX + } + + fn copy_to(&mut self, to: &mut (impl Write + ?Sized)) -> Result { + let len = self.len(); + to.write_all(self)?; + *self = &self[len..]; + Ok(len as u64) + } +} + +impl BufferedReaderSpec for VecDeque { + fn buffer_size(&self) -> usize { + // prefer this specialization since the source "buffer" is all we'll ever need, + // even if it's small + usize::MAX + } + + fn copy_to(&mut self, to: &mut (impl Write + ?Sized)) -> Result { + let len = self.len(); + let (front, back) = self.as_slices(); + let bufs = &mut [IoSlice::new(front), IoSlice::new(back)]; + to.write_all_vectored(bufs)?; + self.clear(); + Ok(len as u64) } } @@ -218,6 +254,47 @@ impl BufferedWriterSpec for BufWriter { } } +impl BufferedWriterSpec for Vec { + fn buffer_size(&self) -> usize { + cmp::max(DEFAULT_BUF_SIZE, self.capacity() - self.len()) + } + + fn copy_from(&mut self, reader: &mut R) -> Result { + let mut bytes = 0; + + // avoid allocating before we have determined that there's anything to read + if self.capacity() == 0 { + bytes = stack_buffer_copy(&mut reader.take(DEFAULT_BUF_SIZE as u64), self)?; + if bytes == 0 { + return Ok(0); + } + } + + loop { + self.reserve(DEFAULT_BUF_SIZE); + let mut buf: BorrowedBuf<'_> = self.spare_capacity_mut().into(); + match reader.read_buf(buf.unfilled()) { + Ok(()) => {} + Err(e) if e.kind() == ErrorKind::Interrupted => continue, + Err(e) => return Err(e), + }; + + let read = buf.filled().len(); + if read == 0 { + break; + } + + // SAFETY: BorrowedBuf guarantees all of its filled bytes are init + // and the number of read bytes can't exceed the spare capacity since + // that's what the buffer is borrowing from. + unsafe { self.set_len(self.len() + read) }; + bytes += read as u64; + } + + Ok(bytes) + } +} + fn stack_buffer_copy( reader: &mut R, writer: &mut W, diff --git a/library/std/src/io/copy/tests.rs b/library/std/src/io/copy/tests.rs index 8c816af15b808..af137eaf856f5 100644 --- a/library/std/src/io/copy/tests.rs +++ b/library/std/src/io/copy/tests.rs @@ -1,4 +1,6 @@ use crate::cmp::{max, min}; +use crate::collections::VecDeque; +use crate::io; use crate::io::*; #[test] @@ -19,7 +21,7 @@ struct ShortReader { impl Read for ShortReader { fn read(&mut self, buf: &mut [u8]) -> Result { - let bytes = min(self.cap, self.read_size); + let bytes = min(self.cap, self.read_size).min(buf.len()); self.cap -= bytes; self.observed_buffer = max(self.observed_buffer, buf.len()); Ok(bytes) @@ -78,6 +80,40 @@ fn copy_specializes_bufreader() { ); } +#[test] +fn copy_specializes_to_vec() { + let cap = 123456; + let mut source = ShortReader { cap, observed_buffer: 0, read_size: 1337 }; + let mut sink = Vec::new(); + assert_eq!(cap as u64, io::copy(&mut source, &mut sink).unwrap()); + assert!( + source.observed_buffer > DEFAULT_BUF_SIZE, + "expected a large buffer to be provided to the reader" + ); +} + +#[test] +fn copy_specializes_from_vecdeque() { + let mut source = VecDeque::with_capacity(100 * 1024); + for _ in 0..20 * 1024 { + source.push_front(0); + } + for _ in 0..20 * 1024 { + source.push_back(0); + } + let mut sink = WriteObserver { observed_buffer: 0 }; + assert_eq!(40 * 1024u64, io::copy(&mut source, &mut sink).unwrap()); + assert_eq!(20 * 1024, sink.observed_buffer); +} + +#[test] +fn copy_specializes_from_slice() { + let mut source = [1; 60 * 1024].as_slice(); + let mut sink = WriteObserver { observed_buffer: 0 }; + assert_eq!(60 * 1024u64, io::copy(&mut source, &mut sink).unwrap()); + assert_eq!(60 * 1024, sink.observed_buffer); +} + #[cfg(unix)] mod io_benches { use crate::fs::File; diff --git a/src/bootstrap/Cargo.lock b/src/bootstrap/Cargo.lock index 2b2e9e9f98893..66d97a2a0d0d3 100644 --- a/src/bootstrap/Cargo.lock +++ b/src/bootstrap/Cargo.lock @@ -85,6 +85,10 @@ dependencies = [ [[package]] name = "build_helper" version = "0.1.0" +dependencies = [ + "serde", + "serde_derive", +] [[package]] name = "cc" diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 05b66f94727ad..c9bd329d430d1 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -665,6 +665,7 @@ impl<'a> Builder<'a> { llvm::Lld, llvm::CrtBeginEnd, tool::RustdocGUITest, + tool::OptimizedDist ), Kind::Check | Kind::Clippy | Kind::Fix => describe!( check::Std, diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 14c3ef79a78f2..efe621bdb7d57 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -508,6 +508,49 @@ impl Step for StdLink { }; add_to_sysroot(builder, &libdir, &hostdir, &libstd_stamp(builder, compiler, target)); + + // Special case for stage0, to make `rustup toolchain link` and `x dist --stage 0` + // work for stage0-sysroot. We only do this if the stage0 compiler comes from beta, + // and is not set to a custom path. + if compiler.stage == 0 + && builder + .build + .config + .initial_rustc + .starts_with(builder.out.join(&compiler.host.triple).join("stage0/bin")) + { + // Copy bin files from stage0/bin to stage0-sysroot/bin + let sysroot = builder.out.join(&compiler.host.triple).join("stage0-sysroot"); + + let host = compiler.host.triple; + let stage0_bin_dir = builder.out.join(&host).join("stage0/bin"); + let sysroot_bin_dir = sysroot.join("bin"); + t!(fs::create_dir_all(&sysroot_bin_dir)); + builder.cp_r(&stage0_bin_dir, &sysroot_bin_dir); + + // Copy all *.so files from stage0/lib to stage0-sysroot/lib + let stage0_lib_dir = builder.out.join(&host).join("stage0/lib"); + if let Ok(files) = fs::read_dir(&stage0_lib_dir) { + for file in files { + let file = t!(file); + let path = file.path(); + if path.is_file() && is_dylib(&file.file_name().into_string().unwrap()) { + builder.copy(&path, &sysroot.join("lib").join(path.file_name().unwrap())); + } + } + } + + // Copy codegen-backends from stage0 + let sysroot_codegen_backends = builder.sysroot_codegen_backends(compiler); + t!(fs::create_dir_all(&sysroot_codegen_backends)); + let stage0_codegen_backends = builder + .out + .join(&host) + .join("stage0/lib/rustlib") + .join(&host) + .join("codegen-backends"); + builder.cp_r(&stage0_codegen_backends, &sysroot_codegen_backends); + } } } diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 5f5f7ea25fb95..28ae46efefe7a 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -875,11 +875,10 @@ impl Default for StringOrBool { } } -#[derive(Clone, Debug, Deserialize, PartialEq, Eq)] -#[serde(untagged)] +#[derive(Clone, Debug, PartialEq, Eq)] pub enum RustOptimize { - #[serde(deserialize_with = "deserialize_and_validate_opt_level")] String(String), + Int(u8), Bool(bool), } @@ -889,26 +888,74 @@ impl Default for RustOptimize { } } -fn deserialize_and_validate_opt_level<'de, D>(d: D) -> Result -where - D: serde::de::Deserializer<'de>, -{ - let v = String::deserialize(d)?; - if ["0", "1", "2", "3", "s", "z"].iter().find(|x| **x == v).is_some() { - Ok(v) - } else { - Err(format!(r#"unrecognized option for rust optimize: "{}", expected one of "0", "1", "2", "3", "s", "z""#, v)).map_err(serde::de::Error::custom) +impl<'de> Deserialize<'de> for RustOptimize { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_any(OptimizeVisitor) + } +} + +struct OptimizeVisitor; + +impl<'de> serde::de::Visitor<'de> for OptimizeVisitor { + type Value = RustOptimize; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str(r#"one of: 0, 1, 2, 3, "s", "z", true, false"#) + } + + fn visit_str(self, value: &str) -> Result + where + E: serde::de::Error, + { + if ["s", "z"].iter().find(|x| **x == value).is_some() { + Ok(RustOptimize::String(value.to_string())) + } else { + Err(format_optimize_error_msg(value)).map_err(serde::de::Error::custom) + } + } + + fn visit_i64(self, value: i64) -> Result + where + E: serde::de::Error, + { + if matches!(value, 0..=3) { + Ok(RustOptimize::Int(value as u8)) + } else { + Err(format_optimize_error_msg(value)).map_err(serde::de::Error::custom) + } + } + + fn visit_bool(self, value: bool) -> Result + where + E: serde::de::Error, + { + Ok(RustOptimize::Bool(value)) } } +fn format_optimize_error_msg(v: impl std::fmt::Display) -> String { + format!( + r#"unrecognized option for rust optimize: "{}", expected one of 0, 1, 2, 3, "s", "z", true, false"#, + v + ) +} + impl RustOptimize { pub(crate) fn is_release(&self) -> bool { - if let RustOptimize::Bool(true) | RustOptimize::String(_) = &self { true } else { false } + match &self { + RustOptimize::Bool(true) | RustOptimize::String(_) => true, + RustOptimize::Int(i) => *i > 0, + RustOptimize::Bool(false) => false, + } } pub(crate) fn get_opt_level(&self) -> Option { match &self { RustOptimize::String(s) => Some(s.clone()), + RustOptimize::Int(i) => Some(i.to_string()), RustOptimize::Bool(_) => None, } } diff --git a/src/bootstrap/config/tests.rs b/src/bootstrap/config/tests.rs index 732df54cdacbd..c340bb2982a2b 100644 --- a/src/bootstrap/config/tests.rs +++ b/src/bootstrap/config/tests.rs @@ -184,7 +184,10 @@ fn rust_optimize() { assert_eq!(parse("").rust_optimize.is_release(), true); assert_eq!(parse("rust.optimize = false").rust_optimize.is_release(), false); assert_eq!(parse("rust.optimize = true").rust_optimize.is_release(), true); - assert_eq!(parse("rust.optimize = \"1\"").rust_optimize.get_opt_level(), Some("1".to_string())); + assert_eq!(parse("rust.optimize = 0").rust_optimize.is_release(), false); + assert_eq!(parse("rust.optimize = 1").rust_optimize.is_release(), true); + assert_eq!(parse("rust.optimize = 1").rust_optimize.get_opt_level(), Some("1".to_string())); + assert_eq!(parse("rust.optimize = \"s\"").rust_optimize.is_release(), true); assert_eq!(parse("rust.optimize = \"s\"").rust_optimize.get_opt_level(), Some("s".to_string())); } diff --git a/src/bootstrap/download-ci-llvm-stamp b/src/bootstrap/download-ci-llvm-stamp index 4111b7cc0d3f9..120b3c9c4d28a 100644 --- a/src/bootstrap/download-ci-llvm-stamp +++ b/src/bootstrap/download-ci-llvm-stamp @@ -1,4 +1,4 @@ Change this file to make users of the `download-ci-llvm` configuration download a new version of LLVM from CI, even if the LLVM submodule hasn’t changed. -Last change is for: https://github.com/rust-lang/rust/pull/96971 +Last change is for: https://github.com/rust-lang/rust/pull/112931 diff --git a/src/bootstrap/llvm.rs b/src/bootstrap/llvm.rs index c4916a21c0fbf..7e27960f3e906 100644 --- a/src/bootstrap/llvm.rs +++ b/src/bootstrap/llvm.rs @@ -352,7 +352,7 @@ impl Step for Llvm { // Disable zstd to avoid a dependency on libzstd.so. cfg.define("LLVM_ENABLE_ZSTD", "OFF"); - if target != "aarch64-apple-darwin" && !target.contains("windows") { + if !target.contains("windows") { cfg.define("LLVM_ENABLE_ZLIB", "ON"); } else { cfg.define("LLVM_ENABLE_ZLIB", "OFF"); diff --git a/src/bootstrap/metrics.rs b/src/bootstrap/metrics.rs index 5990f33b9bc6c..b73df7fe82235 100644 --- a/src/bootstrap/metrics.rs +++ b/src/bootstrap/metrics.rs @@ -7,7 +7,10 @@ use crate::builder::{Builder, Step}; use crate::util::t; use crate::Build; -use serde_derive::{Deserialize, Serialize}; +use build_helper::metrics::{ + JsonInvocation, JsonInvocationSystemStats, JsonNode, JsonRoot, JsonStepSystemStats, Test, + TestOutcome, TestSuite, TestSuiteMetadata, +}; use std::cell::RefCell; use std::fs::File; use std::io::BufWriter; @@ -241,98 +244,7 @@ struct StepMetrics { test_suites: Vec, } -#[derive(Serialize, Deserialize)] -#[serde(rename_all = "snake_case")] -struct JsonRoot { - #[serde(default)] // For version 0 the field was not present. - format_version: usize, - system_stats: JsonInvocationSystemStats, - invocations: Vec, -} - -#[derive(Serialize, Deserialize)] -#[serde(rename_all = "snake_case")] -struct JsonInvocation { - // Unix timestamp in seconds - // - // This is necessary to easily correlate this invocation with logs or other data. - start_time: u64, - duration_including_children_sec: f64, - children: Vec, -} - -#[derive(Serialize, Deserialize)] -#[serde(tag = "kind", rename_all = "snake_case")] -enum JsonNode { - RustbuildStep { - #[serde(rename = "type")] - type_: String, - debug_repr: String, - - duration_excluding_children_sec: f64, - system_stats: JsonStepSystemStats, - - children: Vec, - }, - TestSuite(TestSuite), -} - -#[derive(Serialize, Deserialize)] -struct TestSuite { - metadata: TestSuiteMetadata, - tests: Vec, -} - -#[derive(Serialize, Deserialize)] -#[serde(tag = "kind", rename_all = "snake_case")] -pub(crate) enum TestSuiteMetadata { - CargoPackage { - crates: Vec, - target: String, - host: String, - stage: u32, - }, - Compiletest { - suite: String, - mode: String, - compare_mode: Option, - target: String, - host: String, - stage: u32, - }, -} - -#[derive(Serialize, Deserialize)] -pub(crate) struct Test { - name: String, - #[serde(flatten)] - outcome: TestOutcome, -} - -#[derive(Serialize, Deserialize)] -#[serde(tag = "outcome", rename_all = "snake_case")] -pub(crate) enum TestOutcome { - Passed, - Failed, - Ignored { ignore_reason: Option }, -} - -#[derive(Serialize, Deserialize)] -#[serde(rename_all = "snake_case")] -struct JsonInvocationSystemStats { - cpu_threads_count: usize, - cpu_model: String, - - memory_total_bytes: u64, -} - -#[derive(Serialize, Deserialize)] -#[serde(rename_all = "snake_case")] -struct JsonStepSystemStats { - cpu_utilization_percent: f64, -} - -#[derive(Deserialize)] +#[derive(serde_derive::Deserialize)] struct OnlyFormatVersion { #[serde(default)] // For version 0 the field was not present. format_version: usize, diff --git a/src/bootstrap/render_tests.rs b/src/bootstrap/render_tests.rs index 98a468c883df1..ccd067053ef1b 100644 --- a/src/bootstrap/render_tests.rs +++ b/src/bootstrap/render_tests.rs @@ -141,9 +141,9 @@ impl<'a> Renderer<'a> { self.builder.metrics.record_test( &test.name, match outcome { - Outcome::Ok | Outcome::BenchOk => crate::metrics::TestOutcome::Passed, - Outcome::Failed => crate::metrics::TestOutcome::Failed, - Outcome::Ignored { reason } => crate::metrics::TestOutcome::Ignored { + Outcome::Ok | Outcome::BenchOk => build_helper::metrics::TestOutcome::Passed, + Outcome::Failed => build_helper::metrics::TestOutcome::Failed, + Outcome::Ignored { reason } => build_helper::metrics::TestOutcome::Ignored { ignore_reason: reason.map(|s| s.to_string()), }, }, diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index e4cc88c64a590..0907291b54da7 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -340,7 +340,7 @@ impl Step for Cargo { #[cfg(feature = "build-metrics")] builder.metrics.begin_test_suite( - crate::metrics::TestSuiteMetadata::CargoPackage { + build_helper::metrics::TestSuiteMetadata::CargoPackage { crates: vec!["cargo".into()], target: self.host.triple.to_string(), host: self.host.triple.to_string(), @@ -799,6 +799,10 @@ impl Step for Clippy { // The tests succeeded; nothing to do. return; } + + if !builder.config.cmd.bless() { + crate::detail_exit_macro!(1); + } } } @@ -1823,7 +1827,7 @@ note: if you're sure you want to do this, please open an issue as to why. In the #[cfg(feature = "build-metrics")] builder.metrics.begin_test_suite( - crate::metrics::TestSuiteMetadata::Compiletest { + build_helper::metrics::TestSuiteMetadata::Compiletest { suite: suite.into(), mode: mode.into(), compare_mode: None, @@ -1848,7 +1852,7 @@ note: if you're sure you want to do this, please open an issue as to why. In the #[cfg(feature = "build-metrics")] builder.metrics.begin_test_suite( - crate::metrics::TestSuiteMetadata::Compiletest { + build_helper::metrics::TestSuiteMetadata::Compiletest { suite: suite.into(), mode: mode.into(), compare_mode: Some(compare_mode.into()), @@ -2196,7 +2200,7 @@ fn run_cargo_test( #[cfg(feature = "build-metrics")] builder.metrics.begin_test_suite( - crate::metrics::TestSuiteMetadata::CargoPackage { + build_helper::metrics::TestSuiteMetadata::CargoPackage { crates: crates.iter().map(|c| c.to_string()).collect(), target: target.triple.to_string(), host: compiler.host.triple.to_string(), diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index 06c0317886299..915dceae3893a 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -303,6 +303,7 @@ bootstrap_tool!( SuggestTests, "src/tools/suggest-tests", "suggest-tests"; GenerateWindowsSys, "src/tools/generate-windows-sys", "generate-windows-sys"; RustdocGUITest, "src/tools/rustdoc-gui-test", "rustdoc-gui-test", is_unstable_tool = true, allow_features = "test"; + OptimizedDist, "src/tools/opt-dist", "opt-dist"; ); #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, Ord, PartialOrd)] 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 c2fd2e3a91aef..1fcb99f6d5f3f 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 @@ -54,7 +54,8 @@ COPY host-x86_64/dist-x86_64-linux/build-clang.sh /tmp/ RUN ./build-clang.sh ENV CC=clang CXX=clang++ -# rustc-perf version from 2023-03-15 +# rustc-perf version from 2023-05-30 +# Should also be changed in the opt-dist tool for other environments. ENV PERF_COMMIT 8b2ac3042e1ff2c0074455a0a3618adef97156b1 RUN curl -LS -o perf.zip https://github.com/rust-lang/rustc-perf/archive/$PERF_COMMIT.zip && \ unzip perf.zip && \ @@ -81,7 +82,9 @@ ENV RUST_CONFIGURE_ARGS \ --set rust.jemalloc \ --set rust.use-lld=true \ --set rust.lto=thin -ENV SCRIPT python3 ../src/ci/stage-build.py python3 ../x.py dist \ + +ENV SCRIPT python3 ../x.py build --set rust.debug=true opt-dist && \ + ./build/$HOSTS/stage0-tools-bin/opt-dist python3 ../x.py dist \ --host $HOSTS --target $HOSTS \ --include-default-paths \ build-manifest bootstrap diff --git a/src/ci/docker/host-x86_64/test-various/Dockerfile b/src/ci/docker/host-x86_64/test-various/Dockerfile index 1dc7b79872438..a1d06ab18443c 100644 --- a/src/ci/docker/host-x86_64/test-various/Dockerfile +++ b/src/ci/docker/host-x86_64/test-various/Dockerfile @@ -24,7 +24,7 @@ RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-ins qemu-system-x86 \ && rm -rf /var/lib/apt/lists/* -RUN curl -sL https://nodejs.org/dist/v15.14.0/node-v15.14.0-linux-x64.tar.xz | \ +RUN curl -sL https://nodejs.org/dist/v18.12.0/node-v18.12.0-linux-x64.tar.xz | \ tar -xJ # Install 32-bit OVMF files for the i686-unknown-uefi test. This package @@ -42,7 +42,7 @@ RUN sh /scripts/sccache.sh ENV RUST_CONFIGURE_ARGS \ --musl-root-x86_64=/usr/local/x86_64-linux-musl \ - --set build.nodejs=/node-v15.14.0-linux-x64/bin/node \ + --set build.nodejs=/node-v18.12.0-linux-x64/bin/node \ --set rust.lld # Some run-make tests have assertions about code size, and enabling debug @@ -58,6 +58,8 @@ ENV WASM_SCRIPT python3 /checkout/x.py --stage 2 test --host='' --target $WASM_T tests/ui \ tests/mir-opt \ tests/codegen-units \ + tests/codegen \ + tests/assembly \ library/core ENV NVPTX_TARGETS=nvptx64-nvidia-cuda diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml index 24fc72e660a65..b5b478e60f466 100644 --- a/src/ci/github-actions/ci.yml +++ b/src/ci/github-actions/ci.yml @@ -302,7 +302,7 @@ concurrency: # For a given workflow, if we push to the same branch, cancel all previous builds on that branch. # We add an exception for try builds (try branch) and unrolled rollup builds (try-perf), which # are all triggered on the same branch, but which should be able to run concurrently. - group: ${{ ((github.ref == 'refs/heads/try' || github.ref == 'refs/heads/try-perf') && github.sha) || github.ref }} + group: ${{ github.workflow }}-${{ ((github.ref == 'refs/heads/try' || github.ref == 'refs/heads/try-perf') && github.sha) || github.ref }} cancel-in-progress: true jobs: @@ -643,7 +643,7 @@ jobs: --target=x86_64-pc-windows-msvc --enable-full-tools --enable-profiler - SCRIPT: PGO_HOST=x86_64-pc-windows-msvc python src/ci/stage-build.py python x.py dist bootstrap --include-default-paths + SCRIPT: python x.py build --set rust.debug=true opt-dist && PGO_HOST=x86_64-pc-windows-msvc ./build/x86_64-pc-windows-msvc/stage0-tools-bin/opt-dist python x.py dist bootstrap --include-default-paths DIST_REQUIRE_ALL_TOOLS: 1 <<: *job-windows-8c diff --git a/src/ci/stage-build.py b/src/ci/stage-build.py deleted file mode 100755 index 8640a3e0f3454..0000000000000 --- a/src/ci/stage-build.py +++ /dev/null @@ -1,1035 +0,0 @@ -#!/usr/bin/env python3 -# ignore-tidy-linelength - -# Compatible with Python 3.6+ - -import contextlib -import getpass -import glob -import json -import logging -import os -import pprint -import shutil -import subprocess -import sys -import time -import traceback -import urllib.request -from io import StringIO -from pathlib import Path -from typing import Callable, ContextManager, Dict, Iterable, Iterator, List, Optional, \ - Tuple, Union - -PGO_HOST = os.environ["PGO_HOST"] - -LOGGER = logging.getLogger("stage-build") - -LLVM_PGO_CRATES = [ - "syn-1.0.89", - "cargo-0.60.0", - "serde-1.0.136", - "ripgrep-13.0.0", - "regex-1.5.5", - "clap-3.1.6", - "hyper-0.14.18" -] - -RUSTC_PGO_CRATES = [ - "externs", - "ctfe-stress-5", - "cargo-0.60.0", - "token-stream-stress", - "match-stress", - "tuple-stress", - "diesel-1.4.8", - "bitmaps-3.1.0" -] - -LLVM_BOLT_CRATES = LLVM_PGO_CRATES - - -def is_try_build() -> bool: - return os.environ.get("DIST_TRY_BUILD", "0") != "0" - - -class Pipeline: - # Paths - def checkout_path(self) -> Path: - """ - The root checkout, where the source is located. - """ - raise NotImplementedError - - def downloaded_llvm_dir(self) -> Path: - """ - Directory where the host LLVM is located. - """ - raise NotImplementedError - - def build_root(self) -> Path: - """ - The main directory where the build occurs. - """ - raise NotImplementedError - - def build_artifacts(self) -> Path: - return self.build_root() / "build" / PGO_HOST - - def rustc_stage_0(self) -> Path: - return self.build_artifacts() / "stage0" / "bin" / "rustc" - - def cargo_stage_0(self) -> Path: - return self.build_artifacts() / "stage0" / "bin" / "cargo" - - def rustc_stage_2(self) -> Path: - return self.build_artifacts() / "stage2" / "bin" / "rustc" - - def opt_artifacts(self) -> Path: - raise NotImplementedError - - def llvm_profile_dir_root(self) -> Path: - return self.opt_artifacts() / "llvm-pgo" - - def llvm_profile_merged_file(self) -> Path: - return self.opt_artifacts() / "llvm-pgo.profdata" - - def rustc_perf_dir(self) -> Path: - return self.opt_artifacts() / "rustc-perf" - - def build_rustc_perf(self): - raise NotImplementedError() - - def rustc_profile_dir_root(self) -> Path: - return self.opt_artifacts() / "rustc-pgo" - - def rustc_profile_merged_file(self) -> Path: - return self.opt_artifacts() / "rustc-pgo.profdata" - - def rustc_profile_template_path(self) -> Path: - """ - The profile data is written into a single filepath that is being repeatedly merged when each - rustc invocation ends. Empirically, this can result in some profiling data being lost. That's - why we override the profile path to include the PID. This will produce many more profiling - files, but the resulting profile will produce a slightly faster rustc binary. - """ - return self.rustc_profile_dir_root() / "default_%m_%p.profraw" - - def supports_bolt(self) -> bool: - raise NotImplementedError - - def llvm_bolt_profile_merged_file(self) -> Path: - return self.opt_artifacts() / "bolt.profdata" - - def metrics_path(self) -> Path: - return self.build_root() / "build" / "metrics.json" - - def executable_extension(self) -> str: - raise NotImplementedError - - def skipped_tests(self) -> Iterable[str]: - return () - - -class LinuxPipeline(Pipeline): - def checkout_path(self) -> Path: - return Path("/checkout") - - def downloaded_llvm_dir(self) -> Path: - return Path("/rustroot") - - def build_root(self) -> Path: - return self.checkout_path() / "obj" - - def opt_artifacts(self) -> Path: - return Path("/tmp/tmp-multistage/opt-artifacts") - - def build_rustc_perf(self): - # /tmp/rustc-perf comes from the Dockerfile - shutil.copytree("/tmp/rustc-perf", self.rustc_perf_dir()) - cmd(["chown", "-R", f"{getpass.getuser()}:", self.rustc_perf_dir()]) - - with change_cwd(self.rustc_perf_dir()): - cmd([self.cargo_stage_0(), "build", "-p", "collector"], env=dict( - RUSTC=str(self.rustc_stage_0()), - RUSTC_BOOTSTRAP="1" - )) - - def supports_bolt(self) -> bool: - return True - - def executable_extension(self) -> str: - return "" - - def skipped_tests(self) -> Iterable[str]: - # This test fails because of linker errors, as of June 2023. - yield "tests/ui/process/nofile-limit.rs" - - -class WindowsPipeline(Pipeline): - def __init__(self): - self.checkout_dir = Path(os.getcwd()) - - def checkout_path(self) -> Path: - return self.checkout_dir - - def downloaded_llvm_dir(self) -> Path: - return self.checkout_path() / "citools" / "clang-rust" - - def build_root(self) -> Path: - return self.checkout_path() - - def opt_artifacts(self) -> Path: - return self.checkout_path() / "opt-artifacts" - - def rustc_stage_0(self) -> Path: - return super().rustc_stage_0().with_suffix(".exe") - - def cargo_stage_0(self) -> Path: - return super().cargo_stage_0().with_suffix(".exe") - - def rustc_stage_2(self) -> Path: - return super().rustc_stage_2().with_suffix(".exe") - - def build_rustc_perf(self): - # rustc-perf version from 2023-03-15 - perf_commit = "8b2ac3042e1ff2c0074455a0a3618adef97156b1" - rustc_perf_zip_path = self.opt_artifacts() / "perf.zip" - - def download_rustc_perf(): - download_file( - f"https://github.com/rust-lang/rustc-perf/archive/{perf_commit}.zip", - rustc_perf_zip_path - ) - with change_cwd(self.opt_artifacts()): - unpack_archive(rustc_perf_zip_path) - move_path(Path(f"rustc-perf-{perf_commit}"), self.rustc_perf_dir()) - delete_file(rustc_perf_zip_path) - - retry_action(download_rustc_perf, "Download rustc-perf") - - with change_cwd(self.rustc_perf_dir()): - cmd([self.cargo_stage_0(), "build", "-p", "collector"], env=dict( - RUSTC=str(self.rustc_stage_0()), - RUSTC_BOOTSTRAP="1" - )) - - def rustc_profile_template_path(self) -> Path: - """ - On Windows, we don't have enough space to use separate files for each rustc invocation. - Therefore, we use a single file for the generated profiles. - """ - return self.rustc_profile_dir_root() / "default_%m.profraw" - - def supports_bolt(self) -> bool: - return False - - def executable_extension(self) -> str: - return ".exe" - - def skipped_tests(self) -> Iterable[str]: - # This test fails as of June 2023 - yield "tests\\codegen\\vec-shrink-panik.rs" - - -def get_timestamp() -> float: - return time.time() - - -Duration = float - - -def iterate_timers(timer: "Timer", name: str, level: int = 0) -> Iterator[ - Tuple[int, str, Duration]]: - """ - Hierarchically iterate the children of a timer, in a depth-first order. - """ - yield (level, name, timer.total_duration()) - for (child_name, child_timer) in timer.children: - yield from iterate_timers(child_timer, child_name, level=level + 1) - - -class Timer: - def __init__(self, parent_names: Tuple[str, ...] = ()): - self.children: List[Tuple[str, Timer]] = [] - self.section_active = False - self.parent_names = parent_names - self.duration_excluding_children: Duration = 0 - - @contextlib.contextmanager - def section(self, name: str) -> ContextManager["Timer"]: - assert not self.section_active - self.section_active = True - - start = get_timestamp() - exc = None - - child_timer = Timer(parent_names=self.parent_names + (name,)) - full_name = " > ".join(child_timer.parent_names) - try: - LOGGER.info(f"Section `{full_name}` starts") - yield child_timer - except BaseException as exception: - exc = exception - raise - finally: - end = get_timestamp() - duration = end - start - - child_timer.duration_excluding_children = duration - child_timer.total_duration() - self.add_child(name, child_timer) - if exc is None: - LOGGER.info(f"Section `{full_name}` ended: OK ({duration:.2f}s)") - else: - LOGGER.info(f"Section `{full_name}` ended: FAIL ({duration:.2f}s)") - self.section_active = False - - def total_duration(self) -> Duration: - return self.duration_excluding_children + sum( - c.total_duration() for (_, c) in self.children) - - def has_children(self) -> bool: - return len(self.children) > 0 - - def print_stats(self): - rows = [] - for (child_name, child_timer) in self.children: - for (level, name, duration) in iterate_timers(child_timer, child_name, level=0): - label = f"{' ' * level}{name}:" - rows.append((label, duration)) - - # Empty row - rows.append(("", "")) - - total_duration_label = "Total duration:" - total_duration = self.total_duration() - rows.append((total_duration_label, humantime(total_duration))) - - space_after_label = 2 - max_label_length = max(16, max(len(label) for (label, _) in rows)) + space_after_label - - table_width = max_label_length + 23 - divider = "-" * table_width - - with StringIO() as output: - print(divider, file=output) - for (label, duration) in rows: - if isinstance(duration, Duration): - pct = (duration / total_duration) * 100 - value = f"{duration:>12.2f}s ({pct:>5.2f}%)" - else: - value = f"{duration:>{len(total_duration_label) + 7}}" - print(f"{label:<{max_label_length}} {value}", file=output) - print(divider, file=output, end="") - LOGGER.info(f"Timer results\n{output.getvalue()}") - - def add_child(self, name: str, timer: "Timer"): - self.children.append((name, timer)) - - def add_duration(self, name: str, duration: Duration): - timer = Timer(parent_names=self.parent_names + (name,)) - timer.duration_excluding_children = duration - self.add_child(name, timer) - - -class BuildStep: - def __init__(self, type: str, children: List["BuildStep"], duration: float): - self.type = type - self.children = children - self.duration = duration - - def find_all_by_type(self, type: str) -> Iterator["BuildStep"]: - if type == self.type: - yield self - for child in self.children: - yield from child.find_all_by_type(type) - - def __repr__(self): - return f"BuildStep(type={self.type}, duration={self.duration}, children={len(self.children)})" - - -def load_last_metrics(path: Path) -> BuildStep: - """ - Loads the metrics of the most recent bootstrap execution from a metrics.json file. - """ - with open(path, "r") as f: - metrics = json.load(f) - invocation = metrics["invocations"][-1] - - def parse(entry) -> Optional[BuildStep]: - if "kind" not in entry or entry["kind"] != "rustbuild_step": - return None - type = entry.get("type", "") - duration = entry.get("duration_excluding_children_sec", 0) - children = [] - - for child in entry.get("children", ()): - step = parse(child) - if step is not None: - children.append(step) - duration += step.duration - return BuildStep(type=type, children=children, duration=duration) - - children = [parse(child) for child in invocation.get("children", ())] - return BuildStep( - type="root", - children=children, - duration=invocation.get("duration_including_children_sec", 0) - ) - - -@contextlib.contextmanager -def change_cwd(dir: Path): - """ - Temporarily change working directory to `dir`. - """ - cwd = os.getcwd() - LOGGER.debug(f"Changing working dir from `{cwd}` to `{dir}`") - os.chdir(dir) - try: - yield - finally: - LOGGER.debug(f"Reverting working dir to `{cwd}`") - os.chdir(cwd) - - -def humantime(time_s: float) -> str: - hours = time_s // 3600 - time_s = time_s % 3600 - minutes = time_s // 60 - seconds = time_s % 60 - - result = "" - if hours > 0: - result += f"{int(hours)}h " - if minutes > 0: - result += f"{int(minutes)}m " - result += f"{round(seconds)}s" - return result - - -def move_path(src: Path, dst: Path): - LOGGER.info(f"Moving `{src}` to `{dst}`") - shutil.move(src, dst) - - -def delete_file(path: Path): - LOGGER.info(f"Deleting file `{path}`") - os.unlink(path) - - -def delete_directory(path: Path): - LOGGER.info(f"Deleting directory `{path}`") - shutil.rmtree(path) - - -def unpack_archive(archive: Path, target_dir: Optional[Path] = None): - LOGGER.info(f"Unpacking archive `{archive}`") - shutil.unpack_archive(str(archive), extract_dir=str(target_dir) if target_dir is not None else None) - - -def download_file(src: str, target: Path): - LOGGER.info(f"Downloading `{src}` into `{target}`") - urllib.request.urlretrieve(src, str(target)) - - -def retry_action(action, name: str, max_fails: int = 5): - LOGGER.info(f"Attempting to perform action `{name}` with retry") - for iteration in range(max_fails): - LOGGER.info(f"Attempt {iteration + 1}/{max_fails}") - try: - action() - return - except BaseException: # also catch ctrl+c/sysexit - LOGGER.error(f"Action `{name}` has failed\n{traceback.format_exc()}") - - raise Exception(f"Action `{name}` has failed after {max_fails} attempts") - - -def cmd( - args: List[Union[str, Path]], - env: Optional[Dict[str, str]] = None, - output_path: Optional[Path] = None -): - args = [str(arg) for arg in args] - - environment = os.environ.copy() - - cmd_str = "" - if env is not None: - environment.update(env) - cmd_str += " ".join(f"{k}={v}" for (k, v) in (env or {}).items()) - cmd_str += " " - cmd_str += " ".join(args) - if output_path is not None: - cmd_str += f" > {output_path}" - LOGGER.info(f"Executing `{cmd_str}`") - - if output_path is not None: - with open(output_path, "w") as f: - return subprocess.run( - args, - env=environment, - check=True, - stdout=f - ) - return subprocess.run(args, env=environment, check=True) - - -class BenchmarkRunner: - def run_rustc(self, pipeline: Pipeline): - raise NotImplementedError - - def run_llvm(self, pipeline: Pipeline): - raise NotImplementedError - - def run_bolt(self, pipeline: Pipeline): - raise NotImplementedError - - -class DefaultBenchmarkRunner(BenchmarkRunner): - def run_rustc(self, pipeline: Pipeline): - # Here we're profiling the `rustc` frontend, so we also include `Check`. - # The benchmark set includes various stress tests that put the frontend under pressure. - run_compiler_benchmarks( - pipeline, - profiles=["Check", "Debug", "Opt"], - scenarios=["All"], - crates=RUSTC_PGO_CRATES, - env=dict( - LLVM_PROFILE_FILE=str(pipeline.rustc_profile_template_path()) - ) - ) - - def run_llvm(self, pipeline: Pipeline): - run_compiler_benchmarks( - pipeline, - profiles=["Debug", "Opt"], - scenarios=["Full"], - crates=LLVM_PGO_CRATES - ) - - def run_bolt(self, pipeline: Pipeline): - run_compiler_benchmarks( - pipeline, - profiles=["Check", "Debug", "Opt"], - scenarios=["Full"], - crates=LLVM_BOLT_CRATES - ) - - -def run_compiler_benchmarks( - pipeline: Pipeline, - profiles: List[str], - scenarios: List[str], - crates: List[str], - env: Optional[Dict[str, str]] = None -): - env = env if env is not None else {} - - # Compile libcore, both in opt-level=0 and opt-level=3 - with change_cwd(pipeline.build_root()): - cmd([ - pipeline.rustc_stage_2(), - "--edition", "2021", - "--crate-type", "lib", - str(pipeline.checkout_path() / "library/core/src/lib.rs"), - "--out-dir", pipeline.opt_artifacts() - ], env=dict(RUSTC_BOOTSTRAP="1", **env)) - - cmd([ - pipeline.rustc_stage_2(), - "--edition", "2021", - "--crate-type", "lib", - "-Copt-level=3", - str(pipeline.checkout_path() / "library/core/src/lib.rs"), - "--out-dir", pipeline.opt_artifacts() - ], env=dict(RUSTC_BOOTSTRAP="1", **env)) - - # Run rustc-perf benchmarks - # Benchmark using profile_local with eprintln, which essentially just means - # don't actually benchmark -- just make sure we run rustc a bunch of times. - with change_cwd(pipeline.rustc_perf_dir()): - cmd([ - pipeline.cargo_stage_0(), - "run", - "-p", "collector", "--bin", "collector", "--", - "profile_local", "eprintln", - pipeline.rustc_stage_2(), - "--id", "Test", - "--cargo", pipeline.cargo_stage_0(), - "--profiles", ",".join(profiles), - "--scenarios", ",".join(scenarios), - "--include", ",".join(crates) - ], env=dict( - RUST_LOG="collector=debug", - RUSTC=str(pipeline.rustc_stage_0()), - RUSTC_BOOTSTRAP="1", - **env - )) - - -# https://stackoverflow.com/a/31631711/1107768 -def format_bytes(size: int) -> str: - """Return the given bytes as a human friendly KiB, MiB or GiB string.""" - KB = 1024 - MB = KB ** 2 # 1,048,576 - GB = KB ** 3 # 1,073,741,824 - TB = KB ** 4 # 1,099,511,627,776 - - if size < KB: - return f"{size} B" - elif KB <= size < MB: - return f"{size / KB:.2f} KiB" - elif MB <= size < GB: - return f"{size / MB:.2f} MiB" - elif GB <= size < TB: - return f"{size / GB:.2f} GiB" - else: - return str(size) - - -# https://stackoverflow.com/a/63307131/1107768 -def count_files(path: Path) -> int: - return sum(1 for p in path.rglob("*") if p.is_file()) - - -def count_files_with_prefix(path: Path) -> int: - return sum(1 for p in glob.glob(f"{path}*") if Path(p).is_file()) - - -# https://stackoverflow.com/a/55659577/1107768 -def get_path_size(path: Path) -> int: - if path.is_dir(): - return sum(p.stat().st_size for p in path.rglob("*")) - return path.stat().st_size - - -def get_path_prefix_size(path: Path) -> int: - """ - Get size of all files beginning with the prefix `path`. - Alternative to shell `du -sh *`. - """ - return sum(Path(p).stat().st_size for p in glob.glob(f"{path}*")) - - -def get_files(directory: Path, filter: Optional[Callable[[Path], bool]] = None) -> Iterable[Path]: - for file in os.listdir(directory): - path = directory / file - if filter is None or filter(path): - yield path - - -def bootstrap_build( - pipeline: Pipeline, - args: List[str], - env: Optional[Dict[str, str]] = None, - targets: Iterable[str] = ("library/std", ) -): - if env is None: - env = {} - else: - env = dict(env) - env["RUST_BACKTRACE"] = "1" - arguments = [ - sys.executable, - pipeline.checkout_path() / "x.py", - "build", - "--target", PGO_HOST, - "--host", PGO_HOST, - "--stage", "2", - ] + list(targets) + args - cmd(arguments, env=env) - - -def create_pipeline() -> Pipeline: - if sys.platform == "linux": - return LinuxPipeline() - elif sys.platform in ("cygwin", "win32"): - return WindowsPipeline() - else: - raise Exception(f"Optimized build is not supported for platform {sys.platform}") - - -def gather_llvm_profiles(pipeline: Pipeline, runner: BenchmarkRunner): - LOGGER.info("Running benchmarks with PGO instrumented LLVM") - - runner.run_llvm(pipeline) - - profile_path = pipeline.llvm_profile_merged_file() - LOGGER.info(f"Merging LLVM PGO profiles to {profile_path}") - cmd([ - pipeline.downloaded_llvm_dir() / "bin" / "llvm-profdata", - "merge", - "-o", profile_path, - pipeline.llvm_profile_dir_root() - ]) - - LOGGER.info("LLVM PGO statistics") - LOGGER.info(f"{profile_path}: {format_bytes(get_path_size(profile_path))}") - LOGGER.info( - f"{pipeline.llvm_profile_dir_root()}: {format_bytes(get_path_size(pipeline.llvm_profile_dir_root()))}") - LOGGER.info(f"Profile file count: {count_files(pipeline.llvm_profile_dir_root())}") - - # We don't need the individual .profraw files now that they have been merged - # into a final .profdata - delete_directory(pipeline.llvm_profile_dir_root()) - - -def gather_rustc_profiles(pipeline: Pipeline, runner: BenchmarkRunner): - LOGGER.info("Running benchmarks with PGO instrumented rustc") - - runner.run_rustc(pipeline) - - profile_path = pipeline.rustc_profile_merged_file() - LOGGER.info(f"Merging Rustc PGO profiles to {profile_path}") - cmd([ - pipeline.build_artifacts() / "llvm" / "bin" / "llvm-profdata", - "merge", - "-o", profile_path, - pipeline.rustc_profile_dir_root() - ]) - - LOGGER.info("Rustc PGO statistics") - LOGGER.info(f"{profile_path}: {format_bytes(get_path_size(profile_path))}") - LOGGER.info( - f"{pipeline.rustc_profile_dir_root()}: {format_bytes(get_path_size(pipeline.rustc_profile_dir_root()))}") - LOGGER.info(f"Profile file count: {count_files(pipeline.rustc_profile_dir_root())}") - - # We don't need the individual .profraw files now that they have been merged - # into a final .profdata - delete_directory(pipeline.rustc_profile_dir_root()) - - -def gather_llvm_bolt_profiles(pipeline: Pipeline, runner: BenchmarkRunner): - LOGGER.info("Running benchmarks with BOLT instrumented LLVM") - - runner.run_bolt(pipeline) - - merged_profile_path = pipeline.llvm_bolt_profile_merged_file() - profile_files_path = Path("/tmp/prof.fdata") - LOGGER.info(f"Merging LLVM BOLT profiles to {merged_profile_path}") - - profile_files = sorted(glob.glob(f"{profile_files_path}*")) - cmd([ - "merge-fdata", - *profile_files, - ], output_path=merged_profile_path) - - LOGGER.info("LLVM BOLT statistics") - LOGGER.info(f"{merged_profile_path}: {format_bytes(get_path_size(merged_profile_path))}") - LOGGER.info( - f"{profile_files_path}: {format_bytes(get_path_prefix_size(profile_files_path))}") - LOGGER.info(f"Profile file count: {count_files_with_prefix(profile_files_path)}") - - -def clear_llvm_files(pipeline: Pipeline): - """ - Rustbuild currently doesn't support rebuilding LLVM when PGO options - change (or any other llvm-related options); so just clear out the relevant - directories ourselves. - """ - LOGGER.info("Clearing LLVM build files") - delete_directory(pipeline.build_artifacts() / "llvm") - delete_directory(pipeline.build_artifacts() / "lld") - - -def print_binary_sizes(pipeline: Pipeline): - bin_dir = pipeline.build_artifacts() / "stage2" / "bin" - binaries = get_files(bin_dir) - - lib_dir = pipeline.build_artifacts() / "stage2" / "lib" - libraries = get_files(lib_dir, lambda p: p.suffix == ".so") - - paths = sorted(binaries) + sorted(libraries) - with StringIO() as output: - for path in paths: - path_str = f"{path.name}:" - print(f"{path_str:<50}{format_bytes(path.stat().st_size):>14}", file=output) - LOGGER.info(f"Rustc binary size\n{output.getvalue()}") - - -def print_free_disk_space(pipeline: Pipeline): - usage = shutil.disk_usage(pipeline.opt_artifacts()) - total = usage.total - used = usage.used - free = usage.free - - logging.info( - f"Free disk space: {format_bytes(free)} out of total {format_bytes(total)} ({(used / total) * 100:.2f}% used)") - - -def log_metrics(step: BuildStep): - substeps: List[Tuple[int, BuildStep]] = [] - - def visit(step: BuildStep, level: int): - substeps.append((level, step)) - for child in step.children: - visit(child, level=level + 1) - - visit(step, 0) - - output = StringIO() - for (level, step) in substeps: - label = f"{'.' * level}{step.type}" - print(f"{label:<65}{step.duration:>8.2f}s", file=output) - logging.info(f"Build step durations\n{output.getvalue()}") - - -def record_metrics(pipeline: Pipeline, timer: Timer): - metrics = load_last_metrics(pipeline.metrics_path()) - if metrics is None: - return - llvm_steps = tuple(metrics.find_all_by_type("bootstrap::llvm::Llvm")) - llvm_duration = sum(step.duration for step in llvm_steps) - - rustc_steps = tuple(metrics.find_all_by_type("bootstrap::compile::Rustc")) - rustc_duration = sum(step.duration for step in rustc_steps) - - # The LLVM step is part of the Rustc step - rustc_duration = max(0, rustc_duration - llvm_duration) - - if llvm_duration > 0: - timer.add_duration("LLVM", llvm_duration) - if rustc_duration > 0: - timer.add_duration("Rustc", rustc_duration) - - log_metrics(metrics) - - -def run_tests(pipeline: Pipeline): - """ - After `dist` is executed, we extract its archived components into a sysroot directory, - and then use that extracted rustc as a stage0 compiler. - Then we run a subset of tests using that compiler, to have a basic smoke test which checks - whether the optimization pipeline hasn't broken something. - """ - build_dir = pipeline.build_root() / "build" - dist_dir = build_dir / "dist" - - def extract_dist_dir(name: str) -> Path: - target_dir = build_dir / "optimized-dist" - target_dir.mkdir(parents=True, exist_ok=True) - unpack_archive(dist_dir / f"{name}.tar.xz", target_dir=target_dir) - extracted_path = target_dir / name - assert extracted_path.is_dir() - return extracted_path - - # Extract rustc, libstd, cargo and src archives to create the optimized sysroot - rustc_dir = extract_dist_dir(f"rustc-nightly-{PGO_HOST}") / "rustc" - libstd_dir = extract_dist_dir(f"rust-std-nightly-{PGO_HOST}") / f"rust-std-{PGO_HOST}" - cargo_dir = extract_dist_dir(f"cargo-nightly-{PGO_HOST}") / "cargo" - extracted_src_dir = extract_dist_dir("rust-src-nightly") / "rust-src" - - # We need to manually copy libstd to the extracted rustc sysroot - shutil.copytree( - libstd_dir / "lib" / "rustlib" / PGO_HOST / "lib", - rustc_dir / "lib" / "rustlib" / PGO_HOST / "lib" - ) - - # Extract sources - they aren't in the `rustc-nightly-{host}` tarball, so we need to manually copy libstd - # sources to the extracted sysroot. We need sources available so that `-Zsimulate-remapped-rust-src-base` - # works correctly. - shutil.copytree( - extracted_src_dir / "lib" / "rustlib" / "src", - rustc_dir / "lib" / "rustlib" / "src" - ) - - rustc_path = rustc_dir / "bin" / f"rustc{pipeline.executable_extension()}" - assert rustc_path.is_file() - cargo_path = cargo_dir / "bin" / f"cargo{pipeline.executable_extension()}" - assert cargo_path.is_file() - - # Specify path to a LLVM config so that LLVM is not rebuilt. - # It doesn't really matter which LLVM config we choose, because no sysroot will be compiled. - llvm_config = pipeline.build_artifacts() / "llvm" / "bin" / f"llvm-config{pipeline.executable_extension()}" - assert llvm_config.is_file() - - config_content = f"""profile = "user" -changelog-seen = 2 - -[build] -rustc = "{rustc_path.as_posix()}" -cargo = "{cargo_path.as_posix()}" - -[target.{PGO_HOST}] -llvm-config = "{llvm_config.as_posix()}" -""" - logging.info(f"Using following `config.toml` for running tests:\n{config_content}") - - # Simulate a stage 0 compiler with the extracted optimized dist artifacts. - with open("config.toml", "w") as f: - f.write(config_content) - - args = [ - sys.executable, - pipeline.checkout_path() / "x.py", - "test", - "--stage", "0", - "tests/assembly", - "tests/codegen", - "tests/codegen-units", - "tests/incremental", - "tests/mir-opt", - "tests/pretty", - "tests/run-pass-valgrind", - "tests/ui", - ] - for test_path in pipeline.skipped_tests(): - args.extend(["--exclude", test_path]) - cmd(args=args, env=dict( - COMPILETEST_FORCE_STAGE0="1" - )) - - -def execute_build_pipeline(timer: Timer, pipeline: Pipeline, runner: BenchmarkRunner, dist_build_args: List[str]): - # Clear and prepare tmp directory - shutil.rmtree(pipeline.opt_artifacts(), ignore_errors=True) - os.makedirs(pipeline.opt_artifacts(), exist_ok=True) - - pipeline.build_rustc_perf() - - """ - Stage 1: Build PGO instrumented rustc - - We use a normal build of LLVM, because gathering PGO profiles for LLVM and `rustc` at the same time - can cause issues. - """ - with timer.section("Stage 1 (rustc PGO)") as stage1: - with stage1.section("Build PGO instrumented rustc and LLVM") as rustc_pgo_instrument: - bootstrap_build(pipeline, args=[ - "--rust-profile-generate", - pipeline.rustc_profile_dir_root() - ]) - record_metrics(pipeline, rustc_pgo_instrument) - - with stage1.section("Gather profiles"): - gather_rustc_profiles(pipeline, runner) - print_free_disk_space(pipeline) - - with stage1.section("Build PGO optimized rustc") as rustc_pgo_use: - bootstrap_build(pipeline, args=[ - "--rust-profile-use", - pipeline.rustc_profile_merged_file() - ]) - record_metrics(pipeline, rustc_pgo_use) - dist_build_args += [ - "--rust-profile-use", - pipeline.rustc_profile_merged_file() - ] - - """ - Stage 2: Gather LLVM PGO profiles - """ - with timer.section("Stage 2 (LLVM PGO)") as stage2: - # Clear normal LLVM artifacts - clear_llvm_files(pipeline) - - with stage2.section("Build PGO instrumented LLVM") as llvm_pgo_instrument: - bootstrap_build(pipeline, args=[ - "--llvm-profile-generate", - # We want to keep the already built PGO-optimized `rustc`. - "--keep-stage", "0", - "--keep-stage", "1" - ], env=dict( - LLVM_PROFILE_DIR=str(pipeline.llvm_profile_dir_root() / "prof-%p") - )) - record_metrics(pipeline, llvm_pgo_instrument) - - with stage2.section("Gather profiles"): - gather_llvm_profiles(pipeline, runner) - - dist_build_args += [ - "--llvm-profile-use", - pipeline.llvm_profile_merged_file(), - ] - print_free_disk_space(pipeline) - - # Clear PGO-instrumented LLVM artifacts - clear_llvm_files(pipeline) - - """ - Stage 3: Build BOLT instrumented LLVM - - We build a PGO optimized LLVM in this step, then instrument it with BOLT and gather BOLT profiles. - Note that we don't remove LLVM artifacts after this step, so that they are reused in the final dist build. - BOLT instrumentation is performed "on-the-fly" when the LLVM library is copied to the sysroot of rustc, - therefore the LLVM artifacts on disk are not "tainted" with BOLT instrumentation and they can be reused. - """ - if pipeline.supports_bolt(): - with timer.section("Stage 3 (LLVM BOLT)") as stage3: - with stage3.section("Build BOLT instrumented LLVM") as llvm_bolt_instrument: - bootstrap_build(pipeline, args=[ - "--llvm-profile-use", - pipeline.llvm_profile_merged_file(), - "--llvm-bolt-profile-generate", - # We want to keep the already built PGO-optimized `rustc`. - "--keep-stage", "0", - "--keep-stage", "1" - ]) - record_metrics(pipeline, llvm_bolt_instrument) - - with stage3.section("Gather profiles"): - gather_llvm_bolt_profiles(pipeline, runner) - - dist_build_args += [ - "--llvm-bolt-profile-use", - pipeline.llvm_bolt_profile_merged_file() - ] - print_free_disk_space(pipeline) - - # We want to keep the already built PGO-optimized `rustc`. - dist_build_args += [ - "--keep-stage", "0", - "--keep-stage", "1" - ] - - """ - Final stage: Build PGO optimized rustc + PGO/BOLT optimized LLVM - """ - with timer.section("Final stage (dist build)") as final_stage: - cmd(dist_build_args) - record_metrics(pipeline, final_stage) - - # Try builds can be in various broken states, so we don't want to gatekeep them with tests - if not is_try_build(): - with timer.section("Run tests"): - run_tests(pipeline) - - -def run(runner: BenchmarkRunner): - logging.basicConfig( - level=logging.DEBUG, - format="%(name)s %(levelname)-4s: %(message)s", - ) - - LOGGER.info(f"Running multi-stage build using Python {sys.version}") - LOGGER.info(f"Environment values\n{pprint.pformat(dict(os.environ), indent=2)}") - - build_args = sys.argv[1:] - - # Skip components that are not needed for try builds to speed them up - if is_try_build(): - LOGGER.info("Skipping building of unimportant components for a try build") - for target in ("rust-docs", "rustc-docs", "rust-docs-json", "rust-analyzer", - "rustc-src", "clippy", "miri", "rustfmt"): - build_args.extend(["--exclude", target]) - - timer = Timer() - pipeline = create_pipeline() - - try: - execute_build_pipeline(timer, pipeline, runner, build_args) - except BaseException as e: - LOGGER.error("The multi-stage build has failed") - raise e - finally: - timer.print_stats() - print_free_disk_space(pipeline) - - print_binary_sizes(pipeline) - - -if __name__ == "__main__": - runner = DefaultBenchmarkRunner() - run(runner) diff --git a/src/doc/unstable-book/src/library-features/default-free-fn.md b/src/doc/unstable-book/src/library-features/default-free-fn.md deleted file mode 100644 index bafc9ac4d0d96..0000000000000 --- a/src/doc/unstable-book/src/library-features/default-free-fn.md +++ /dev/null @@ -1,47 +0,0 @@ -# `default_free_fn` - -The tracking issue for this feature is: [#73014] - -[#73014]: https://github.com/rust-lang/rust/issues/73014 - ------------------------- - -Adds a free `default()` function to the `std::default` module. This function -just forwards to [`Default::default()`], but may remove repetition of the word -"default" from the call site. - -[`Default::default()`]: ../../std/default/trait.Default.html#tymethod.default - -Here is an example: - -```rust -#![feature(default_free_fn)] -use std::default::default; - -#[derive(Default)] -struct AppConfig { - foo: FooConfig, - bar: BarConfig, -} - -#[derive(Default)] -struct FooConfig { - foo: i32, -} - -#[derive(Default)] -struct BarConfig { - bar: f32, - baz: u8, -} - -fn main() { - let options = AppConfig { - foo: default(), - bar: BarConfig { - bar: 10.1, - ..default() - }, - }; -} -``` diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 870cfa93058aa..55321055f38fc 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -632,6 +632,10 @@ pub(crate) fn print_inlined_const(tcx: TyCtxt<'_>, did: DefId) -> String { } fn build_const(cx: &mut DocContext<'_>, def_id: DefId) -> clean::Constant { + let mut generics = + clean_ty_generics(cx, cx.tcx.generics_of(def_id), cx.tcx.explicit_predicates_of(def_id)); + clean::simplify::move_bounds_to_generic_parameters(&mut generics); + clean::Constant { type_: clean_middle_ty( ty::Binder::dummy(cx.tcx.type_of(def_id).subst_identity()), @@ -639,6 +643,7 @@ fn build_const(cx: &mut DocContext<'_>, def_id: DefId) -> clean::Constant { Some(def_id), None, ), + generics: Box::new(generics), kind: clean::ConstantKind::Extern { def_id }, } } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 0182d50773d77..b471afb07a1c6 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -256,6 +256,7 @@ pub(crate) fn clean_const<'tcx>(constant: &hir::ConstArg, cx: &mut DocContext<'t Some(def_id), None, ), + generics: Box::new(Generics::default()), kind: ConstantKind::Anonymous { body: constant.value.body }, } } @@ -267,6 +268,7 @@ pub(crate) fn clean_middle_const<'tcx>( // FIXME: instead of storing the stringified expression, store `self` directly instead. Constant { type_: clean_middle_ty(constant.map_bound(|c| c.ty()), cx, None, None), + generics: Box::new(Generics::default()), kind: ConstantKind::TyConst { expr: constant.skip_binder().to_string().into() }, } } @@ -1159,11 +1161,20 @@ fn clean_trait_item<'tcx>(trait_item: &hir::TraitItem<'tcx>, cx: &mut DocContext let local_did = trait_item.owner_id.to_def_id(); cx.with_param_env(local_did, |cx| { let inner = match trait_item.kind { - hir::TraitItemKind::Const(ty, Some(default)) => AssocConstItem( - clean_ty(ty, cx), - ConstantKind::Local { def_id: local_did, body: default }, - ), - hir::TraitItemKind::Const(ty, None) => TyAssocConstItem(clean_ty(ty, cx)), + hir::TraitItemKind::Const(ty, Some(default)) => { + // FIXME(generic_consts): I don't think we need to / should `enter_impl_trait` + let generics = enter_impl_trait(cx, |cx| clean_generics(trait_item.generics, cx)); + AssocConstItem( + Box::new(generics), + clean_ty(ty, cx), + ConstantKind::Local { def_id: local_did, body: default }, + ) + } + hir::TraitItemKind::Const(ty, None) => { + // FIXME(generic_consts): I don't think we need to / should `enter_impl_trait` + let generics = enter_impl_trait(cx, |cx| clean_generics(trait_item.generics, cx)); + TyAssocConstItem(Box::new(generics), clean_ty(ty, cx)) + } hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => { let m = clean_function(cx, sig, trait_item.generics, FunctionArgs::Body(body)); MethodItem(m, None) @@ -1208,8 +1219,9 @@ pub(crate) fn clean_impl_item<'tcx>( cx.with_param_env(local_did, |cx| { let inner = match impl_.kind { hir::ImplItemKind::Const(ty, expr) => { + let generics = clean_generics(impl_.generics, cx); let default = ConstantKind::Local { def_id: local_did, body: expr }; - AssocConstItem(clean_ty(ty, cx), default) + AssocConstItem(Box::new(generics), clean_ty(ty, cx), default) } hir::ImplItemKind::Fn(ref sig, body) => { let m = clean_function(cx, sig, impl_.generics, FunctionArgs::Body(body)); @@ -1250,14 +1262,21 @@ pub(crate) fn clean_middle_assoc_item<'tcx>( None, ); + let mut generics = Box::new(clean_ty_generics( + cx, + tcx.generics_of(assoc_item.def_id), + tcx.explicit_predicates_of(assoc_item.def_id), + )); + simplify::move_bounds_to_generic_parameters(&mut generics); + let provided = match assoc_item.container { ty::ImplContainer => true, ty::TraitContainer => tcx.defaultness(assoc_item.def_id).has_value(), }; if provided { - AssocConstItem(ty, ConstantKind::Extern { def_id: assoc_item.def_id }) + AssocConstItem(generics, ty, ConstantKind::Extern { def_id: assoc_item.def_id }) } else { - TyAssocConstItem(ty) + TyAssocConstItem(generics, ty) } } ty::AssocKind::Fn => { @@ -1348,34 +1367,7 @@ pub(crate) fn clean_middle_assoc_item<'tcx>( tcx.generics_of(assoc_item.def_id), ty::GenericPredicates { parent: None, predicates }, ); - // Move bounds that are (likely) directly attached to the parameters of the - // (generic) associated type from the where clause to the respective parameter. - // There is no guarantee that this is what the user actually wrote but we have - // no way of knowing. - let mut where_predicates = ThinVec::new(); - for mut pred in generics.where_predicates { - if let WherePredicate::BoundPredicate { ty: Generic(arg), bounds, .. } = &mut pred - && let Some(GenericParamDef { - kind: GenericParamDefKind::Type { bounds: param_bounds, .. }, - .. - }) = generics.params.iter_mut().find(|param| ¶m.name == arg) - { - param_bounds.append(bounds); - } else if let WherePredicate::RegionPredicate { lifetime: Lifetime(arg), bounds } = &mut pred - && let Some(GenericParamDef { - kind: GenericParamDefKind::Lifetime { outlives: param_bounds }, - .. - }) = generics.params.iter_mut().find(|param| ¶m.name == arg) - { - param_bounds.extend(bounds.drain(..).map(|bound| match bound { - GenericBound::Outlives(lifetime) => lifetime, - _ => unreachable!(), - })); - } else { - where_predicates.push(pred); - } - } - generics.where_predicates = where_predicates; + simplify::move_bounds_to_generic_parameters(&mut generics); if let ty::TraitContainer = assoc_item.container { // Move bounds that are (likely) directly attached to the associated type @@ -2446,8 +2438,9 @@ fn clean_maybe_renamed_item<'tcx>( ItemKind::Static(ty, mutability, body_id) => { StaticItem(Static { type_: clean_ty(ty, cx), mutability, expr: Some(body_id) }) } - ItemKind::Const(ty, body_id) => ConstantItem(Constant { + ItemKind::Const(ty, generics, body_id) => ConstantItem(Constant { type_: clean_ty(ty, cx), + generics: Box::new(clean_generics(generics, cx)), kind: ConstantKind::Local { body: body_id, def_id }, }), ItemKind::OpaqueTy(ref ty) => OpaqueTyItem(OpaqueTy { diff --git a/src/librustdoc/clean/simplify.rs b/src/librustdoc/clean/simplify.rs index 65b1b72adc153..22b9ab3100172 100644 --- a/src/librustdoc/clean/simplify.rs +++ b/src/librustdoc/clean/simplify.rs @@ -136,3 +136,38 @@ fn trait_is_same_or_supertrait(cx: &DocContext<'_>, child: DefId, trait_: DefId) }) .any(|did| trait_is_same_or_supertrait(cx, did, trait_)) } + +/// Move bounds that are (likely) directly attached to generic parameters from the where-clause to +/// the respective parameter. +/// +/// There is no guarantee that this is what the user actually wrote but we have no way of knowing. +// FIXME(fmease): It'd make a lot of sense to just incorporate this logic into `clean_ty_generics` +// making every of its users benefit from it. +pub(crate) fn move_bounds_to_generic_parameters(generics: &mut clean::Generics) { + use clean::types::*; + + let mut where_predicates = ThinVec::new(); + for mut pred in generics.where_predicates.drain(..) { + if let WherePredicate::BoundPredicate { ty: Generic(arg), bounds, .. } = &mut pred + && let Some(GenericParamDef { + kind: GenericParamDefKind::Type { bounds: param_bounds, .. }, + .. + }) = generics.params.iter_mut().find(|param| ¶m.name == arg) + { + param_bounds.append(bounds); + } else if let WherePredicate::RegionPredicate { lifetime: Lifetime(arg), bounds } = &mut pred + && let Some(GenericParamDef { + kind: GenericParamDefKind::Lifetime { outlives: param_bounds }, + .. + }) = generics.params.iter_mut().find(|param| ¶m.name == arg) + { + param_bounds.extend(bounds.drain(..).map(|bound| match bound { + GenericBound::Outlives(lifetime) => lifetime, + _ => unreachable!(), + })); + } else { + where_predicates.push(pred); + } + } + generics.where_predicates = where_predicates; +} diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 26139d5276919..1f696cfdcf0d1 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -830,9 +830,9 @@ pub(crate) enum ItemKind { ProcMacroItem(ProcMacro), PrimitiveItem(PrimitiveType), /// A required associated constant in a trait declaration. - TyAssocConstItem(Type), + TyAssocConstItem(Box, Type), /// An associated constant in a trait impl or a provided one in a trait declaration. - AssocConstItem(Type, ConstantKind), + AssocConstItem(Box, Type, ConstantKind), /// A required associated type in a trait declaration. /// /// The bounds may be non-empty if there is a `where` clause. @@ -877,8 +877,8 @@ impl ItemKind { | MacroItem(_) | ProcMacroItem(_) | PrimitiveItem(_) - | TyAssocConstItem(_) - | AssocConstItem(_, _) + | TyAssocConstItem(..) + | AssocConstItem(..) | TyAssocTypeItem(..) | AssocTypeItem(..) | StrippedItem(_) @@ -1275,7 +1275,7 @@ impl Lifetime { } } -#[derive(Clone, Debug)] +#[derive(Clone, PartialEq, Eq, Hash, Debug)] pub(crate) enum WherePredicate { BoundPredicate { ty: Type, bounds: Vec, bound_params: Vec }, RegionPredicate { lifetime: Lifetime, bounds: Vec }, @@ -1345,7 +1345,7 @@ impl GenericParamDef { } // maybe use a Generic enum and use Vec? -#[derive(Clone, Debug, Default)] +#[derive(Clone, PartialEq, Eq, Hash, Debug, Default)] pub(crate) struct Generics { pub(crate) params: ThinVec, pub(crate) where_predicates: ThinVec, @@ -2253,6 +2253,7 @@ pub(crate) struct Static { #[derive(Clone, PartialEq, Eq, Hash, Debug)] pub(crate) struct Constant { pub(crate) type_: Type, + pub(crate) generics: Box, pub(crate) kind: ConstantKind, } @@ -2502,7 +2503,8 @@ mod size_asserts { static_assert_size!(GenericParamDef, 56); static_assert_size!(Generics, 16); static_assert_size!(Item, 56); - static_assert_size!(ItemKind, 64); + // FIXME(generic_consts): Further reduce the size. + static_assert_size!(ItemKind, 72); static_assert_size!(PathSegment, 40); static_assert_size!(Type, 32); // tidy-alphabetical-end diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index f923f90545126..6c9010e2cefed 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -748,20 +748,22 @@ fn assoc_href_attr(it: &clean::Item, link: AssocItemLink<'_>, cx: &Context<'_>) fn assoc_const( w: &mut Buffer, it: &clean::Item, + generics: &clean::Generics, ty: &clean::Type, default: Option<&clean::ConstantKind>, link: AssocItemLink<'_>, - extra: &str, + indent: usize, cx: &Context<'_>, ) { let tcx = cx.tcx(); write!( w, - "{extra}{vis}const {name}: {ty}", - extra = extra, + "{indent}{vis}const {name}{generics}: {ty}", + indent = " ".repeat(indent), vis = visibility_print_with_space(it.visibility(tcx), it.item_id, cx), href = assoc_href_attr(it, link, cx), name = it.name.as_ref().unwrap(), + generics = generics.print(cx), ty = ty.print(cx), ); if let Some(default) = default { @@ -774,6 +776,7 @@ fn assoc_const( // Find a way to print constants here without all that jazz. write!(w, "{}", Escape(&default.value(tcx).unwrap_or_else(|| default.expr(tcx)))); } + write!(w, "{}", print_where_clause(generics, cx, indent, Ending::NoNewline)); } fn assoc_type( @@ -986,19 +989,22 @@ fn render_assoc_item( clean::MethodItem(m, _) => { assoc_method(w, item, &m.generics, &m.decl, link, parent, cx, render_mode) } - kind @ (clean::TyAssocConstItem(ty) | clean::AssocConstItem(ty, _)) => assoc_const( - w, - item, - ty, - match kind { - clean::TyAssocConstItem(_) => None, - clean::AssocConstItem(_, default) => Some(default), - _ => unreachable!(), - }, - link, - if parent == ItemType::Trait { " " } else { "" }, - cx, - ), + kind @ (clean::TyAssocConstItem(generics, ty) | clean::AssocConstItem(generics, ty, _)) => { + assoc_const( + w, + item, + generics, + ty, + match kind { + clean::TyAssocConstItem(..) => None, + clean::AssocConstItem(.., default) => Some(default), + _ => unreachable!(), + }, + link, + if parent == ItemType::Trait { 4 } else { 0 }, + cx, + ) + } clean::TyAssocTypeItem(ref generics, ref bounds) => assoc_type( w, item, @@ -1565,7 +1571,8 @@ fn render_impl( w.write_str(""); } } - kind @ (clean::TyAssocConstItem(ty) | clean::AssocConstItem(ty, _)) => { + kind @ (clean::TyAssocConstItem(generics, ty) + | clean::AssocConstItem(generics, ty, _)) => { let source_id = format!("{}.{}", item_type, name); let id = cx.derive_id(source_id.clone()); write!(w, "
", id, item_type, in_trait_class); @@ -1578,14 +1585,15 @@ fn render_impl( assoc_const( w, item, + generics, ty, match kind { - clean::TyAssocConstItem(_) => None, - clean::AssocConstItem(_, default) => Some(default), + clean::TyAssocConstItem(..) => None, + clean::AssocConstItem(.., default) => Some(default), _ => unreachable!(), }, link.anchor(if trait_.is_some() { &source_id } else { &id }), - "", + 0, cx, ); w.write_str(""); diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 383e3c170881a..e363e75f56561 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -1543,10 +1543,12 @@ fn item_constant(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, c: &cle write!( w, - "{vis}const {name}: {typ}", + "{vis}const {name}{generics}: {typ}{where_clause}", vis = visibility_print_with_space(it.visibility(tcx), it.item_id, cx), name = it.name.unwrap(), + generics = c.generics.print(cx), typ = c.type_.print(cx), + where_clause = print_where_clause(&c.generics, cx, 0, Ending::NoNewline), ); // FIXME: The code below now prints diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index 91cd55b1113ab..73a0f146ba72a 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -321,8 +321,12 @@ fn from_clean_item(item: clean::Item, tcx: TyCtxt<'_>) -> ItemEnum { impls: Vec::new(), // Added in JsonRenderer::item }) } - TyAssocConstItem(ty) => ItemEnum::AssocConst { type_: ty.into_tcx(tcx), default: None }, - AssocConstItem(ty, default) => { + // FIXME(generic_consts): Add support. + TyAssocConstItem(_generics, ty) => { + ItemEnum::AssocConst { type_: ty.into_tcx(tcx), default: None } + } + // FIXME(generic_consts): Add support. + AssocConstItem(_generics, ty, default) => { ItemEnum::AssocConst { type_: ty.into_tcx(tcx), default: Some(default.expr(tcx)) } } TyAssocTypeItem(g, b) => ItemEnum::AssocType { diff --git a/src/tools/build_helper/Cargo.toml b/src/tools/build_helper/Cargo.toml index 99f6fea2ecf99..66894e1abc40e 100644 --- a/src/tools/build_helper/Cargo.toml +++ b/src/tools/build_helper/Cargo.toml @@ -6,3 +6,5 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +serde = "1" +serde_derive = "1" diff --git a/src/tools/build_helper/src/lib.rs b/src/tools/build_helper/src/lib.rs index 3fa970373b3fb..575f3677155e5 100644 --- a/src/tools/build_helper/src/lib.rs +++ b/src/tools/build_helper/src/lib.rs @@ -1,3 +1,4 @@ pub mod ci; pub mod git; +pub mod metrics; pub mod util; diff --git a/src/tools/build_helper/src/metrics.rs b/src/tools/build_helper/src/metrics.rs new file mode 100644 index 0000000000000..2d0c66a8f3339 --- /dev/null +++ b/src/tools/build_helper/src/metrics.rs @@ -0,0 +1,92 @@ +use serde_derive::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +pub struct JsonRoot { + #[serde(default)] // For version 0 the field was not present. + pub format_version: usize, + pub system_stats: JsonInvocationSystemStats, + pub invocations: Vec, +} + +#[derive(Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +pub struct JsonInvocation { + // Unix timestamp in seconds + // + // This is necessary to easily correlate this invocation with logs or other data. + pub start_time: u64, + pub duration_including_children_sec: f64, + pub children: Vec, +} + +#[derive(Serialize, Deserialize)] +#[serde(tag = "kind", rename_all = "snake_case")] +pub enum JsonNode { + RustbuildStep { + #[serde(rename = "type")] + type_: String, + debug_repr: String, + + duration_excluding_children_sec: f64, + system_stats: JsonStepSystemStats, + + children: Vec, + }, + TestSuite(TestSuite), +} + +#[derive(Serialize, Deserialize)] +pub struct TestSuite { + pub metadata: TestSuiteMetadata, + pub tests: Vec, +} + +#[derive(Serialize, Deserialize)] +#[serde(tag = "kind", rename_all = "snake_case")] +pub enum TestSuiteMetadata { + CargoPackage { + crates: Vec, + target: String, + host: String, + stage: u32, + }, + Compiletest { + suite: String, + mode: String, + compare_mode: Option, + target: String, + host: String, + stage: u32, + }, +} + +#[derive(Serialize, Deserialize)] +pub struct Test { + pub name: String, + #[serde(flatten)] + pub outcome: TestOutcome, +} + +#[derive(Serialize, Deserialize)] +#[serde(tag = "outcome", rename_all = "snake_case")] +pub enum TestOutcome { + Passed, + Failed, + Ignored { ignore_reason: Option }, +} + +#[derive(Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +pub struct JsonInvocationSystemStats { + pub cpu_threads_count: usize, + pub cpu_model: String, + + pub memory_total_bytes: u64, +} + +#[derive(Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +pub struct JsonStepSystemStats { + pub cpu_utilization_percent: f64, +} diff --git a/src/tools/cargo b/src/tools/cargo index 5b377cece0e0d..45782b6b8afd1 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 5b377cece0e0dd0af686cf53ce4637d5d85c2a10 +Subproject commit 45782b6b8afd1da042d45c2daeec9c0744f72cc7 diff --git a/src/tools/clippy/clippy_lints/src/derivable_impls.rs b/src/tools/clippy/clippy_lints/src/derivable_impls.rs index ec0ca50cfec70..020ffe7f8fa22 100644 --- a/src/tools/clippy/clippy_lints/src/derivable_impls.rs +++ b/src/tools/clippy/clippy_lints/src/derivable_impls.rs @@ -9,7 +9,7 @@ use rustc_hir::{ Body, Expr, ExprKind, GenericArg, Impl, ImplItemKind, Item, ItemKind, Node, PathSegment, QPath, TyKind, }; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty::adjustment::{Adjust, PointerCast}; +use rustc_middle::ty::adjustment::{Adjust, PointerCoercion}; use rustc_middle::ty::{self, Adt, AdtDef, SubstsRef, Ty, TypeckResults}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::sym; @@ -116,7 +116,7 @@ fn check_struct<'tcx>( let is_default_without_adjusts = |expr| { is_default_equivalent(cx, expr) && typeck_results.expr_adjustments(expr).iter().all(|adj| { - !matches!(adj.kind, Adjust::Pointer(PointerCast::Unsize) + !matches!(adj.kind, Adjust::Pointer(PointerCoercion::Unsize) if contains_trait_object(adj.target)) }) }; diff --git a/src/tools/clippy/clippy_lints/src/incorrect_impls.rs b/src/tools/clippy/clippy_lints/src/incorrect_impls.rs index 13cc0b23ba33d..7b95116ee4e36 100644 --- a/src/tools/clippy/clippy_lints/src/incorrect_impls.rs +++ b/src/tools/clippy/clippy_lints/src/incorrect_impls.rs @@ -82,7 +82,7 @@ impl LateLintPass<'_> for IncorrectImpls { cx, hir_ty_to_ty(cx.tcx, imp.self_ty), copy_def_id, - trait_impl.substs, + &[], ) { if impl_item.ident.name == sym::clone { diff --git a/src/tools/clippy/clippy_lints/src/large_const_arrays.rs b/src/tools/clippy/clippy_lints/src/large_const_arrays.rs index 4dc750c03b488..e80804aff22eb 100644 --- a/src/tools/clippy/clippy_lints/src/large_const_arrays.rs +++ b/src/tools/clippy/clippy_lints/src/large_const_arrays.rs @@ -50,7 +50,11 @@ impl<'tcx> LateLintPass<'tcx> for LargeConstArrays { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { if_chain! { if !item.span.from_expansion(); - if let ItemKind::Const(hir_ty, _) = &item.kind; + if let ItemKind::Const(hir_ty, generics, _) = &item.kind; + // Since static items may not have generics, skip generic consts. + // FIXME(generic_consts): I don't think checking `generics.hwcp` suffices as it doesn't + // account for empty where-clauses that only consist of keyword `where` (IIRC). + if generics.params.is_empty() && !generics.has_where_clause_predicates; let ty = hir_ty_to_ty(cx.tcx, hir_ty); if let ty::Array(element_type, cst) = ty.kind(); if let ConstKind::Value(ty::ValTree::Leaf(element_count)) = cst.kind(); diff --git a/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs b/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs index cb446567506af..1fafbbabc847a 100644 --- a/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs @@ -284,6 +284,8 @@ impl<'a, 'tcx> VarVisitor<'a, 'tcx> { if index_used_directly { self.indexed_directly.insert( seqvar.segments[0].ident.name, + // FIXME(generic_consts): Do we need to subst anything here or has + // that already been taken care of? (None, self.cx.typeck_results().node_type(seqexpr.hir_id)), ); } else { diff --git a/src/tools/clippy/clippy_lints/src/non_copy_const.rs b/src/tools/clippy/clippy_lints/src/non_copy_const.rs index 75f1e95276a69..ce9deb1cd1b35 100644 --- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs +++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs @@ -286,7 +286,9 @@ declare_lint_pass!(NonCopyConst => [DECLARE_INTERIOR_MUTABLE_CONST, BORROW_INTER impl<'tcx> LateLintPass<'tcx> for NonCopyConst { fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx Item<'_>) { - if let ItemKind::Const(hir_ty, body_id) = it.kind { + if let ItemKind::Const(hir_ty, _generics, body_id) = it.kind { + // FIXME(generic_consts): Not sure if we need to handle generics explicitly here like + // replacing params with placeholders or can `is_unfrozen` handle params on its own? let ty = hir_ty_to_ty(cx.tcx, hir_ty); if !ignored_macro(cx, it) && is_unfrozen(cx, ty) && is_value_unfrozen_poly(cx, body_id, ty) { lint(cx, Source::Item { item: it.span }); @@ -295,6 +297,7 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst { } fn check_trait_item(&mut self, cx: &LateContext<'tcx>, trait_item: &'tcx TraitItem<'_>) { + // FIXME(generic_consts): Not sure if we need to handle generics explicitly here. if let TraitItemKind::Const(hir_ty, body_id_opt) = &trait_item.kind { let ty = hir_ty_to_ty(cx.tcx, hir_ty); @@ -322,6 +325,7 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst { } fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx ImplItem<'_>) { + // FIXME(generic_consts): Not sure if we need to handle generics explicitly here if let ImplItemKind::Const(hir_ty, body_id) = &impl_item.kind { let item_def_id = cx.tcx.hir().get_parent_item(impl_item.hir_id()).def_id; let item = cx.tcx.hir().expect_item(item_def_id); diff --git a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs index 0d78c3048ba12..eab725de17f68 100644 --- a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs +++ b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs @@ -14,7 +14,7 @@ use rustc_hir as hir; use rustc_hir::intravisit::FnKind; use rustc_hir::{BindingAnnotation, Body, FnDecl, Impl, ItemKind, MutTy, Mutability, Node, PatKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty::adjustment::{Adjust, PointerCast}; +use rustc_middle::ty::adjustment::{Adjust, PointerCoercion}; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, RegionKind}; use rustc_session::{declare_tool_lint, impl_lint_pass}; @@ -195,7 +195,7 @@ impl<'tcx> PassByRefOrValue { .adjustments() .items() .flat_map(|(_, a)| a) - .any(|a| matches!(a.kind, Adjust::Pointer(PointerCast::UnsafeFnPointer))) + .any(|a| matches!(a.kind, Adjust::Pointer(PointerCoercion::UnsafeFnPointer))) { continue; } diff --git a/src/tools/clippy/clippy_lints/src/types/mod.rs b/src/tools/clippy/clippy_lints/src/types/mod.rs index 3c873a5901d42..23dd6701c1567 100644 --- a/src/tools/clippy/clippy_lints/src/types/mod.rs +++ b/src/tools/clippy/clippy_lints/src/types/mod.rs @@ -349,7 +349,9 @@ impl<'tcx> LateLintPass<'tcx> for Types { let is_exported = cx.effective_visibilities.is_exported(item.owner_id.def_id); match item.kind { - ItemKind::Static(ty, _, _) | ItemKind::Const(ty, _) => self.check_ty( + // FIXME(generic_consts): Not sure if we need to handle generics explicitly here like + // replacing params with placeholders or can relate routines handle params on their own? + ItemKind::Static(ty, _, _) | ItemKind::Const(ty, _, _) => self.check_ty( cx, ty, CheckTyContext { @@ -364,6 +366,8 @@ impl<'tcx> LateLintPass<'tcx> for Types { fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>) { match item.kind { + // FIXME(generic_consts): Not sure if we need to handle generics explicitly here like + // replacing params with placeholders or can relate routines handle params on their own? ImplItemKind::Const(ty, _) => { let is_in_trait_impl = if let Some(hir::Node::Item(item)) = cx .tcx @@ -413,6 +417,8 @@ impl<'tcx> LateLintPass<'tcx> for Types { }; match item.kind { + // FIXME(generic_consts): Not sure if we need to handle generics explicitly here like + // replacing params with placeholders or can relate routines handle params on their own? TraitItemKind::Const(ty, _) | TraitItemKind::Type(_, Some(ty)) => { self.check_ty(cx, ty, context); }, diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs index dced9fcf9abd3..d0c5adf317e28 100644 --- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs +++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs @@ -77,6 +77,7 @@ impl<'tcx> LateLintPass<'tcx> for InterningDefinedSymbol { for def_id in def_path_def_ids(cx, module) { for item in cx.tcx.module_children(def_id) { if_chain! { + // FIXME(generic_consts): Shouldn't we subst here now? if let Res::Def(DefKind::Const, item_def_id) = item.res; let ty = cx.tcx.type_of(item_def_id).subst_identity(); if match_type(cx, ty, &paths::SYMBOL); diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs index 9afe02c1e47da..c7a5822c9c556 100644 --- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs +++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs @@ -34,6 +34,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidPaths { if_chain! { if mod_name.as_str() == "paths"; if let hir::ItemKind::Const(ty, body_id) = item.kind; + // FIXME(generic_consts): Is this compatible with generic consts? let ty = hir_ty_to_ty(cx.tcx, ty); if let ty::Array(el_ty, _) = &ty.kind(); if let ty::Ref(_, el_ty, _) = &el_ty.kind(); diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs index 00842376628cc..238ad394113ab 100644 --- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs +++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs @@ -231,6 +231,7 @@ fn path_to_matched_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option match cx.tcx.const_eval_poly(def_id).ok()? { ConstValue::ByRef { alloc, offset } if offset.bytes() == 0 => { read_mir_alloc_def_path(cx, alloc.inner(), cx.tcx.type_of(def_id).subst_identity()) diff --git a/src/tools/clippy/clippy_utils/src/ast_utils.rs b/src/tools/clippy/clippy_utils/src/ast_utils.rs index 8cc01f1ef9740..7e42924603a41 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils.rs @@ -301,15 +301,17 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { ( Const(box ast::ConstItem { defaultness: ld, + generics: lg, ty: lt, expr: le, }), Const(box ast::ConstItem { defaultness: rd, + generics: rg, ty: rt, expr: re, }), - ) => eq_defaultness(*ld, *rd) && eq_ty(lt, rt) && eq_expr_opt(le, re), + ) => eq_defaultness(*ld, *rd) && eq_generics(lg, rg) && eq_ty(lt, rt) && eq_expr_opt(le, re), ( Fn(box ast::Fn { defaultness: ld, @@ -476,15 +478,17 @@ pub fn eq_assoc_item_kind(l: &AssocItemKind, r: &AssocItemKind) -> bool { ( Const(box ast::ConstItem { defaultness: ld, + generics: lg, ty: lt, expr: le, }), Const(box ast::ConstItem { defaultness: rd, + generics: rg, ty: rt, expr: re, }), - ) => eq_defaultness(*ld, *rd) && eq_ty(lt, rt) && eq_expr_opt(le, re), + ) => eq_defaultness(*ld, *rd) && eq_generics(lg, rg) && eq_ty(lt, rt) && eq_expr_opt(le, re), ( Fn(box ast::Fn { defaultness: ld, diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs index d1cfdc49658d7..d253cf4fa05b0 100644 --- a/src/tools/clippy/clippy_utils/src/consts.rs +++ b/src/tools/clippy/clippy_utils/src/consts.rs @@ -463,7 +463,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { // Check if this constant is based on `cfg!(..)`, // which is NOT constant for our purposes. if let Some(node) = self.lcx.tcx.hir().get_if_local(def_id) - && let Node::Item(Item { kind: ItemKind::Const(_, body_id), .. }) = node + && let Node::Item(Item { kind: ItemKind::Const(.., body_id), .. }) = node && let Node::Expr(Expr { kind: ExprKind::Lit(_), span, .. }) = self.lcx .tcx .hir() @@ -473,6 +473,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { return None; } + // FIXME(generic_consts): Does this already account for generic consts? let substs = self.typeck_results.node_substs(id); let substs = if self.substs.is_empty() { substs diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index 727b59f1f432a..2f9acfa9be685 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -2385,7 +2385,7 @@ fn with_test_item_names(tcx: TyCtxt<'_>, module: LocalDefId, f: impl Fn(&[Symbol for id in tcx.hir().module_items(module) { if matches!(tcx.def_kind(id.owner_id), DefKind::Const) && let item = tcx.hir().item(id) - && let ItemKind::Const(ty, _body) = item.kind { + && let ItemKind::Const(ty, _generics, _body) = item.kind { if let TyKind::Path(QPath::Resolved(_, path)) = ty.kind { // We could also check for the type name `test::TestDescAndFn` if let Res::Def(DefKind::Struct, _) = path.res { diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs index c9938caefb067..fbf4ab2722e60 100644 --- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs +++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs @@ -16,7 +16,7 @@ use rustc_middle::mir::{ }; use rustc_middle::traits::{ImplSource, ObligationCause}; use rustc_middle::ty::subst::GenericArgKind; -use rustc_middle::ty::{self, adjustment::PointerCast, Ty, TyCtxt}; +use rustc_middle::ty::{self, adjustment::PointerCoercion, Ty, TyCtxt}; use rustc_middle::ty::{BoundConstness, TraitRef}; use rustc_semver::RustcVersion; use rustc_span::symbol::sym; @@ -119,18 +119,18 @@ fn check_rvalue<'tcx>( | CastKind::FloatToFloat | CastKind::FnPtrToPtr | CastKind::PtrToPtr - | CastKind::Pointer(PointerCast::MutToConstPointer | PointerCast::ArrayToPointer), + | CastKind::PointerCoercion(PointerCoercion::MutToConstPointer | PointerCoercion::ArrayToPointer), operand, _, ) => check_operand(tcx, operand, span, body), Rvalue::Cast( - CastKind::Pointer( - PointerCast::UnsafeFnPointer | PointerCast::ClosureFnPointer(_) | PointerCast::ReifyFnPointer, + CastKind::PointerCoercion( + PointerCoercion::UnsafeFnPointer | PointerCoercion::ClosureFnPointer(_) | PointerCoercion::ReifyFnPointer, ), _, _, ) => Err((span, "function pointer casts are not allowed in const fn".into())), - Rvalue::Cast(CastKind::Pointer(PointerCast::Unsize), op, cast_ty) => { + Rvalue::Cast(CastKind::PointerCoercion(PointerCoercion::Unsize), op, cast_ty) => { let pointee_ty = if let Some(deref_ty) = cast_ty.builtin_deref(true) { deref_ty.ty } else { diff --git a/src/tools/clippy/tests/ui/needless_raw_string.fixed b/src/tools/clippy/tests/ui/needless_raw_string.fixed index 6438e46977bbd..b36912efbb2d4 100644 --- a/src/tools/clippy/tests/ui/needless_raw_string.fixed +++ b/src/tools/clippy/tests/ui/needless_raw_string.fixed @@ -10,7 +10,8 @@ fn main() { b"aaa"; br#""aaa""#; br#"\s"#; - c"aaa"; - cr#""aaa""#; - cr#"\s"#; + // currently disabled: https://github.com/rust-lang/rust/issues/113333 + // cr#"aaa"#; + // cr#""aaa""#; + // cr#"\s"#; } diff --git a/src/tools/clippy/tests/ui/needless_raw_string.rs b/src/tools/clippy/tests/ui/needless_raw_string.rs index f7ddc68265edf..8f48e7dab2a6e 100644 --- a/src/tools/clippy/tests/ui/needless_raw_string.rs +++ b/src/tools/clippy/tests/ui/needless_raw_string.rs @@ -10,7 +10,8 @@ fn main() { br#"aaa"#; br#""aaa""#; br#"\s"#; - cr#"aaa"#; - cr#""aaa""#; - cr#"\s"#; + // currently disabled: https://github.com/rust-lang/rust/issues/113333 + // cr#"aaa"#; + // cr#""aaa""#; + // cr#"\s"#; } diff --git a/src/tools/clippy/tests/ui/needless_raw_string.stderr b/src/tools/clippy/tests/ui/needless_raw_string.stderr index 0179978b7b08c..cfb07b647d7c6 100644 --- a/src/tools/clippy/tests/ui/needless_raw_string.stderr +++ b/src/tools/clippy/tests/ui/needless_raw_string.stderr @@ -12,11 +12,5 @@ error: unnecessary raw string literal LL | br#"aaa"#; | ^^^^^^^^^ help: try: `b"aaa"` -error: unnecessary raw string literal - --> $DIR/needless_raw_string.rs:13:5 - | -LL | cr#"aaa"#; - | ^^^^^^^^^ help: try: `c"aaa"` - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors diff --git a/src/tools/clippy/tests/ui/needless_raw_string_hashes.fixed b/src/tools/clippy/tests/ui/needless_raw_string_hashes.fixed index e4d7d8fb017a9..c8507c7271513 100644 --- a/src/tools/clippy/tests/ui/needless_raw_string_hashes.fixed +++ b/src/tools/clippy/tests/ui/needless_raw_string_hashes.fixed @@ -12,8 +12,9 @@ fn main() { br#"Hello "world"!"#; br####" "### "## "# "####; br###" "aa" "# "## "###; - cr#"aaa"#; - cr#"Hello "world"!"#; - cr####" "### "## "# "####; - cr###" "aa" "# "## "###; + // currently disabled: https://github.com/rust-lang/rust/issues/113333 + // cr#"aaa"#; + // cr##"Hello "world"!"##; + // cr######" "### "## "# "######; + // cr######" "aa" "# "## "######; } diff --git a/src/tools/clippy/tests/ui/needless_raw_string_hashes.rs b/src/tools/clippy/tests/ui/needless_raw_string_hashes.rs index e2d85c52e78cc..912fbde1679db 100644 --- a/src/tools/clippy/tests/ui/needless_raw_string_hashes.rs +++ b/src/tools/clippy/tests/ui/needless_raw_string_hashes.rs @@ -12,8 +12,9 @@ fn main() { br##"Hello "world"!"##; br######" "### "## "# "######; br######" "aa" "# "## "######; - cr#"aaa"#; - cr##"Hello "world"!"##; - cr######" "### "## "# "######; - cr######" "aa" "# "## "######; + // currently disabled: https://github.com/rust-lang/rust/issues/113333 + // cr#"aaa"#; + // cr##"Hello "world"!"##; + // cr######" "### "## "# "######; + // cr######" "aa" "# "## "######; } diff --git a/src/tools/clippy/tests/ui/needless_raw_string_hashes.stderr b/src/tools/clippy/tests/ui/needless_raw_string_hashes.stderr index dff47a2d04212..30e6783a38e8b 100644 --- a/src/tools/clippy/tests/ui/needless_raw_string_hashes.stderr +++ b/src/tools/clippy/tests/ui/needless_raw_string_hashes.stderr @@ -36,23 +36,5 @@ error: unnecessary hashes around raw string literal LL | br######" "aa" "# "## "######; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `br###" "aa" "# "## "###` -error: unnecessary hashes around raw string literal - --> $DIR/needless_raw_string_hashes.rs:16:5 - | -LL | cr##"Hello "world"!"##; - | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `cr#"Hello "world"!"#` - -error: unnecessary hashes around raw string literal - --> $DIR/needless_raw_string_hashes.rs:17:5 - | -LL | cr######" "### "## "# "######; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cr####" "### "## "# "####` - -error: unnecessary hashes around raw string literal - --> $DIR/needless_raw_string_hashes.rs:18:5 - | -LL | cr######" "aa" "# "## "######; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cr###" "aa" "# "## "###` - -error: aborting due to 9 previous errors +error: aborting due to 6 previous errors diff --git a/src/tools/clippy/tests/ui/to_string_in_format_args_incremental.rs b/src/tools/clippy/tests/ui/to_string_in_format_args_incremental.rs deleted file mode 100644 index 67115f7c5a7b7..0000000000000 --- a/src/tools/clippy/tests/ui/to_string_in_format_args_incremental.rs +++ /dev/null @@ -1,9 +0,0 @@ -//@run-rustfix -//@compile-flags: -C incremental=target/debug/test/incr - -// see https://github.com/rust-lang/rust-clippy/issues/10969 - -fn main() { - let s = "Hello, world!"; - println!("{}", s.to_string()); -} diff --git a/src/tools/clippy/tests/ui/to_string_in_format_args_incremental.stderr b/src/tools/clippy/tests/ui/to_string_in_format_args_incremental.stderr deleted file mode 100644 index a992c54291495..0000000000000 --- a/src/tools/clippy/tests/ui/to_string_in_format_args_incremental.stderr +++ /dev/null @@ -1,10 +0,0 @@ -error: `to_string` applied to a type that implements `Display` in `println!` args - --> $DIR/to_string_in_format_args_incremental.rs:8:21 - | -LL | println!("{}", s.to_string()); - | ^^^^^^^^^^^^ help: remove this - | - = note: `-D clippy::to-string-in-format-args` implied by `-D warnings` - -error: aborting due to previous error - diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index c835962ad12fd..ad10c3e07cef4 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -588,21 +588,22 @@ impl TestProps { } } +/// Extract a `(Option, directive)` directive from a line if comment is present. pub fn line_directive<'line>( comment: &str, ln: &'line str, ) -> Option<(Option<&'line str>, &'line str)> { + let ln = ln.trim_start(); if ln.starts_with(comment) { let ln = ln[comment.len()..].trim_start(); if ln.starts_with('[') { // A comment like `//[foo]` is specific to revision `foo` - if let Some(close_brace) = ln.find(']') { - let lncfg = &ln[1..close_brace]; + let Some(close_brace) = ln.find(']') else { + panic!("malformed condition directive: expected `{}[foo]`, found `{}`", comment, ln); + }; - Some((Some(lncfg), ln[(close_brace + 1)..].trim_start())) - } else { - panic!("malformed condition directive: expected `{}[foo]`, found `{}`", comment, ln) - } + let lncfg = &ln[1..close_brace]; + Some((Some(lncfg), ln[(close_brace + 1)..].trim_start())) } else { Some((None, ln)) } diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 672779325ae35..ac19fe078f09e 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -41,7 +41,7 @@ use crate::extract_gdb_version; use crate::is_android_gdb_target; mod debugger; -use debugger::{check_debugger_output, DebuggerCommands}; +use debugger::DebuggerCommands; #[cfg(test)] mod tests; @@ -997,16 +997,13 @@ impl<'test> TestCx<'test> { }; // Parse debugger commands etc from test files - let DebuggerCommands { commands, check_lines, breakpoint_lines, .. } = - match DebuggerCommands::parse_from( - &self.testpaths.file, - self.config, - prefixes, - self.revision, - ) { - Ok(cmds) => cmds, - Err(e) => self.fatal(&e), - }; + let dbg_cmds = DebuggerCommands::parse_from( + &self.testpaths.file, + self.config, + prefixes, + self.revision, + ) + .unwrap_or_else(|e| self.fatal(&e)); // https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/debugger-commands let mut script_str = String::with_capacity(2048); @@ -1023,12 +1020,12 @@ impl<'test> TestCx<'test> { // Set breakpoints on every line that contains the string "#break" let source_file_name = self.testpaths.file.file_name().unwrap().to_string_lossy(); - for line in &breakpoint_lines { + for line in &dbg_cmds.breakpoint_lines { script_str.push_str(&format!("bp `{}:{}`\n", source_file_name, line)); } // Append the other `cdb-command:`s - for line in &commands { + for line in &dbg_cmds.commands { script_str.push_str(line); script_str.push_str("\n"); } @@ -1058,7 +1055,7 @@ impl<'test> TestCx<'test> { self.fatal_proc_rec("Error while running CDB", &debugger_run_result); } - if let Err(e) = check_debugger_output(&debugger_run_result, &check_lines) { + if let Err(e) = dbg_cmds.check_output(&debugger_run_result) { self.fatal_proc_rec(&e, &debugger_run_result); } } @@ -1088,17 +1085,14 @@ impl<'test> TestCx<'test> { PREFIXES }; - let DebuggerCommands { commands, check_lines, breakpoint_lines } = - match DebuggerCommands::parse_from( - &self.testpaths.file, - self.config, - prefixes, - self.revision, - ) { - Ok(cmds) => cmds, - Err(e) => self.fatal(&e), - }; - let mut cmds = commands.join("\n"); + let dbg_cmds = DebuggerCommands::parse_from( + &self.testpaths.file, + self.config, + prefixes, + self.revision, + ) + .unwrap_or_else(|e| self.fatal(&e)); + let mut cmds = dbg_cmds.commands.join("\n"); // compile test file (it should have 'compile-flags:-g' in the header) let should_run = self.run_if_enabled(); @@ -1132,13 +1126,14 @@ impl<'test> TestCx<'test> { ./{}/stage2/lib/rustlib/{}/lib/\n", self.config.host, self.config.target )); - for line in &breakpoint_lines { + for line in &dbg_cmds.breakpoint_lines { script_str.push_str( - &format!( + format!( "break {:?}:{}\n", self.testpaths.file.file_name().unwrap().to_string_lossy(), *line - )[..], + ) + .as_str(), ); } script_str.push_str(&cmds); @@ -1279,7 +1274,7 @@ impl<'test> TestCx<'test> { } // Add line breakpoints - for line in &breakpoint_lines { + for line in &dbg_cmds.breakpoint_lines { script_str.push_str(&format!( "break '{}':{}\n", self.testpaths.file.file_name().unwrap().to_string_lossy(), @@ -1315,7 +1310,7 @@ impl<'test> TestCx<'test> { self.fatal_proc_rec("gdb failed to execute", &debugger_run_result); } - if let Err(e) = check_debugger_output(&debugger_run_result, &check_lines) { + if let Err(e) = dbg_cmds.check_output(&debugger_run_result) { self.fatal_proc_rec(&e, &debugger_run_result); } } @@ -1372,16 +1367,13 @@ impl<'test> TestCx<'test> { }; // Parse debugger commands etc from test files - let DebuggerCommands { commands, check_lines, breakpoint_lines, .. } = - match DebuggerCommands::parse_from( - &self.testpaths.file, - self.config, - prefixes, - self.revision, - ) { - Ok(cmds) => cmds, - Err(e) => self.fatal(&e), - }; + let dbg_cmds = DebuggerCommands::parse_from( + &self.testpaths.file, + self.config, + prefixes, + self.revision, + ) + .unwrap_or_else(|e| self.fatal(&e)); // Write debugger script: // We don't want to hang when calling `quit` while the process is still running @@ -1430,7 +1422,7 @@ impl<'test> TestCx<'test> { // Set breakpoints on every line that contains the string "#break" let source_file_name = self.testpaths.file.file_name().unwrap().to_string_lossy(); - for line in &breakpoint_lines { + for line in &dbg_cmds.breakpoint_lines { script_str.push_str(&format!( "breakpoint set --file '{}' --line {}\n", source_file_name, line @@ -1438,7 +1430,7 @@ impl<'test> TestCx<'test> { } // Append the other commands - for line in &commands { + for line in &dbg_cmds.commands { script_str.push_str(line); script_str.push_str("\n"); } @@ -1458,7 +1450,7 @@ impl<'test> TestCx<'test> { self.fatal_proc_rec("Error while running LLDB", &debugger_run_result); } - if let Err(e) = check_debugger_output(&debugger_run_result, &check_lines) { + if let Err(e) = dbg_cmds.check_output(&debugger_run_result) { self.fatal_proc_rec(&e, &debugger_run_result); } } diff --git a/src/tools/compiletest/src/runtest/debugger.rs b/src/tools/compiletest/src/runtest/debugger.rs index 379ff0bab408a..eebe5f3580b30 100644 --- a/src/tools/compiletest/src/runtest/debugger.rs +++ b/src/tools/compiletest/src/runtest/debugger.rs @@ -2,18 +2,25 @@ use crate::common::Config; use crate::header::line_directive; use crate::runtest::ProcRes; +use std::fmt::Write; use std::fs::File; use std::io::{BufRead, BufReader}; -use std::path::Path; +use std::path::{Path, PathBuf}; +/// Representation of information to invoke a debugger and check its output pub(super) struct DebuggerCommands { + /// Commands for the debuuger pub commands: Vec, - pub check_lines: Vec, + /// Lines to insert breakpoints at pub breakpoint_lines: Vec, + /// Contains the source line number to check and the line itself + check_lines: Vec<(usize, String)>, + /// Source file name + file: PathBuf, } impl DebuggerCommands { - pub(super) fn parse_from( + pub fn parse_from( file: &Path, config: &Config, debugger_prefixes: &[&str], @@ -21,7 +28,7 @@ impl DebuggerCommands { ) -> Result { let directives = debugger_prefixes .iter() - .map(|prefix| (format!("{}-command", prefix), format!("{}-check", prefix))) + .map(|prefix| (format!("{prefix}-command"), format!("{prefix}-check"))) .collect::>(); let mut breakpoint_lines = vec![]; @@ -29,63 +36,88 @@ impl DebuggerCommands { let mut check_lines = vec![]; let mut counter = 0; let reader = BufReader::new(File::open(file).unwrap()); - for line in reader.lines() { + for (line_no, line) in reader.lines().enumerate() { counter += 1; - match line { - Ok(line) => { - let (lnrev, line) = line_directive("//", &line).unwrap_or((None, &line)); - - // Skip any revision specific directive that doesn't match the current - // revision being tested - if lnrev.is_some() && lnrev != rev { - continue; - } - - if line.contains("#break") { - breakpoint_lines.push(counter); - } - - for &(ref command_directive, ref check_directive) in &directives { - config - .parse_name_value_directive(&line, command_directive) - .map(|cmd| commands.push(cmd)); - - config - .parse_name_value_directive(&line, check_directive) - .map(|cmd| check_lines.push(cmd)); - } - } - Err(e) => return Err(format!("Error while parsing debugger commands: {}", e)), + let line = line.map_err(|e| format!("Error while parsing debugger commands: {}", e))?; + let (lnrev, line) = line_directive("//", &line).unwrap_or((None, &line)); + + // Skip any revision specific directive that doesn't match the current + // revision being tested + if lnrev.is_some() && lnrev != rev { + continue; + } + + if line.contains("#break") { + breakpoint_lines.push(counter); + } + + for &(ref command_directive, ref check_directive) in &directives { + config + .parse_name_value_directive(&line, command_directive) + .map(|cmd| commands.push(cmd)); + + config + .parse_name_value_directive(&line, check_directive) + .map(|cmd| check_lines.push((line_no, cmd))); } } - Ok(Self { commands, check_lines, breakpoint_lines }) + Ok(Self { commands, breakpoint_lines, check_lines, file: file.to_owned() }) } -} -pub(super) fn check_debugger_output( - debugger_run_result: &ProcRes, - check_lines: &[String], -) -> Result<(), String> { - let num_check_lines = check_lines.len(); - - let mut check_line_index = 0; - for line in debugger_run_result.stdout.lines() { - if check_line_index >= num_check_lines { - break; + /// Given debugger output and lines to check, ensure that every line is + /// contained in the debugger output. The check lines need to be found in + /// order, but there can be extra lines between. + pub fn check_output(&self, debugger_run_result: &ProcRes) -> Result<(), String> { + // (src_lineno, ck_line) that we did find + let mut found = vec![]; + // (src_lineno, ck_line) that we couldn't find + let mut missing = vec![]; + // We can find our any current match anywhere after our last match + let mut last_idx = 0; + let dbg_lines: Vec<&str> = debugger_run_result.stdout.lines().collect(); + + for (src_lineno, ck_line) in &self.check_lines { + if let Some(offset) = dbg_lines + .iter() + .skip(last_idx) + .position(|out_line| check_single_line(out_line, &ck_line)) + { + last_idx += offset; + found.push((src_lineno, dbg_lines[last_idx])); + } else { + missing.push((src_lineno, ck_line)); + } } - if check_single_line(line, &(check_lines[check_line_index])[..]) { - check_line_index += 1; + if missing.is_empty() { + Ok(()) + } else { + let fname = self.file.file_name().unwrap().to_string_lossy(); + let mut msg = format!( + "check directive(s) from `{}` not found in debugger output. errors:", + self.file.display() + ); + + for (src_lineno, err_line) in missing { + write!(msg, "\n ({fname}:{num}) `{err_line}`", num = src_lineno + 1).unwrap(); + } + + if !found.is_empty() { + let init = "\nthe following subset of check directive(s) was found successfully:"; + msg.push_str(init); + for (src_lineno, found_line) in found { + write!(msg, "\n ({fname}:{num}) `{found_line}`", num = src_lineno + 1) + .unwrap(); + } + } + + Err(msg) } } - if check_line_index != num_check_lines && num_check_lines > 0 { - Err(format!("line not found in debugger output: {}", check_lines[check_line_index])) - } else { - Ok(()) - } } +/// Check that the pattern in `check_line` applies to `line`. Returns `true` if they do match. fn check_single_line(line: &str, check_line: &str) -> bool { // Allow check lines to leave parts unspecified (e.g., uninitialized // bits in the wrong case of an enum) with the notation "[...]". @@ -101,21 +133,19 @@ fn check_single_line(line: &str, check_line: &str) -> bool { } let (mut rest, first_fragment) = if can_start_anywhere { - match line.find(check_fragments[0]) { - Some(pos) => (&line[pos + check_fragments[0].len()..], 1), - None => return false, - } + let Some(pos) = line.find(check_fragments[0]) else { + return false; + }; + (&line[pos + check_fragments[0].len()..], 1) } else { (line, 0) }; for current_fragment in &check_fragments[first_fragment..] { - match rest.find(current_fragment) { - Some(pos) => { - rest = &rest[pos + current_fragment.len()..]; - } - None => return false, - } + let Some(pos) = rest.find(current_fragment) else { + return false; + }; + rest = &rest[pos + current_fragment.len()..]; } if !can_end_anywhere && !rest.is_empty() { false } else { true } diff --git a/src/tools/miri/.github/workflows/ci.yml b/src/tools/miri/.github/workflows/ci.yml index 8068db1cf4f0d..c87b3e4232361 100644 --- a/src/tools/miri/.github/workflows/ci.yml +++ b/src/tools/miri/.github/workflows/ci.yml @@ -15,6 +15,10 @@ on: env: CARGO_UNSTABLE_SPARSE_REGISTRY: 'true' +defaults: + run: + shell: bash + jobs: build: runs-on: ${{ matrix.os }} @@ -59,12 +63,9 @@ jobs: - name: Install rustup-toolchain-install-master if: ${{ steps.cache.outputs.cache-hit != 'true' }} - shell: bash - run: | - cargo install -f rustup-toolchain-install-master + run: cargo install -f rustup-toolchain-install-master - name: Install "master" toolchain - shell: bash run: | if [[ ${{ github.event_name }} == 'schedule' ]]; then echo "Building against latest rustc git version" @@ -79,7 +80,7 @@ jobs: cargo -V - name: Test - run: bash ./ci.sh + run: ./ci.sh style: name: style checks @@ -111,14 +112,10 @@ jobs: - name: Install rustup-toolchain-install-master if: ${{ steps.cache.outputs.cache-hit != 'true' }} - shell: bash - run: | - cargo install -f rustup-toolchain-install-master + run: cargo install -f rustup-toolchain-install-master - name: Install "master" toolchain - shell: bash - run: | - ./miri toolchain + run: ./miri toolchain - name: Show Rust version run: | @@ -138,7 +135,6 @@ jobs: # workflow is successful listening to webhooks only. # # ALL THE PREVIOUS JOBS NEED TO BE ADDED TO THE `needs` SECTION OF THIS JOB! - # (`fmt` is deliberately not listed, we want bors to ignore it.) end-success: name: bors build finished runs-on: ubuntu-latest @@ -166,12 +162,12 @@ jobs: - name: Install zulip-send run: pip3 install zulip - name: Send Zulip notification - shell: bash env: ZULIP_BOT_EMAIL: ${{ secrets.ZULIP_BOT_EMAIL }} ZULIP_API_TOKEN: ${{ secrets.ZULIP_API_TOKEN }} run: | - ~/.local/bin/zulip-send --stream miri --subject "Cron Job Failure (miri, $(date -u +%Y-%m))" \ + ~/.local/bin/zulip-send --user $ZULIP_BOT_EMAIL --api-key $ZULIP_API_TOKEN --site https://rust-lang.zulipchat.com \ + --stream miri --subject "Cron Job Failure (miri, $(date -u +%Y-%m))" \ --message 'Dear @*T-miri*, It would appear that the [Miri cron job build]('"https://github.com/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID"') failed. @@ -183,9 +179,12 @@ jobs: Thanks in advance! Sincerely, - The Miri Cronjobs Bot' \ - --user $ZULIP_BOT_EMAIL --api-key $ZULIP_API_TOKEN --site https://rust-lang.zulipchat.com + The Miri Cronjobs Bot' + # Attempt to auto-sync with rustc + - uses: actions/checkout@v3 + with: + fetch-depth: 256 # get a bit more of the history - name: install josh-proxy run: cargo +stable install josh-proxy --git https://github.com/josh-project/josh --tag r22.12.06 - name: start josh-proxy @@ -196,16 +195,24 @@ jobs: git config --global user.email 'miri@cron.bot' - name: get changes from rustc run: ./miri rustc-pull + - name: Install rustup-toolchain-install-master + run: cargo install -f rustup-toolchain-install-master - name: format changes (if any) run: | ./miri toolchain ./miri fmt --check || (./miri fmt && git commit -am "fmt") - name: Push changes to a branch run: | - git switch -c "rustup$(date -u +%Y-%m)" - git push + BRANCH="rustup$(date -u +%Y-%m-%d)" + git switch -c $BRANCH + git push -u origin $BRANCH - name: Create Pull Request - run: gh pr create -B master --title 'Automatic sync from rustc' --body '' + run: | + PR=$(gh pr create -B master --title 'Automatic sync from rustc' --body '') + ~/.local/bin/zulip-send --user $ZULIP_BOT_EMAIL --api-key $ZULIP_API_TOKEN --site https://rust-lang.zulipchat.com \ + --stream miri --subject "Cron Job Failure (miri, $(date -u +%Y-%m))" \ + --message "A PR doing a rustc-pull [has been automatically created]($PR) for your convenience." env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - + ZULIP_BOT_EMAIL: ${{ secrets.ZULIP_BOT_EMAIL }} + ZULIP_API_TOKEN: ${{ secrets.ZULIP_API_TOKEN }} diff --git a/src/tools/miri/Cargo.lock b/src/tools/miri/Cargo.lock index edb3ee48a4eaf..4232d7fda78f1 100644 --- a/src/tools/miri/Cargo.lock +++ b/src/tools/miri/Cargo.lock @@ -842,9 +842,9 @@ dependencies = [ [[package]] name = "ui_test" -version = "0.11.6" +version = "0.11.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24a2e70adc9d18b9b4dd80ea57aeec447103c6fbb354a07c080adad451c645e1" +checksum = "c21899b59f53717dfad29e4f46e5b21a200a1b6888ab86532a07cfc8b48dd78c" dependencies = [ "bstr", "cargo-platform", diff --git a/src/tools/miri/Cargo.toml b/src/tools/miri/Cargo.toml index 50864334fc51e..a625e1696e143 100644 --- a/src/tools/miri/Cargo.toml +++ b/src/tools/miri/Cargo.toml @@ -36,7 +36,7 @@ libloading = "0.7" [dev-dependencies] colored = "2" -ui_test = "0.11.6" +ui_test = "0.11.7" rustc_version = "0.4" # Features chosen to match those required by env_logger, to avoid rebuilds regex = { version = "1.5.5", default-features = false, features = ["perf", "std"] } diff --git a/src/tools/miri/cargo-miri/src/main.rs b/src/tools/miri/cargo-miri/src/main.rs index 85c9cdad7dfd2..6178670b4f034 100644 --- a/src/tools/miri/cargo-miri/src/main.rs +++ b/src/tools/miri/cargo-miri/src/main.rs @@ -80,7 +80,11 @@ fn main() { match first.as_str() { "miri" => phase_cargo_miri(args), "runner" => phase_runner(args, RunnerPhase::Cargo), - arg if arg == env::var("RUSTC").unwrap() => { + arg if arg == env::var("RUSTC").unwrap_or_else(|_| { + show_error!( + "`cargo-miri` called without RUSTC set; please only invoke this binary through `cargo miri`" + ) + }) => { // If the first arg is equal to the RUSTC env variable (which should be set at this // point), then we need to behave as rustc. This is the somewhat counter-intuitive // behavior of having both RUSTC and RUSTC_WRAPPER set diff --git a/src/tools/miri/cargo-miri/src/util.rs b/src/tools/miri/cargo-miri/src/util.rs index 60f39cb36abaa..4c19ed97fb810 100644 --- a/src/tools/miri/cargo-miri/src/util.rs +++ b/src/tools/miri/cargo-miri/src/util.rs @@ -82,7 +82,7 @@ pub enum MiriCommand { pub fn escape_for_toml(s: &str) -> String { // We want to surround this string in quotes `"`. So we first escape all quotes, // and also all backslashes (that are used to escape quotes). - let s = s.replace('\\', r#"\\"#).replace('"', r#"\""#); + let s = s.replace('\\', r"\\").replace('"', r#"\""#); format!("\"{s}\"") } @@ -130,7 +130,7 @@ pub fn exec(mut cmd: Command) -> ! { { use std::os::unix::process::CommandExt; let error = cmd.exec(); - Err(error).expect("failed to run command") + panic!("failed to run command: {error}") } } diff --git a/src/tools/miri/miri b/src/tools/miri/miri index 7cda995879cfb..ace3d17ae2afb 100755 --- a/src/tools/miri/miri +++ b/src/tools/miri/miri @@ -124,7 +124,7 @@ rustc-pull) git commit rust-version -m "Preparing for merge from rustc" || (echo "FAILED to commit rust-version file, something went wrong"; exit 1) # Fetch given rustc commit and note down which one that was git fetch http://localhost:8000/rust-lang/rust.git@$FETCH_COMMIT$JOSH_FILTER.git || (echo "FAILED to fetch new commits, something went wrong"; exit 1) - git merge FETCH_HEAD --no-ff -m "Merge from rustc" || (echo "FAILED to merge new commits, something went wrong"; exit 1) + git merge FETCH_HEAD --no-ff -m "Merge from rustc" || (echo "FAILED to merge new commits ($(git rev-parse FETCH_HEAD)), something went wrong"; exit 1) exit 0 ;; rustc-push) @@ -325,6 +325,7 @@ run|run-dep) MIRIFLAGS="$MIRIFLAGS --target $MIRI_TEST_TARGET" fi + CARGO="$CARGO --quiet" # First build and get a sysroot. $CARGO build $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml find_sysroot diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 6790454bdb72b..02b0dd16f91c1 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -75726cae37317c7262b69d3e9fd11a3496a88d04 +d4096e0412ac5de785d739a0aa2b1c1c7b9d3b7d diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs index 2dc33334417e3..1ec4cbc4de71d 100644 --- a/src/tools/miri/src/bin/miri.rs +++ b/src/tools/miri/src/bin/miri.rs @@ -67,7 +67,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { if tcx.sess.compile_status().is_err() { tcx.sess.fatal("miri cannot be run on programs that fail compilation"); } -; + init_late_loggers(handler, tcx); if !tcx.sess.crate_types().contains(&CrateType::Executable) { tcx.sess.fatal("miri only makes sense on bin crates"); diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/diagnostics.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/diagnostics.rs index c9674e0a2fe2c..de307a3c5f5be 100644 --- a/src/tools/miri/src/borrow_tracker/stacked_borrows/diagnostics.rs +++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/diagnostics.rs @@ -221,7 +221,10 @@ impl AllocHistory { impl<'history, 'ecx, 'mir, 'tcx> DiagnosticCx<'history, 'ecx, 'mir, 'tcx> { pub fn start_grant(&mut self, perm: Permission) { let Operation::Retag(op) = &mut self.operation else { - unreachable!("start_grant must only be called during a retag, this is: {:?}", self.operation) + unreachable!( + "start_grant must only be called during a retag, this is: {:?}", + self.operation + ) }; op.permission = Some(perm); @@ -286,7 +289,8 @@ impl<'history, 'ecx, 'mir, 'tcx> DiagnosticCx<'history, 'ecx, 'mir, 'tcx> { tag: BorTag, protector_tag: Option, ) -> Option { - let Some(created) = self.history + let Some(created) = self + .history .creations .iter() .rev() @@ -315,22 +319,27 @@ impl<'history, 'ecx, 'mir, 'tcx> DiagnosticCx<'history, 'ecx, 'mir, 'tcx> { None } }) - }).or_else(|| { + }) + .or_else(|| { // If we didn't find a retag that created this tag, it might be the base tag of // this allocation. if self.history.base.0.tag() == tag { Some(( - format!("{tag:?} was created here, as the base tag for {:?}", self.history.id), - self.history.base.1.data() + format!( + "{tag:?} was created here, as the base tag for {:?}", + self.history.id + ), + self.history.base.1.data(), )) } else { None } - }) else { - // But if we don't have a creation event, this is related to a wildcard, and there - // is really nothing we can do to help. - return None; - }; + }) + else { + // But if we don't have a creation event, this is related to a wildcard, and there + // is really nothing we can do to help. + return None; + }; let invalidated = self.history.invalidations.iter().rev().find_map(|event| { if event.tag == tag { Some(event.generate_diagnostic()) } else { None } diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs index 581327e54f1bc..ca0f69450c931 100644 --- a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs +++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs @@ -430,12 +430,15 @@ impl<'tcx> Stack { .find_granting(AccessKind::Write, derived_from, exposed_tags) .map_err(|()| dcx.grant_error(self))?; - let (Some(granting_idx), ProvenanceExtra::Concrete(_)) = (granting_idx, derived_from) else { + let (Some(granting_idx), ProvenanceExtra::Concrete(_)) = (granting_idx, derived_from) + else { // The parent is a wildcard pointer or matched the unknown bottom. // This is approximate. Nobody knows what happened, so forget everything. // The new thing is SRW anyway, so we cannot push it "on top of the unknown part" // (for all we know, it might join an SRW group inside the unknown). - trace!("reborrow: forgetting stack entirely due to SharedReadWrite reborrow from wildcard or unknown"); + trace!( + "reborrow: forgetting stack entirely due to SharedReadWrite reborrow from wildcard or unknown" + ); self.set_unknown_bottom(global.next_ptr_tag); return Ok(()); }; @@ -1008,7 +1011,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { // We have to turn the place into a pointer to use the existing code. // (The pointer type does not matter, so we use a raw pointer.) - let ptr_layout = this.layout_of(Ty::new_mut_ptr(this.tcx.tcx,return_place.layout.ty))?; + let ptr_layout = this.layout_of(Ty::new_mut_ptr(this.tcx.tcx, return_place.layout.ty))?; let val = ImmTy::from_immediate(return_place.to_ref(this), ptr_layout); // Reborrow it. With protection! That is part of the point. let new_perm = NewPermission::Uniform { diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/stack.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/stack.rs index a1e949183ad40..291807c25eeb7 100644 --- a/src/tools/miri/src/borrow_tracker/stacked_borrows/stack.rs +++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/stack.rs @@ -196,19 +196,19 @@ impl<'tcx> Stack { let ProvenanceExtra::Concrete(tag) = tag else { // Handle the wildcard case. // Go search the stack for an exposed tag. - if let Some(idx) = - self.borrows - .iter() - .enumerate() // we also need to know *where* in the stack - .rev() // search top-to-bottom - .find_map(|(idx, item)| { - // If the item fits and *might* be this wildcard, use it. - if item.perm().grants(access) && exposed_tags.contains(&item.tag()) { - Some(idx) - } else { - None - } - }) + if let Some(idx) = self + .borrows + .iter() + .enumerate() // we also need to know *where* in the stack + .rev() // search top-to-bottom + .find_map(|(idx, item)| { + // If the item fits and *might* be this wildcard, use it. + if item.perm().grants(access) && exposed_tags.contains(&item.tag()) { + Some(idx) + } else { + None + } + }) { return Ok(Some(idx)); } diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs index a87a4bbddadea..3b2d6f9608ee4 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs @@ -570,9 +570,13 @@ impl DisplayRepr { extraction_aux(tree, tree.root, show_unnamed, &mut v); let Some(root) = v.pop() else { if show_unnamed { - unreachable!("This allocation contains no tags, not even a root. This should not happen."); + unreachable!( + "This allocation contains no tags, not even a root. This should not happen." + ); } - eprintln!("This allocation does not contain named tags. Use `miri_print_borrow_state(_, true)` to also print unnamed tags."); + eprintln!( + "This allocation does not contain named tags. Use `miri_print_borrow_state(_, true)` to also print unnamed tags." + ); return None; }; assert!(v.is_empty()); diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs index 4c0690c585cd5..e134b73988800 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs @@ -256,7 +256,9 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<' ptr_size.bytes() ); - let Some(new_perm) = new_perm else { return Ok(Some((alloc_id, orig_tag))); }; + let Some(new_perm) = new_perm else { + return Ok(Some((alloc_id, orig_tag))); + }; if let Some(protect) = new_perm.protector { // We register the protection in two different places. @@ -509,7 +511,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { // We have to turn the place into a pointer to use the existing code. // (The pointer type does not matter, so we use a raw pointer.) - let ptr_layout = this.layout_of(Ty::new_mut_ptr(this.tcx.tcx,return_place.layout.ty))?; + let ptr_layout = this.layout_of(Ty::new_mut_ptr(this.tcx.tcx, return_place.layout.ty))?; let val = ImmTy::from_immediate(return_place.to_ref(this), ptr_layout); // Reborrow it. With protection! That is part of the point. // FIXME: do we truly want a 2phase borrow here? diff --git a/src/tools/miri/src/eval.rs b/src/tools/miri/src/eval.rs index 56de9c007d0e9..aba7dd5a9fee0 100644 --- a/src/tools/miri/src/eval.rs +++ b/src/tools/miri/src/eval.rs @@ -305,7 +305,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( for arg in config.args.iter() { // Make space for `0` terminator. let size = u64::try_from(arg.len()).unwrap().checked_add(1).unwrap(); - let arg_type = Ty::new_array(tcx,tcx.types.u8, size); + let arg_type = Ty::new_array(tcx, tcx.types.u8, size); let arg_place = ecx.allocate(ecx.layout_of(arg_type)?, MiriMemoryKind::Machine.into())?; ecx.write_os_str_to_c_str(OsStr::new(arg), arg_place.ptr, size)?; @@ -313,9 +313,11 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( argvs.push(arg_place.to_ref(&ecx)); } // Make an array with all these pointers, in the Miri memory. - let argvs_layout = ecx.layout_of( - Ty::new_array(tcx,Ty::new_imm_ptr(tcx,tcx.types.u8), u64::try_from(argvs.len()).unwrap()), - )?; + let argvs_layout = ecx.layout_of(Ty::new_array( + tcx, + Ty::new_imm_ptr(tcx, tcx.types.u8), + u64::try_from(argvs.len()).unwrap(), + ))?; let argvs_place = ecx.allocate(argvs_layout, MiriMemoryKind::Machine.into())?; for (idx, arg) in argvs.into_iter().enumerate() { let place = ecx.mplace_field(&argvs_place, idx)?; @@ -333,7 +335,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( ecx.machine.argc = Some(*argc_place); let argv_place = ecx.allocate( - ecx.layout_of(Ty::new_imm_ptr(tcx,tcx.types.unit))?, + ecx.layout_of(Ty::new_imm_ptr(tcx, tcx.types.unit))?, MiriMemoryKind::Machine.into(), )?; ecx.write_immediate(argv, &argv_place.into())?; @@ -345,7 +347,8 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( // Construct a command string with all the arguments. let cmd_utf16: Vec = args_to_utf16_command_string(config.args.iter()); - let cmd_type = Ty::new_array(tcx,tcx.types.u16, u64::try_from(cmd_utf16.len()).unwrap()); + let cmd_type = + Ty::new_array(tcx, tcx.types.u16, u64::try_from(cmd_utf16.len()).unwrap()); let cmd_place = ecx.allocate(ecx.layout_of(cmd_type)?, MiriMemoryKind::Machine.into())?; ecx.machine.cmd_line = Some(*cmd_place); @@ -366,7 +369,11 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( match entry_type { EntryFnType::Main { .. } => { - let start_id = tcx.lang_items().start_fn().unwrap(); + let start_id = tcx.lang_items().start_fn().unwrap_or_else(|| { + tcx.sess.fatal( + "could not find start function. Make sure the entry point is marked with `#[start]`." + ); + }); let main_ret_ty = tcx.fn_sig(entry_id).no_bound_vars().unwrap().output(); let main_ret_ty = main_ret_ty.no_bound_vars().unwrap(); let start_instance = ty::Instance::resolve( diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs index e79bb47c78b18..7e92dc7a0c743 100644 --- a/src/tools/miri/src/lib.rs +++ b/src/tools/miri/src/lib.rs @@ -9,6 +9,7 @@ #![feature(local_key_cell_methods)] #![feature(round_ties_even)] #![feature(os_str_bytes)] +#![feature(lint_reasons)] // Configure clippy and other lints #![allow( clippy::collapsible_else_if, diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index 5fcf3905199d3..ac2bad221199c 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -313,10 +313,12 @@ pub struct PrimitiveLayouts<'tcx> { impl<'mir, 'tcx: 'mir> PrimitiveLayouts<'tcx> { fn new(layout_cx: LayoutCx<'tcx, TyCtxt<'tcx>>) -> Result> { let tcx = layout_cx.tcx; - let mut_raw_ptr = Ty::new_ptr(tcx,TypeAndMut { ty: tcx.types.unit, mutbl: Mutability::Mut }); - let const_raw_ptr = Ty::new_ptr(tcx,TypeAndMut { ty: tcx.types.unit, mutbl: Mutability::Not }); + let mut_raw_ptr = + Ty::new_ptr(tcx, TypeAndMut { ty: tcx.types.unit, mutbl: Mutability::Mut }); + let const_raw_ptr = + Ty::new_ptr(tcx, TypeAndMut { ty: tcx.types.unit, mutbl: Mutability::Not }); Ok(Self { - unit: layout_cx.layout_of(Ty::new_unit(tcx,))?, + unit: layout_cx.layout_of(Ty::new_unit(tcx))?, i8: layout_cx.layout_of(tcx.types.i8)?, i16: layout_cx.layout_of(tcx.types.i16)?, i32: layout_cx.layout_of(tcx.types.i32)?, diff --git a/src/tools/miri/src/shims/backtrace.rs b/src/tools/miri/src/shims/backtrace.rs index eaa66f1f87469..adf9a35d5c3a3 100644 --- a/src/tools/miri/src/shims/backtrace.rs +++ b/src/tools/miri/src/shims/backtrace.rs @@ -71,7 +71,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let len: u64 = ptrs.len().try_into().unwrap(); let ptr_ty = this.machine.layouts.mut_raw_ptr.ty; - let array_layout = this.layout_of(Ty::new_array(tcx.tcx,ptr_ty, len)).unwrap(); + let array_layout = this.layout_of(Ty::new_array(tcx.tcx, ptr_ty, len)).unwrap(); match flags { // storage for pointers is allocated by miri diff --git a/src/tools/miri/src/shims/env.rs b/src/tools/miri/src/shims/env.rs index 3d4967f1f834e..1dcb877a83f0d 100644 --- a/src/tools/miri/src/shims/env.rs +++ b/src/tools/miri/src/shims/env.rs @@ -5,8 +5,8 @@ use std::mem; use rustc_const_eval::interpret::Pointer; use rustc_data_structures::fx::FxHashMap; -use rustc_middle::ty::Ty; use rustc_middle::ty::layout::LayoutOf; +use rustc_middle::ty::Ty; use rustc_target::abi::Size; use crate::helpers::target_os_is_unix; @@ -449,9 +449,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { vars.push(Pointer::null()); // Make an array with all these pointers inside Miri. let tcx = this.tcx; - let vars_layout = this.layout_of( - Ty::new_array(tcx.tcx,this.machine.layouts.mut_raw_ptr.ty, u64::try_from(vars.len()).unwrap()), - )?; + let vars_layout = this.layout_of(Ty::new_array( + tcx.tcx, + this.machine.layouts.mut_raw_ptr.ty, + u64::try_from(vars.len()).unwrap(), + ))?; let vars_place = this.allocate(vars_layout, MiriMemoryKind::Runtime.into())?; for (idx, var) in vars.into_iter().enumerate() { let place = this.mplace_field(&vars_place, idx)?; diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs index f4e91c30d9f1a..6915c396d616c 100644 --- a/src/tools/miri/src/shims/foreign_items.rs +++ b/src/tools/miri/src/shims/foreign_items.rs @@ -763,6 +763,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let ptr_dest = this.read_pointer(ptr_dest)?; let ptr_src = this.read_pointer(ptr_src)?; let n = this.read_target_usize(n)?; + + // C requires that this must always be a valid pointer, even if `n` is zero, so we better check that. + // (This is more than Rust requires, so `mem_copy` is not sufficient.) + this.ptr_get_alloc_id(ptr_dest)?; + this.ptr_get_alloc_id(ptr_src)?; + this.mem_copy( ptr_src, Align::ONE, diff --git a/src/tools/miri/src/shims/intrinsics/simd.rs b/src/tools/miri/src/shims/intrinsics/simd.rs index 1995db715e8da..94f8cfbfb1c3d 100644 --- a/src/tools/miri/src/shims/intrinsics/simd.rs +++ b/src/tools/miri/src/shims/intrinsics/simd.rs @@ -483,7 +483,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { // `index` is an array, not a SIMD type let ty::Array(_, index_len) = index.layout.ty.kind() else { - span_bug!(this.cur_span(), "simd_shuffle index argument has non-array type {}", index.layout.ty) + span_bug!( + this.cur_span(), + "simd_shuffle index argument has non-array type {}", + index.layout.ty + ) }; let index_len = index_len.eval_target_usize(*this.tcx, this.param_env()); @@ -622,9 +626,7 @@ fn fmax_op<'tcx>( right: &ImmTy<'tcx, Provenance>, ) -> InterpResult<'tcx, Scalar> { assert_eq!(left.layout.ty, right.layout.ty); - let ty::Float(float_ty) = left.layout.ty.kind() else { - bug!("fmax operand is not a float") - }; + let ty::Float(float_ty) = left.layout.ty.kind() else { bug!("fmax operand is not a float") }; let left = left.to_scalar(); let right = right.to_scalar(); Ok(match float_ty { @@ -638,9 +640,7 @@ fn fmin_op<'tcx>( right: &ImmTy<'tcx, Provenance>, ) -> InterpResult<'tcx, Scalar> { assert_eq!(left.layout.ty, right.layout.ty); - let ty::Float(float_ty) = left.layout.ty.kind() else { - bug!("fmin operand is not a float") - }; + let ty::Float(float_ty) = left.layout.ty.kind() else { bug!("fmin operand is not a float") }; let left = left.to_scalar(); let right = right.to_scalar(); Ok(match float_ty { diff --git a/src/tools/miri/src/shims/os_str.rs b/src/tools/miri/src/shims/os_str.rs index 4cdd54fa21b77..f08f0aad5e764 100644 --- a/src/tools/miri/src/shims/os_str.rs +++ b/src/tools/miri/src/shims/os_str.rs @@ -7,8 +7,8 @@ use std::os::unix::ffi::{OsStrExt, OsStringExt}; #[cfg(windows)] use std::os::windows::ffi::{OsStrExt, OsStringExt}; -use rustc_middle::ty::Ty; use rustc_middle::ty::layout::LayoutOf; +use rustc_middle::ty::Ty; use crate::*; @@ -141,7 +141,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let size = u64::try_from(os_str.len()).unwrap().checked_add(1).unwrap(); // Make space for `0` terminator. let this = self.eval_context_mut(); - let arg_type = Ty::new_array(this.tcx.tcx,this.tcx.types.u8, size); + let arg_type = Ty::new_array(this.tcx.tcx, this.tcx.types.u8, size); let arg_place = this.allocate(this.layout_of(arg_type).unwrap(), memkind)?; let (written, _) = self.write_os_str_to_c_str(os_str, arg_place.ptr, size).unwrap(); assert!(written); @@ -157,7 +157,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let size = u64::try_from(os_str.len()).unwrap().checked_add(1).unwrap(); // Make space for `0x0000` terminator. let this = self.eval_context_mut(); - let arg_type = Ty::new_array(this.tcx.tcx,this.tcx.types.u16, size); + let arg_type = Ty::new_array(this.tcx.tcx, this.tcx.types.u16, size); let arg_place = this.allocate(this.layout_of(arg_type).unwrap(), memkind)?; let (written, _) = self.write_os_str_to_wide_str(os_str, arg_place.ptr, size, /*truncate*/ false).unwrap(); diff --git a/src/tools/miri/src/shims/unix/linux/fd.rs b/src/tools/miri/src/shims/unix/linux/fd.rs index dc395d39ce11a..87e887000c523 100644 --- a/src/tools/miri/src/shims/unix/linux/fd.rs +++ b/src/tools/miri/src/shims/unix/linux/fd.rs @@ -181,6 +181,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { /// `EFD_SEMAPHORE` - miri does not support semaphore-like semantics. /// /// + #[expect(clippy::needless_if)] fn eventfd( &mut self, val: &OpTy<'tcx, Provenance>, diff --git a/src/tools/miri/tests/compiletest.rs b/src/tools/miri/tests/compiletest.rs index 73671e716efe5..59143550253d6 100644 --- a/src/tools/miri/tests/compiletest.rs +++ b/src/tools/miri/tests/compiletest.rs @@ -145,7 +145,8 @@ fn run_tests(mode: Mode, path: &str, target: &str, with_dependencies: bool) -> R // The files we're actually interested in (all `.rs` files). |path| { path.extension().is_some_and(|ext| ext == "rs") - && (filters.is_empty() || filters.iter().any(|f| path.starts_with(f))) + && (filters.is_empty() + || filters.iter().any(|f| path.display().to_string().contains(f))) }, // This could be used to overwrite the `Config` on a per-test basis. |_, _| None, @@ -274,13 +275,13 @@ fn main() -> Result<()> { fn run_dep_mode(target: String, mut args: impl Iterator) -> Result<()> { let path = args.next().expect("./miri run-dep must be followed by a file name"); let mut config = test_config(&target, "", Mode::Yolo, /* with dependencies */ true); - config.program.args.remove(0); // remove the `--error-format=json` argument - config.program.args.push("--color".into()); - config.program.args.push("always".into()); - let mut cmd = ui_test::test_command(config, Path::new(&path))?; - // Separate the arguments to the `cargo miri` invocation from - // the arguments to the interpreted prog - cmd.arg("--"); + config.program.args.clear(); // We want to give the user full control over flags + config.build_dependencies_and_link_them()?; + + let mut cmd = config.program.build(&config.out_dir); + + cmd.arg(path); + cmd.args(args); if cmd.spawn()?.wait()?.success() { Ok(()) } else { std::process::exit(1) } } diff --git a/src/tools/miri/tests/fail/overlapping_assignment.rs b/src/tools/miri/tests/fail/overlapping_assignment.rs new file mode 100644 index 0000000000000..84994c179f9ea --- /dev/null +++ b/src/tools/miri/tests/fail/overlapping_assignment.rs @@ -0,0 +1,23 @@ +#![feature(core_intrinsics)] +#![feature(custom_mir)] + +use std::intrinsics::mir::*; + +// It's not that easy to fool the MIR validity check +// which wants to prevent overlapping assignments... +// So we use two separate pointer arguments, and then arrange for them to alias. +#[custom_mir(dialect = "runtime", phase = "optimized")] +pub fn self_copy(ptr1: *mut [i32; 4], ptr2: *mut [i32; 4]) { + mir! { + { + *ptr1 = *ptr2; //~ERROR: overlapping ranges + Return() + } + } +} + +pub fn main() { + let mut x = [0; 4]; + let ptr = std::ptr::addr_of_mut!(x); + self_copy(ptr, ptr); +} diff --git a/src/tools/miri/tests/fail/overlapping_assignment.stderr b/src/tools/miri/tests/fail/overlapping_assignment.stderr new file mode 100644 index 0000000000000..42a000dfcc6c7 --- /dev/null +++ b/src/tools/miri/tests/fail/overlapping_assignment.stderr @@ -0,0 +1,20 @@ +error: Undefined Behavior: `copy_nonoverlapping` called on overlapping ranges + --> $DIR/overlapping_assignment.rs:LL:CC + | +LL | *ptr1 = *ptr2; + | ^^^^^^^^^^^^^ `copy_nonoverlapping` called on overlapping ranges + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside `self_copy` at $DIR/overlapping_assignment.rs:LL:CC +note: inside `main` + --> $DIR/overlapping_assignment.rs:LL:CC + | +LL | self_copy(ptr, ptr); + | ^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/src/tools/miri/tests/fail/shims/memchr_null.rs b/src/tools/miri/tests/fail/shims/memchr_null.rs new file mode 100644 index 0000000000000..6bc7af7e6bf77 --- /dev/null +++ b/src/tools/miri/tests/fail/shims/memchr_null.rs @@ -0,0 +1,10 @@ +//@ignore-target-windows: No libc on Windows + +use std::ptr; + +// null is explicitly called out as UB in the C docs. +fn main() { + unsafe { + libc::memchr(ptr::null(), 0, 0); //~ERROR: dangling + } +} diff --git a/src/tools/miri/tests/fail/shims/memchr_null.stderr b/src/tools/miri/tests/fail/shims/memchr_null.stderr new file mode 100644 index 0000000000000..d48606f34ad9e --- /dev/null +++ b/src/tools/miri/tests/fail/shims/memchr_null.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: memory access failed: null pointer is a dangling pointer (it has no provenance) + --> $DIR/memchr_null.rs:LL:CC + | +LL | libc::memchr(ptr::null(), 0, 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: null pointer is a dangling pointer (it has no provenance) + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside `main` at $DIR/memchr_null.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/src/tools/miri/tests/fail/shims/memcmp_null.rs b/src/tools/miri/tests/fail/shims/memcmp_null.rs new file mode 100644 index 0000000000000..a4e0034c40bdc --- /dev/null +++ b/src/tools/miri/tests/fail/shims/memcmp_null.rs @@ -0,0 +1,10 @@ +//@ignore-target-windows: No libc on Windows + +use std::ptr; + +// null is explicitly called out as UB in the C docs. +fn main() { + unsafe { + libc::memcmp(ptr::null(), ptr::null(), 0); //~ERROR: dangling + } +} diff --git a/src/tools/miri/tests/fail/shims/memcmp_null.stderr b/src/tools/miri/tests/fail/shims/memcmp_null.stderr new file mode 100644 index 0000000000000..7a09c77989455 --- /dev/null +++ b/src/tools/miri/tests/fail/shims/memcmp_null.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: memory access failed: null pointer is a dangling pointer (it has no provenance) + --> $DIR/memcmp_null.rs:LL:CC + | +LL | libc::memcmp(ptr::null(), ptr::null(), 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: null pointer is a dangling pointer (it has no provenance) + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside `main` at $DIR/memcmp_null.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/src/tools/miri/tests/fail/shims/memcpy_zero.rs b/src/tools/miri/tests/fail/shims/memcpy_zero.rs new file mode 100644 index 0000000000000..5283fea4cb989 --- /dev/null +++ b/src/tools/miri/tests/fail/shims/memcpy_zero.rs @@ -0,0 +1,12 @@ +//@ignore-target-windows: No libc on Windows +//@compile-flags: -Zmiri-permissive-provenance +// C's memcpy is 0 bytes is UB for some pointers that are allowed in Rust's `copy_nonoverlapping`. + +fn main() { + let from = 42 as *const u8; + let to = 23 as *mut u8; + unsafe { + to.copy_from(from, 0); // this is fine + libc::memcpy(to.cast(), from.cast(), 0); //~ERROR: dangling + } +} diff --git a/src/tools/miri/tests/fail/shims/memcpy_zero.stderr b/src/tools/miri/tests/fail/shims/memcpy_zero.stderr new file mode 100644 index 0000000000000..7c1c3fe20c4e5 --- /dev/null +++ b/src/tools/miri/tests/fail/shims/memcpy_zero.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: out-of-bounds pointer use: 0x17[noalloc] is a dangling pointer (it has no provenance) + --> $DIR/memcpy_zero.rs:LL:CC + | +LL | libc::memcpy(to.cast(), from.cast(), 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: 0x17[noalloc] is a dangling pointer (it has no provenance) + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside `main` at $DIR/memcpy_zero.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/src/tools/miri/tests/fail/shims/memrchr_null.rs b/src/tools/miri/tests/fail/shims/memrchr_null.rs new file mode 100644 index 0000000000000..b6707d558d8f6 --- /dev/null +++ b/src/tools/miri/tests/fail/shims/memrchr_null.rs @@ -0,0 +1,11 @@ +//@ignore-target-windows: No libc on Windows +//@ignore-target-apple: No `memrchr` on some apple targets + +use std::ptr; + +// null is explicitly called out as UB in the C docs. +fn main() { + unsafe { + libc::memrchr(ptr::null(), 0, 0); //~ERROR: dangling + } +} diff --git a/src/tools/miri/tests/fail/shims/memrchr_null.stderr b/src/tools/miri/tests/fail/shims/memrchr_null.stderr new file mode 100644 index 0000000000000..b5b7630e7fd0d --- /dev/null +++ b/src/tools/miri/tests/fail/shims/memrchr_null.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: memory access failed: null pointer is a dangling pointer (it has no provenance) + --> $DIR/memrchr_null.rs:LL:CC + | +LL | libc::memrchr(ptr::null(), 0, 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: null pointer is a dangling pointer (it has no provenance) + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside `main` at $DIR/memrchr_null.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/src/tools/miri/tests/pass/vec.rs b/src/tools/miri/tests/pass/vec.rs index 048f7d1c3512a..4ab2bcb7f2281 100644 --- a/src/tools/miri/tests/pass/vec.rs +++ b/src/tools/miri/tests/pass/vec.rs @@ -100,7 +100,7 @@ fn vec_push_ptr_stable() { v.push(0); let v0 = unsafe { &mut *(&mut v[0] as *mut _) }; // laundering the lifetime -- we take care that `v` does not reallocate, so that's okay. v.push(1); - let _val = *v0; + *v0 = *v0; } fn vec_extend_ptr_stable() { @@ -109,23 +109,23 @@ fn vec_extend_ptr_stable() { let v0 = unsafe { &mut *(&mut v[0] as *mut _) }; // laundering the lifetime -- we take care that `v` does not reallocate, so that's okay. // `slice::Iter` (with `T: Copy`) specialization v.extend(&[1]); - let _val = *v0; + *v0 = *v0; // `vec::IntoIter` specialization v.extend(vec![2]); - let _val = *v0; + *v0 = *v0; // `TrustedLen` specialization v.extend(std::iter::once(3)); - let _val = *v0; + *v0 = *v0; // base case v.extend(std::iter::once(3).filter(|_| true)); - let _val = *v0; + *v0 = *v0; } fn vec_truncate_ptr_stable() { let mut v = vec![0; 10]; let v0 = unsafe { &mut *(&mut v[0] as *mut _) }; // laundering the lifetime -- we take care that `v` does not reallocate, so that's okay. v.truncate(5); - let _val = *v0; + *v0 = *v0; } fn push_str_ptr_stable() { diff --git a/src/tools/opt-dist/Cargo.toml b/src/tools/opt-dist/Cargo.toml new file mode 100644 index 0000000000000..5a1794d33364d --- /dev/null +++ b/src/tools/opt-dist/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "opt-dist" +version = "0.1.0" +edition = "2021" + +[dependencies] +build_helper = { path = "../build_helper" } +env_logger = "0.10" +log = "0.4" +anyhow = { version = "1", features = ["backtrace"] } +humantime = "2" +humansize = "2" +sysinfo = { version = "0.29", default-features = false } +fs_extra = "1" +camino = "1" +reqwest = { version = "0.11", features = ["blocking"] } +zip = { version = "0.6", default-features = false, features = ["deflate"] } +tar = "0.4" +xz = "0.1" +serde = { version = "1", features = ["derive"] } +serde_json = "1" +glob = "0.3" diff --git a/src/tools/opt-dist/README.md b/src/tools/opt-dist/README.md new file mode 100644 index 0000000000000..05a75870da140 --- /dev/null +++ b/src/tools/opt-dist/README.md @@ -0,0 +1,7 @@ +# Optimized build pipeline +This binary implements a heavily optimized build pipeline for `rustc` and `LLVM` artifacts that are used for both for +benchmarking using the perf. bot and for final distribution to users. + +It uses LTO, PGO and BOLT to optimize the compiler and LLVM as much as possible. +This logic is not part of bootstrap, because it needs to invoke bootstrap multiple times, force-rebuild various +artifacts repeatedly and sometimes go around bootstrap's cache mechanism. diff --git a/src/tools/opt-dist/src/environment/linux.rs b/src/tools/opt-dist/src/environment/linux.rs new file mode 100644 index 0000000000000..d4c55c46f7ce8 --- /dev/null +++ b/src/tools/opt-dist/src/environment/linux.rs @@ -0,0 +1,54 @@ +use crate::environment::Environment; +use crate::exec::cmd; +use crate::utils::io::copy_directory; +use camino::{Utf8Path, Utf8PathBuf}; + +pub(super) struct LinuxEnvironment; + +impl Environment for LinuxEnvironment { + fn python_binary(&self) -> &'static str { + "python3" + } + + fn checkout_path(&self) -> Utf8PathBuf { + Utf8PathBuf::from("/checkout") + } + + fn downloaded_llvm_dir(&self) -> Utf8PathBuf { + Utf8PathBuf::from("/rustroot") + } + + fn opt_artifacts(&self) -> Utf8PathBuf { + Utf8PathBuf::from("/tmp/tmp-multistage/opt-artifacts") + } + + fn build_root(&self) -> Utf8PathBuf { + self.checkout_path().join("obj") + } + + fn prepare_rustc_perf(&self) -> anyhow::Result<()> { + // /tmp/rustc-perf comes from the x64 dist Dockerfile + copy_directory(Utf8Path::new("/tmp/rustc-perf"), &self.rustc_perf_dir())?; + cmd(&[self.cargo_stage_0().as_str(), "build", "-p", "collector"]) + .workdir(&self.rustc_perf_dir()) + .env("RUSTC", &self.rustc_stage_0().into_string()) + .env("RUSTC_BOOTSTRAP", "1") + .run()?; + Ok(()) + } + + fn supports_bolt(&self) -> bool { + true + } + + fn executable_extension(&self) -> &'static str { + "" + } + + fn skipped_tests(&self) -> &'static [&'static str] { + &[ + // Fails because of linker errors, as of June 2023. + "tests/ui/process/nofile-limit.rs", + ] + } +} diff --git a/src/tools/opt-dist/src/environment/mod.rs b/src/tools/opt-dist/src/environment/mod.rs new file mode 100644 index 0000000000000..f66b9ab41ead9 --- /dev/null +++ b/src/tools/opt-dist/src/environment/mod.rs @@ -0,0 +1,75 @@ +use camino::Utf8PathBuf; + +#[cfg(target_family = "unix")] +mod linux; +#[cfg(target_family = "windows")] +mod windows; + +pub trait Environment { + fn host_triple(&self) -> String { + std::env::var("PGO_HOST").expect("PGO_HOST environment variable missing") + } + + fn python_binary(&self) -> &'static str; + + /// The rustc checkout, where the compiler source is located. + fn checkout_path(&self) -> Utf8PathBuf; + + /// Path to the downloaded host LLVM. + fn downloaded_llvm_dir(&self) -> Utf8PathBuf; + + /// Directory where the optimization artifacts (PGO/BOLT profiles, etc.) + /// will be stored. + fn opt_artifacts(&self) -> Utf8PathBuf; + + /// The main directory where the build occurs. + fn build_root(&self) -> Utf8PathBuf; + + fn build_artifacts(&self) -> Utf8PathBuf { + self.build_root().join("build").join(self.host_triple()) + } + + fn cargo_stage_0(&self) -> Utf8PathBuf { + self.build_artifacts() + .join("stage0") + .join("bin") + .join(format!("cargo{}", self.executable_extension())) + } + + fn rustc_stage_0(&self) -> Utf8PathBuf { + self.build_artifacts() + .join("stage0") + .join("bin") + .join(format!("rustc{}", self.executable_extension())) + } + + fn rustc_stage_2(&self) -> Utf8PathBuf { + self.build_artifacts() + .join("stage2") + .join("bin") + .join(format!("rustc{}", self.executable_extension())) + } + + /// Path to the built rustc-perf benchmark suite. + fn rustc_perf_dir(&self) -> Utf8PathBuf { + self.opt_artifacts().join("rustc-perf") + } + + /// Download and/or compile rustc-perf. + fn prepare_rustc_perf(&self) -> anyhow::Result<()>; + + fn supports_bolt(&self) -> bool; + + /// What is the extension of binary executables in this environment? + fn executable_extension(&self) -> &'static str; + + /// List of test paths that should be skipped when testing the optimized artifacts. + fn skipped_tests(&self) -> &'static [&'static str]; +} + +pub fn create_environment() -> Box { + #[cfg(target_family = "unix")] + return Box::new(linux::LinuxEnvironment); + #[cfg(target_family = "windows")] + return Box::new(windows::WindowsEnvironment::new()); +} diff --git a/src/tools/opt-dist/src/environment/windows.rs b/src/tools/opt-dist/src/environment/windows.rs new file mode 100644 index 0000000000000..36f4c0f29cc4a --- /dev/null +++ b/src/tools/opt-dist/src/environment/windows.rs @@ -0,0 +1,78 @@ +use crate::environment::Environment; +use crate::exec::cmd; +use crate::utils::io::move_directory; +use camino::Utf8PathBuf; +use std::io::Cursor; +use zip::ZipArchive; + +pub(super) struct WindowsEnvironment { + checkout_dir: Utf8PathBuf, +} + +impl WindowsEnvironment { + pub fn new() -> Self { + Self { checkout_dir: std::env::current_dir().unwrap().try_into().unwrap() } + } +} + +impl Environment for WindowsEnvironment { + fn python_binary(&self) -> &'static str { + "python" + } + + fn checkout_path(&self) -> Utf8PathBuf { + self.checkout_dir.clone() + } + + fn downloaded_llvm_dir(&self) -> Utf8PathBuf { + self.checkout_path().join("citools").join("clang-rust") + } + + fn opt_artifacts(&self) -> Utf8PathBuf { + self.checkout_path().join("opt-artifacts") + } + + fn build_root(&self) -> Utf8PathBuf { + self.checkout_path() + } + + fn prepare_rustc_perf(&self) -> anyhow::Result<()> { + // FIXME: add some mechanism for synchronization of this commit SHA with + // Linux (which builds rustc-perf in a Dockerfile) + // rustc-perf version from 2023-05-30 + const PERF_COMMIT: &str = "8b2ac3042e1ff2c0074455a0a3618adef97156b1"; + + let url = format!("https://github.com/rust-lang/rustc-perf/archive/{PERF_COMMIT}.zip"); + let response = reqwest::blocking::get(url)?.error_for_status()?.bytes()?.to_vec(); + + let mut archive = ZipArchive::new(Cursor::new(response))?; + archive.extract(self.rustc_perf_dir())?; + move_directory( + &self.rustc_perf_dir().join(format!("rustc-perf-{PERF_COMMIT}")), + &self.rustc_perf_dir(), + )?; + + cmd(&[self.cargo_stage_0().as_str(), "build", "-p", "collector"]) + .workdir(&self.rustc_perf_dir()) + .env("RUSTC", &self.rustc_stage_0().into_string()) + .env("RUSTC_BOOTSTRAP", "1") + .run()?; + + Ok(()) + } + + fn supports_bolt(&self) -> bool { + false + } + + fn executable_extension(&self) -> &'static str { + ".exe" + } + + fn skipped_tests(&self) -> &'static [&'static str] { + &[ + // Fails as of June 2023. + "tests\\codegen\\vec-shrink-panik.rs", + ] + } +} diff --git a/src/tools/opt-dist/src/exec.rs b/src/tools/opt-dist/src/exec.rs new file mode 100644 index 0000000000000..d05ddbd4c0e3b --- /dev/null +++ b/src/tools/opt-dist/src/exec.rs @@ -0,0 +1,169 @@ +use crate::environment::Environment; +use crate::metrics::{load_metrics, record_metrics}; +use crate::timer::TimerSection; +use crate::training::{LlvmBoltProfile, LlvmPGOProfile, RustcPGOProfile}; +use camino::{Utf8Path, Utf8PathBuf}; +use std::collections::BTreeMap; +use std::fs::File; +use std::process::{Command, Stdio}; + +#[derive(Default)] +pub struct CmdBuilder { + args: Vec, + env: BTreeMap, + workdir: Option, + output: Option, +} + +impl CmdBuilder { + pub fn arg(mut self, arg: &str) -> Self { + self.args.push(arg.to_string()); + self + } + + pub fn env(mut self, name: &str, value: &str) -> Self { + self.env.insert(name.to_string(), value.to_string()); + self + } + + pub fn workdir(mut self, path: &Utf8Path) -> Self { + self.workdir = Some(path.to_path_buf()); + self + } + + pub fn redirect_output(mut self, path: Utf8PathBuf) -> Self { + self.output = Some(path); + self + } + + pub fn run(self) -> anyhow::Result<()> { + let mut cmd_str = String::new(); + cmd_str.push_str( + &self + .env + .iter() + .map(|(key, value)| format!("{key}={value}")) + .collect::>() + .join(" "), + ); + if !self.env.is_empty() { + cmd_str.push(' '); + } + cmd_str.push_str(&self.args.join(" ")); + if let Some(ref path) = self.output { + cmd_str.push_str(&format!(" > {path:?}")); + } + cmd_str.push_str(&format!( + " [at {}]", + self.workdir + .clone() + .unwrap_or_else(|| std::env::current_dir().unwrap().try_into().unwrap()) + )); + log::info!("Executing `{cmd_str}`"); + + let mut cmd = Command::new(&self.args[0]); + cmd.stdin(Stdio::null()); + cmd.args(self.args.iter().skip(1)); + for (key, value) in &self.env { + cmd.env(key, value); + } + if let Some(ref output) = self.output { + cmd.stdout(File::create(output.clone().into_std_path_buf())?); + } + if let Some(ref workdir) = self.workdir { + cmd.current_dir(workdir.clone().into_std_path_buf()); + } + let exit_status = cmd.spawn()?.wait()?; + if !exit_status.success() { + Err(anyhow::anyhow!( + "Command {cmd_str} has failed with exit code {:?}", + exit_status.code(), + )) + } else { + Ok(()) + } + } +} + +pub fn cmd(args: &[&str]) -> CmdBuilder { + assert!(!args.is_empty()); + CmdBuilder { args: args.iter().map(|s| s.to_string()).collect(), ..Default::default() } +} + +pub struct Bootstrap { + cmd: CmdBuilder, + metrics_path: Utf8PathBuf, +} + +impl Bootstrap { + pub fn build(env: &dyn Environment) -> Self { + let metrics_path = env.build_root().join("build").join("metrics.json"); + let cmd = cmd(&[ + env.python_binary(), + env.checkout_path().join("x.py").as_str(), + "build", + "--target", + &env.host_triple(), + "--host", + &env.host_triple(), + "--stage", + "2", + "library/std", + ]) + .env("RUST_BACKTRACE", "full"); + Self { cmd, metrics_path } + } + + pub fn dist(env: &dyn Environment, dist_args: &[String]) -> Self { + let metrics_path = env.build_root().join("build").join("metrics.json"); + let cmd = cmd(&dist_args.iter().map(|arg| arg.as_str()).collect::>()) + .env("RUST_BACKTRACE", "full"); + Self { cmd, metrics_path } + } + + pub fn llvm_pgo_instrument(mut self, profile_dir: &Utf8Path) -> Self { + self.cmd = self + .cmd + .arg("--llvm-profile-generate") + .env("LLVM_PROFILE_DIR", profile_dir.join("prof-%p").as_str()); + self + } + + pub fn llvm_pgo_optimize(mut self, profile: &LlvmPGOProfile) -> Self { + self.cmd = self.cmd.arg("--llvm-profile-use").arg(profile.0.as_str()); + self + } + + pub fn rustc_pgo_instrument(mut self, profile_dir: &Utf8Path) -> Self { + self.cmd = self.cmd.arg("--rust-profile-generate").arg(profile_dir.as_str()); + self + } + + pub fn rustc_pgo_optimize(mut self, profile: &RustcPGOProfile) -> Self { + self.cmd = self.cmd.arg("--rust-profile-use").arg(profile.0.as_str()); + self + } + + pub fn llvm_bolt_instrument(mut self) -> Self { + self.cmd = self.cmd.arg("--llvm-bolt-profile-generate"); + self + } + + pub fn llvm_bolt_optimize(mut self, profile: &LlvmBoltProfile) -> Self { + self.cmd = self.cmd.arg("--llvm-bolt-profile-use").arg(profile.0.as_str()); + self + } + + /// Do not rebuild rustc, and use a previously built rustc sysroot instead. + pub fn avoid_rustc_rebuild(mut self) -> Self { + self.cmd = self.cmd.arg("--keep-stage").arg("0").arg("--keep-stage").arg("1"); + self + } + + pub fn run(self, timer: &mut TimerSection) -> anyhow::Result<()> { + self.cmd.run()?; + let metrics = load_metrics(&self.metrics_path)?; + record_metrics(&metrics, timer); + Ok(()) + } +} diff --git a/src/tools/opt-dist/src/main.rs b/src/tools/opt-dist/src/main.rs new file mode 100644 index 0000000000000..39fa7e1fb2afd --- /dev/null +++ b/src/tools/opt-dist/src/main.rs @@ -0,0 +1,175 @@ +use anyhow::Context; +use log::LevelFilter; + +use crate::environment::{create_environment, Environment}; +use crate::exec::Bootstrap; +use crate::tests::run_tests; +use crate::timer::Timer; +use crate::training::{gather_llvm_bolt_profiles, gather_llvm_profiles, gather_rustc_profiles}; +use crate::utils::io::reset_directory; +use crate::utils::{clear_llvm_files, format_env_variables, print_free_disk_space}; + +mod environment; +mod exec; +mod metrics; +mod tests; +mod timer; +mod training; +mod utils; + +fn is_try_build() -> bool { + std::env::var("DIST_TRY_BUILD").unwrap_or_else(|_| "0".to_string()) != "0" +} + +fn execute_pipeline( + env: &dyn Environment, + timer: &mut Timer, + dist_args: Vec, +) -> anyhow::Result<()> { + reset_directory(&env.opt_artifacts())?; + env.prepare_rustc_perf()?; + + // Stage 1: Build PGO instrumented rustc + // We use a normal build of LLVM, because gathering PGO profiles for LLVM and `rustc` at the + // same time can cause issues, because the host and in-tree LLVM versions can diverge. + let rustc_pgo_profile = timer.section("Stage 1 (Rustc PGO)", |stage| { + let rustc_profile_dir_root = env.opt_artifacts().join("rustc-pgo"); + + stage.section("Build PGO instrumented rustc and LLVM", |section| { + Bootstrap::build(env).rustc_pgo_instrument(&rustc_profile_dir_root).run(section) + })?; + + let profile = stage + .section("Gather profiles", |_| gather_rustc_profiles(env, &rustc_profile_dir_root))?; + print_free_disk_space()?; + + stage.section("Build PGO optimized rustc", |section| { + Bootstrap::build(env).rustc_pgo_optimize(&profile).run(section) + })?; + + Ok(profile) + })?; + + // Stage 2: Gather LLVM PGO profiles + // Here we build a PGO instrumented LLVM, reusing the previously PGO optimized rustc. + // Then we use the instrumented LLVM to gather LLVM PGO profiles. + let llvm_pgo_profile = timer.section("Stage 2 (LLVM PGO)", |stage| { + // Remove the previous, uninstrumented build of LLVM. + clear_llvm_files(env)?; + + let llvm_profile_dir_root = env.opt_artifacts().join("llvm-pgo"); + + stage.section("Build PGO instrumented LLVM", |section| { + Bootstrap::build(env) + .llvm_pgo_instrument(&llvm_profile_dir_root) + .avoid_rustc_rebuild() + .run(section) + })?; + + let profile = stage + .section("Gather profiles", |_| gather_llvm_profiles(env, &llvm_profile_dir_root))?; + + print_free_disk_space()?; + + // Proactively delete the instrumented artifacts, to avoid using them by accident in + // follow-up stages. + clear_llvm_files(env)?; + + Ok(profile) + })?; + + let llvm_bolt_profile = if env.supports_bolt() { + // Stage 3: Build BOLT instrumented LLVM + // We build a PGO optimized LLVM in this step, then instrument it with BOLT and gather BOLT profiles. + // Note that we don't remove LLVM artifacts after this step, so that they are reused in the final dist build. + // BOLT instrumentation is performed "on-the-fly" when the LLVM library is copied to the sysroot of rustc, + // therefore the LLVM artifacts on disk are not "tainted" with BOLT instrumentation and they can be reused. + timer.section("Stage 3 (LLVM BOLT)", |stage| { + stage.section("Build BOLT instrumented LLVM", |stage| { + Bootstrap::build(env) + .llvm_bolt_instrument() + .llvm_pgo_optimize(&llvm_pgo_profile) + .avoid_rustc_rebuild() + .run(stage) + })?; + + let profile = stage.section("Gather profiles", |_| gather_llvm_bolt_profiles(env))?; + print_free_disk_space()?; + + // LLVM is not being cleared here, we want to reuse the previous PGO-optimized build + + Ok(Some(profile)) + })? + } else { + None + }; + + let mut dist = Bootstrap::dist(env, &dist_args) + .llvm_pgo_optimize(&llvm_pgo_profile) + .rustc_pgo_optimize(&rustc_pgo_profile) + .avoid_rustc_rebuild(); + + if let Some(llvm_bolt_profile) = llvm_bolt_profile { + dist = dist.llvm_bolt_optimize(&llvm_bolt_profile); + } + + // Final stage: Assemble the dist artifacts + // The previous PGO optimized rustc build and PGO optimized LLVM builds should be reused. + timer.section("Stage 4 (final build)", |stage| dist.run(stage))?; + + // After dist has finished, run a subset of the test suite on the optimized artifacts to discover + // possible regressions. + // The tests are not executed for try builds, which can be in various broken states, so we don't + // want to gatekeep them with tests. + if !is_try_build() { + timer.section("Run tests", |_| run_tests(env))?; + } + + Ok(()) +} + +fn main() -> anyhow::Result<()> { + // Make sure that we get backtraces for easier debugging in CI + std::env::set_var("RUST_BACKTRACE", "1"); + + env_logger::builder() + .filter_level(LevelFilter::Info) + .format_timestamp_millis() + .parse_default_env() + .init(); + + let mut build_args: Vec = std::env::args().skip(1).collect(); + log::info!("Running optimized build pipeline with args `{}`", build_args.join(" ")); + log::info!("Environment values\n{}", format_env_variables()); + + if let Ok(config) = std::fs::read_to_string("config.toml") { + log::info!("Contents of `config.toml`:\n{config}"); + } + + // Skip components that are not needed for try builds to speed them up + if is_try_build() { + log::info!("Skipping building of unimportant components for a try build"); + for target in [ + "rust-docs", + "rustc-docs", + "rust-docs-json", + "rust-analyzer", + "rustc-src", + "clippy", + "miri", + "rustfmt", + ] { + build_args.extend(["--exclude".to_string(), target.to_string()]); + } + } + + let mut timer = Timer::new(); + let env = create_environment(); + + let result = execute_pipeline(env.as_ref(), &mut timer, build_args); + log::info!("Timer results\n{}", timer.format_stats()); + + print_free_disk_space()?; + + result.context("Optimized build pipeline has failed") +} diff --git a/src/tools/opt-dist/src/metrics.rs b/src/tools/opt-dist/src/metrics.rs new file mode 100644 index 0000000000000..cabe07eda329f --- /dev/null +++ b/src/tools/opt-dist/src/metrics.rs @@ -0,0 +1,106 @@ +use crate::timer::TimerSection; +use build_helper::metrics::{JsonNode, JsonRoot}; +use camino::Utf8Path; +use std::time::Duration; + +#[derive(Clone, Debug)] +pub struct BuildStep { + r#type: String, + children: Vec, + duration: Duration, +} + +impl BuildStep { + pub fn find_all_by_type(&self, r#type: &str) -> Vec<&BuildStep> { + let mut result = Vec::new(); + self.find_by_type(r#type, &mut result); + result + } + fn find_by_type<'a>(&'a self, r#type: &str, result: &mut Vec<&'a BuildStep>) { + if self.r#type == r#type { + result.push(self); + } + for child in &self.children { + child.find_by_type(r#type, result); + } + } +} + +/// Loads the metrics of the most recent bootstrap execution from a metrics.json file. +pub fn load_metrics(path: &Utf8Path) -> anyhow::Result { + let content = std::fs::read(path.as_std_path())?; + let mut metrics = serde_json::from_slice::(&content)?; + let invocation = metrics + .invocations + .pop() + .ok_or_else(|| anyhow::anyhow!("No bootstrap invocation found in metrics file"))?; + + fn parse(node: JsonNode) -> Option { + match node { + JsonNode::RustbuildStep { + type_: kind, + children, + duration_excluding_children_sec, + .. + } => { + let children: Vec<_> = children.into_iter().filter_map(parse).collect(); + let children_duration = children.iter().map(|c| c.duration).sum::(); + Some(BuildStep { + r#type: kind.to_string(), + children, + duration: children_duration + + Duration::from_secs_f64(duration_excluding_children_sec), + }) + } + JsonNode::TestSuite(_) => None, + } + } + + let duration = Duration::from_secs_f64(invocation.duration_including_children_sec); + let children: Vec<_> = invocation.children.into_iter().filter_map(parse).collect(); + Ok(BuildStep { r#type: "root".to_string(), children, duration }) +} + +/// Logs the individual metrics in a table and add Rustc and LLVM durations to the passed +/// timer. +pub fn record_metrics(metrics: &BuildStep, timer: &mut TimerSection) { + let llvm_steps = metrics.find_all_by_type("bootstrap::llvm::Llvm"); + let llvm_duration: Duration = llvm_steps.into_iter().map(|s| s.duration).sum(); + + let rustc_steps = metrics.find_all_by_type("bootstrap::compile::Rustc"); + let rustc_duration: Duration = rustc_steps.into_iter().map(|s| s.duration).sum(); + + // The LLVM step is part of the Rustc step + let rustc_duration = rustc_duration.saturating_sub(llvm_duration); + + if !llvm_duration.is_zero() { + timer.add_duration("LLVM", llvm_duration); + } + if !rustc_duration.is_zero() { + timer.add_duration("Rustc", rustc_duration); + } + + log_metrics(metrics); +} + +fn log_metrics(metrics: &BuildStep) { + use std::fmt::Write; + + let mut substeps: Vec<(u32, &BuildStep)> = Vec::new(); + + fn visit<'a>(step: &'a BuildStep, level: u32, substeps: &mut Vec<(u32, &'a BuildStep)>) { + substeps.push((level, step)); + for child in &step.children { + visit(child, level + 1, substeps); + } + } + + visit(metrics, 0, &mut substeps); + + let mut output = String::new(); + for (level, step) in substeps { + let label = format!("{}{}", ".".repeat(level as usize), step.r#type); + writeln!(output, "{label:<65}{:>8.2}s", step.duration.as_secs_f64()).unwrap(); + } + log::info!("Build step durations\n{output}"); +} diff --git a/src/tools/opt-dist/src/tests.rs b/src/tools/opt-dist/src/tests.rs new file mode 100644 index 0000000000000..6b35b13e58624 --- /dev/null +++ b/src/tools/opt-dist/src/tests.rs @@ -0,0 +1,101 @@ +use crate::environment::Environment; +use crate::exec::cmd; +use crate::utils::io::{copy_directory, unpack_archive}; +use anyhow::Context; +use camino::Utf8PathBuf; + +/// Run tests on optimized dist artifacts. +pub fn run_tests(env: &dyn Environment) -> anyhow::Result<()> { + // After `dist` is executed, we extract its archived components into a sysroot directory, + // and then use that extracted rustc as a stage0 compiler. + // Then we run a subset of tests using that compiler, to have a basic smoke test which checks + // whether the optimization pipeline hasn't broken something. + let build_dir = env.build_root().join("build"); + let dist_dir = build_dir.join("dist"); + let unpacked_dist_dir = build_dir.join("unpacked-dist"); + std::fs::create_dir_all(&unpacked_dist_dir)?; + + let extract_dist_dir = |name: &str| -> anyhow::Result { + unpack_archive(&dist_dir.join(format!("{name}.tar.xz")), &unpacked_dist_dir)?; + let extracted_path = unpacked_dist_dir.join(name); + assert!(extracted_path.is_dir()); + Ok(extracted_path) + }; + let host_triple = env.host_triple(); + + // Extract rustc, libstd, cargo and src archives to create the optimized sysroot + let rustc_dir = extract_dist_dir(&format!("rustc-nightly-{host_triple}"))?.join("rustc"); + let libstd_dir = extract_dist_dir(&format!("rust-std-nightly-{host_triple}"))? + .join(format!("rust-std-{host_triple}")); + let cargo_dir = extract_dist_dir(&format!("cargo-nightly-{host_triple}"))?.join("cargo"); + let extracted_src_dir = extract_dist_dir("rust-src-nightly")?.join("rust-src"); + + // We need to manually copy libstd to the extracted rustc sysroot + copy_directory( + &libstd_dir.join("lib").join("rustlib").join(&host_triple).join("lib"), + &rustc_dir.join("lib").join("rustlib").join(&host_triple).join("lib"), + )?; + + // Extract sources - they aren't in the `rustc-nightly-{host}` tarball, so we need to manually copy libstd + // sources to the extracted sysroot. We need sources available so that `-Zsimulate-remapped-rust-src-base` + // works correctly. + copy_directory( + &extracted_src_dir.join("lib").join("rustlib").join("src"), + &rustc_dir.join("lib").join("rustlib").join("src"), + )?; + + let rustc_path = rustc_dir.join("bin").join(format!("rustc{}", env.executable_extension())); + assert!(rustc_path.is_file()); + let cargo_path = cargo_dir.join("bin").join(format!("cargo{}", env.executable_extension())); + assert!(cargo_path.is_file()); + + // Specify path to a LLVM config so that LLVM is not rebuilt. + // It doesn't really matter which LLVM config we choose, because no sysroot will be compiled. + let llvm_config = env + .build_artifacts() + .join("llvm") + .join("bin") + .join(format!("llvm-config{}", env.executable_extension())); + assert!(llvm_config.is_file()); + + let config_content = format!( + r#"profile = "user" +changelog-seen = 2 + +[build] +rustc = "{rustc}" +cargo = "{cargo}" + +[target.{host_triple}] +llvm-config = "{llvm_config}" +"#, + rustc = rustc_path.to_string().replace('\\', "/"), + cargo = cargo_path.to_string().replace('\\', "/"), + llvm_config = llvm_config.to_string().replace('\\', "/") + ); + log::info!("Using following `config.toml` for running tests:\n{config_content}"); + + // Simulate a stage 0 compiler with the extracted optimized dist artifacts. + std::fs::write("config.toml", config_content)?; + + let x_py = env.checkout_path().join("x.py"); + let mut args = vec![ + env.python_binary(), + x_py.as_str(), + "test", + "--stage", + "0", + "tests/assembly", + "tests/codegen", + "tests/codegen-units", + "tests/incremental", + "tests/mir-opt", + "tests/pretty", + "tests/run-pass-valgrind", + "tests/ui", + ]; + for test_path in env.skipped_tests() { + args.extend(["--exclude", test_path]); + } + cmd(&args).env("COMPILETEST_FORCE_STAGE0", "1").run().context("Cannot execute tests") +} diff --git a/src/tools/opt-dist/src/timer.rs b/src/tools/opt-dist/src/timer.rs new file mode 100644 index 0000000000000..2b29ba8d59f0f --- /dev/null +++ b/src/tools/opt-dist/src/timer.rs @@ -0,0 +1,167 @@ +use std::ops::{Deref, DerefMut}; +use std::time::{Duration, SystemTime}; + +pub struct Timer { + root: TimerSection, +} + +impl Timer { + pub fn new() -> Self { + Timer { root: TimerSection::new(None) } + } + + pub fn format_stats(&self) -> String { + use std::fmt::Write; + + let mut items = Vec::new(); + for (name, child) in &self.root.children { + match child { + SectionEntry::SubSection(section) => { + section.collect_levels(0, name, &mut items); + } + SectionEntry::Duration(duration) => items.push((0, name, *duration)), + } + } + + let rows: Vec<(String, Duration)> = items + .into_iter() + .map(|(level, name, duration)| (format!("{}{name}:", " ".repeat(level)), duration)) + .collect(); + + let total_duration = self.total_duration(); + let total_duration_label = "Total duration:".to_string(); + + const SPACE_AFTER_LABEL: usize = 2; + let max_label_length = 16.max(rows.iter().map(|(label, _)| label.len()).max().unwrap_or(0)) + + SPACE_AFTER_LABEL; + + let table_width = max_label_length + 23; + let divider = "-".repeat(table_width); + + let mut output = String::new(); + writeln!(output, "{divider}").unwrap(); + for (label, duration) in rows { + let pct = (duration.as_millis() as f64 / total_duration.as_millis() as f64) * 100.0; + let duration_fmt = format!("{:>12.2}s ({pct:>5.2}%)", duration.as_secs_f64()); + writeln!(output, "{label:<0$} {duration_fmt}", max_label_length).unwrap(); + } + output.push('\n'); + + let total_duration = Duration::new(total_duration.as_secs(), 0); + let total_duration = format!( + "{:>1$}", + humantime::format_duration(total_duration).to_string(), + table_width - total_duration_label.len() + ); + writeln!(output, "{total_duration_label}{total_duration}").unwrap(); + + writeln!(output, "{divider}").unwrap(); + output + } +} + +impl Deref for Timer { + type Target = TimerSection; + + fn deref(&self) -> &Self::Target { + &self.root + } +} + +impl DerefMut for Timer { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.root + } +} + +pub struct TimerSection { + name: Option, + children: Vec<(String, SectionEntry)>, + duration_excluding_children: Duration, +} + +impl TimerSection { + pub fn new(name: Option) -> Self { + TimerSection { + name, + children: Default::default(), + duration_excluding_children: Duration::ZERO, + } + } + + pub fn section anyhow::Result, R>( + &mut self, + name: &str, + func: F, + ) -> anyhow::Result { + let full_name = match &self.name { + Some(current_name) => { + format!("{current_name} > {name}") + } + None => name.to_string(), + }; + log::info!("Section `{full_name}` starts"); + let mut child = TimerSection { + name: Some(full_name.clone()), + children: Default::default(), + duration_excluding_children: Duration::ZERO, + }; + + let start = SystemTime::now(); + let result = func(&mut child); + let duration = start.elapsed().unwrap(); + + let msg = match result { + Ok(_) => "OK", + Err(_) => "FAIL", + }; + + child.duration_excluding_children = duration.saturating_sub(child.total_duration()); + + log::info!("Section `{full_name}` ended: {msg} ({:.2}s)`", duration.as_secs_f64()); + self.children.push((name.to_string(), SectionEntry::SubSection(child))); + result + } + + pub fn add_duration(&mut self, name: &str, duration: Duration) { + self.children.push((name.to_string(), SectionEntry::Duration(duration))); + } + + fn total_duration(&self) -> Duration { + self.duration_excluding_children + + self.children.iter().map(|(_, child)| child.total_duration()).sum::() + } + + fn collect_levels<'a>( + &'a self, + level: usize, + name: &'a str, + items: &mut Vec<(usize, &'a str, Duration)>, + ) { + items.push((level, name, self.total_duration())); + for (name, child) in &self.children { + match &child { + SectionEntry::Duration(duration) => { + items.push((level + 1, name, *duration)); + } + SectionEntry::SubSection(section) => { + section.collect_levels(level + 1, name, items); + } + } + } + } +} + +enum SectionEntry { + Duration(Duration), + SubSection(TimerSection), +} + +impl SectionEntry { + fn total_duration(&self) -> Duration { + match self { + SectionEntry::Duration(duration) => *duration, + SectionEntry::SubSection(timer) => timer.total_duration(), + } + } +} diff --git a/src/tools/opt-dist/src/training.rs b/src/tools/opt-dist/src/training.rs new file mode 100644 index 0000000000000..10f4a60369575 --- /dev/null +++ b/src/tools/opt-dist/src/training.rs @@ -0,0 +1,202 @@ +use crate::environment::Environment; +use crate::exec::{cmd, CmdBuilder}; +use crate::utils::io::{count_files, delete_directory}; +use anyhow::Context; +use camino::{Utf8Path, Utf8PathBuf}; +use humansize::BINARY; + +const LLVM_PGO_CRATES: &[&str] = &[ + "syn-1.0.89", + "cargo-0.60.0", + "serde-1.0.136", + "ripgrep-13.0.0", + "regex-1.5.5", + "clap-3.1.6", + "hyper-0.14.18", +]; + +const RUSTC_PGO_CRATES: &[&str] = &[ + "externs", + "ctfe-stress-5", + "cargo-0.60.0", + "token-stream-stress", + "match-stress", + "tuple-stress", + "diesel-1.4.8", + "bitmaps-3.1.0", +]; + +const LLVM_BOLT_CRATES: &[&str] = LLVM_PGO_CRATES; + +fn init_compiler_benchmarks( + env: &dyn Environment, + profiles: &[&str], + scenarios: &[&str], + crates: &[&str], +) -> CmdBuilder { + // Run rustc-perf benchmarks + // Benchmark using profile_local with eprintln, which essentially just means + // don't actually benchmark -- just make sure we run rustc a bunch of times. + cmd(&[ + env.cargo_stage_0().as_str(), + "run", + "-p", + "collector", + "--bin", + "collector", + "--", + "profile_local", + "eprintln", + env.rustc_stage_2().as_str(), + "--id", + "Test", + "--cargo", + env.cargo_stage_0().as_str(), + "--profiles", + profiles.join(",").as_str(), + "--scenarios", + scenarios.join(",").as_str(), + "--include", + crates.join(",").as_str(), + ]) + .env("RUST_LOG", "collector=debug") + .env("RUSTC", env.rustc_stage_0().as_str()) + .env("RUSTC_BOOTSTRAP", "1") + .workdir(&env.rustc_perf_dir()) +} + +fn merge_llvm_profiles( + env: &dyn Environment, + merged_path: &Utf8Path, + profile_dir: &Utf8Path, +) -> anyhow::Result<()> { + cmd(&[ + env.downloaded_llvm_dir().join("bin/llvm-profdata").as_str(), + "merge", + "-o", + merged_path.as_str(), + profile_dir.as_str(), + ]) + .run() + .context("Cannot merge LLVM profiles")?; + Ok(()) +} + +fn log_profile_stats( + name: &str, + merged_profile: &Utf8Path, + profile_root: &Utf8Path, +) -> anyhow::Result<()> { + log::info!("{name} PGO statistics"); + log::info!( + "{merged_profile}: {}", + humansize::format_size(std::fs::metadata(merged_profile.as_std_path())?.len(), BINARY) + ); + log::info!( + "{profile_root}: {}", + humansize::format_size(fs_extra::dir::get_size(profile_root.as_std_path())?, BINARY) + ); + log::info!("Profile file count: {}", count_files(profile_root)?); + Ok(()) +} + +pub struct LlvmPGOProfile(pub Utf8PathBuf); + +pub fn gather_llvm_profiles( + env: &dyn Environment, + profile_root: &Utf8Path, +) -> anyhow::Result { + log::info!("Running benchmarks with PGO instrumented LLVM"); + + init_compiler_benchmarks(env, &["Debug", "Opt"], &["Full"], LLVM_PGO_CRATES) + .run() + .context("Cannot gather LLVM PGO profiles")?; + + let merged_profile = env.opt_artifacts().join("llvm-pgo.profdata"); + log::info!("Merging LLVM PGO profiles to {merged_profile}"); + + merge_llvm_profiles(env, &merged_profile, profile_root)?; + log_profile_stats("LLVM", &merged_profile, profile_root)?; + + // We don't need the individual .profraw files now that they have been merged + // into a final .profdata + delete_directory(profile_root)?; + + Ok(LlvmPGOProfile(merged_profile)) +} + +pub struct RustcPGOProfile(pub Utf8PathBuf); + +pub fn gather_rustc_profiles( + env: &dyn Environment, + profile_root: &Utf8Path, +) -> anyhow::Result { + log::info!("Running benchmarks with PGO instrumented rustc"); + + // The profile data is written into a single filepath that is being repeatedly merged when each + // rustc invocation ends. Empirically, this can result in some profiling data being lost. That's + // why we override the profile path to include the PID. This will produce many more profiling + // files, but the resulting profile will produce a slightly faster rustc binary. + let profile_template = profile_root.join("default_%m_%p.profraw"); + + // Here we're profiling the `rustc` frontend, so we also include `Check`. + // The benchmark set includes various stress tests that put the frontend under pressure. + init_compiler_benchmarks(env, &["Check", "Debug", "Opt"], &["All"], RUSTC_PGO_CRATES) + .env("LLVM_PROFILE_FILE", profile_template.as_str()) + .run() + .context("Cannot gather rustc PGO profiles")?; + + let merged_profile = env.opt_artifacts().join("rustc-pgo.profdata"); + log::info!("Merging Rustc PGO profiles to {merged_profile}"); + + merge_llvm_profiles(env, &merged_profile, profile_root)?; + log_profile_stats("Rustc", &merged_profile, profile_root)?; + + // We don't need the individual .profraw files now that they have been merged + // into a final .profdata + delete_directory(profile_root)?; + + Ok(RustcPGOProfile(merged_profile)) +} + +pub struct LlvmBoltProfile(pub Utf8PathBuf); + +pub fn gather_llvm_bolt_profiles(env: &dyn Environment) -> anyhow::Result { + log::info!("Running benchmarks with BOLT instrumented LLVM"); + + init_compiler_benchmarks(env, &["Check", "Debug", "Opt"], &["Full"], LLVM_BOLT_CRATES) + .run() + .context("Cannot gather LLVM BOLT profiles")?; + + let merged_profile = env.opt_artifacts().join("bolt.profdata"); + let profile_root = Utf8PathBuf::from("/tmp/prof.fdata"); + log::info!("Merging LLVM BOLT profiles to {merged_profile}"); + + let profiles: Vec<_> = + glob::glob(&format!("{profile_root}*"))?.into_iter().collect::, _>>()?; + + let mut merge_args = vec!["merge-fdata"]; + merge_args.extend(profiles.iter().map(|p| p.to_str().unwrap())); + + cmd(&merge_args) + .redirect_output(merged_profile.clone()) + .run() + .context("Cannot merge BOLT profiles")?; + + log::info!("LLVM BOLT statistics"); + log::info!( + "{merged_profile}: {}", + humansize::format_size(std::fs::metadata(merged_profile.as_std_path())?.len(), BINARY) + ); + + let size = profiles + .iter() + .map(|p| std::fs::metadata(p).map(|metadata| metadata.len())) + .collect::, _>>()? + .into_iter() + .sum::(); + log::info!("{profile_root}: {}", humansize::format_size(size, BINARY)); + log::info!("Profile file count: {}", profiles.len()); + + Ok(LlvmBoltProfile(merged_profile)) +} diff --git a/src/tools/opt-dist/src/utils/io.rs b/src/tools/opt-dist/src/utils/io.rs new file mode 100644 index 0000000000000..43546e5fcfa67 --- /dev/null +++ b/src/tools/opt-dist/src/utils/io.rs @@ -0,0 +1,48 @@ +use anyhow::Context; +use camino::Utf8Path; +use fs_extra::dir::CopyOptions; +use std::fs::File; + +/// Delete and re-create the directory. +pub fn reset_directory(path: &Utf8Path) -> anyhow::Result<()> { + log::info!("Resetting directory {path}"); + let _ = std::fs::remove_dir(path); + std::fs::create_dir_all(path)?; + Ok(()) +} + +pub fn copy_directory(src: &Utf8Path, dst: &Utf8Path) -> anyhow::Result<()> { + log::info!("Copying directory {src} to {dst}"); + fs_extra::dir::copy(src, dst, &CopyOptions::default().copy_inside(true))?; + Ok(()) +} + +#[allow(unused)] +pub fn move_directory(src: &Utf8Path, dst: &Utf8Path) -> anyhow::Result<()> { + log::info!("Moving directory {src} to {dst}"); + fs_extra::dir::move_dir(src, dst, &CopyOptions::default().content_only(true))?; + Ok(()) +} + +/// Counts all children of a directory (non-recursively). +pub fn count_files(dir: &Utf8Path) -> anyhow::Result { + Ok(std::fs::read_dir(dir)?.count() as u64) +} + +pub fn delete_directory(path: &Utf8Path) -> anyhow::Result<()> { + log::info!("Deleting directory `{path}`"); + std::fs::remove_dir_all(path.as_std_path()) + .context(format!("Cannot remove directory {path}"))?; + Ok(()) +} + +pub fn unpack_archive(path: &Utf8Path, dest_dir: &Utf8Path) -> anyhow::Result<()> { + log::info!("Unpacking directory `{path}` into `{dest_dir}`"); + + assert!(path.as_str().ends_with(".tar.xz")); + let file = File::open(path.as_std_path())?; + let file = xz::read::XzDecoder::new(file); + let mut archive = tar::Archive::new(file); + archive.unpack(dest_dir.as_std_path())?; + Ok(()) +} diff --git a/src/tools/opt-dist/src/utils/mod.rs b/src/tools/opt-dist/src/utils/mod.rs new file mode 100644 index 0000000000000..9305d4989aa76 --- /dev/null +++ b/src/tools/opt-dist/src/utils/mod.rs @@ -0,0 +1,36 @@ +pub mod io; + +use crate::environment::Environment; +use crate::utils::io::delete_directory; +use humansize::BINARY; +use sysinfo::{DiskExt, RefreshKind, System, SystemExt}; + +pub fn format_env_variables() -> String { + let vars = std::env::vars().map(|(key, value)| format!("{key}={value}")).collect::>(); + vars.join("\n") +} + +pub fn print_free_disk_space() -> anyhow::Result<()> { + let sys = System::new_with_specifics(RefreshKind::default().with_disks_list().with_disks()); + let available_space: u64 = sys.disks().iter().map(|d| d.available_space()).sum(); + let total_space: u64 = sys.disks().iter().map(|d| d.total_space()).sum(); + let used_space = total_space - available_space; + + log::info!( + "Free disk space: {} out of total {} ({:.2}% used)", + humansize::format_size(available_space, BINARY), + humansize::format_size(total_space, BINARY), + (used_space as f64 / total_space as f64) * 100.0 + ); + Ok(()) +} + +pub fn clear_llvm_files(env: &dyn Environment) -> anyhow::Result<()> { + // Bootstrap currently doesn't support rebuilding LLVM when PGO options + // change (or any other llvm-related options); so just clear out the relevant + // directories ourselves. + log::info!("Clearing LLVM build files"); + delete_directory(&env.build_artifacts().join("llvm"))?; + delete_directory(&env.build_artifacts().join("lld"))?; + Ok(()) +} diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index ecc84c1618c0f..2c237c418b1ad 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -40,10 +40,12 @@ const EXCEPTIONS: &[(&str, &str)] = &[ ("ar_archive_writer", "Apache-2.0 WITH LLVM-exception"), // rustc ("colored", "MPL-2.0"), // rustfmt ("dissimilar", "Apache-2.0"), // rustdoc, rustc_lexer (few tests) via expect-test, (dev deps) + ("encoding_rs", "(Apache-2.0 OR MIT) AND BSD-3-Clause"), // opt-dist ("fluent-langneg", "Apache-2.0"), // rustc (fluent translations) ("fortanix-sgx-abi", "MPL-2.0"), // libstd but only for `sgx` target. FIXME: this dependency violates the documentation comment above. ("instant", "BSD-3-Clause"), // rustc_driver/tracing-subscriber/parking_lot ("mdbook", "MPL-2.0"), // mdbook + ("openssl", "Apache-2.0"), // opt-dist ("ryu", "Apache-2.0 OR BSL-1.0"), // cargo/... (because of serde) ("self_cell", "Apache-2.0"), // rustc (fluent translations) ("snap", "BSD-3-Clause"), // rustc @@ -142,6 +144,8 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "elsa", "ena", "equivalent", + "errno", + "errno-dragonfly", "expect-test", "fallible-iterator", // dependency of `thorin` "fastrand", diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs index 55bf38110a6d5..3ed587caadc6b 100644 --- a/src/tools/tidy/src/ui_tests.rs +++ b/src/tools/tidy/src/ui_tests.rs @@ -11,7 +11,7 @@ use std::path::{Path, PathBuf}; const ENTRY_LIMIT: usize = 900; // FIXME: The following limits should be reduced eventually. const ISSUES_ENTRY_LIMIT: usize = 1896; -const ROOT_ENTRY_LIMIT: usize = 870; +const ROOT_ENTRY_LIMIT: usize = 871; const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[ "rs", // test source files diff --git a/src/version b/src/version index 0834888f55808..5e3a42566267c 100644 --- a/src/version +++ b/src/version @@ -1 +1 @@ -1.72.0 +1.73.0 diff --git a/tests/assembly/stack-protector/stack-protector-heuristics-effect.rs b/tests/assembly/stack-protector/stack-protector-heuristics-effect.rs index 011a253c6ff61..a7c9e4845c70a 100644 --- a/tests/assembly/stack-protector/stack-protector-heuristics-effect.rs +++ b/tests/assembly/stack-protector/stack-protector-heuristics-effect.rs @@ -3,6 +3,7 @@ // ignore-macos slightly different policy on stack protection of arrays // ignore-windows stack check code uses different function names // ignore-nvptx64 stack protector is not supported +// ignore-wasm32-bare // [all] compile-flags: -Z stack-protector=all // [strong] compile-flags: -Z stack-protector=strong // [basic] compile-flags: -Z stack-protector=basic diff --git a/tests/assembly/wasm_exceptions.rs b/tests/assembly/wasm_exceptions.rs new file mode 100644 index 0000000000000..b7d20881b624f --- /dev/null +++ b/tests/assembly/wasm_exceptions.rs @@ -0,0 +1,60 @@ +// only-wasm32-bare +// assembly-output: emit-asm +// compile-flags: -C target-feature=+exception-handling +// compile-flags: -C panic=unwind +// compile-flags: -C llvm-args=-wasm-enable-eh + +#![crate_type = "lib"] +#![feature(core_intrinsics)] +#![feature(rustc_attrs)] + +extern { + fn may_panic(); + + #[rustc_nounwind] + fn log_number(number: usize); +} + +struct LogOnDrop; + +impl Drop for LogOnDrop { + fn drop(&mut self) { + unsafe { log_number(0); } + } +} + +// CHECK-LABEL: test_cleanup: +#[no_mangle] +pub fn test_cleanup() { + let _log_on_drop = LogOnDrop; + unsafe { may_panic(); } + + // CHECK-NOT: call + // CHECK: try + // CHECK: call may_panic + // CHECK: catch_all + // CHECK: rethrow + // CHECK: end_try +} + +// CHECK-LABEL: test_rtry: +#[no_mangle] +pub fn test_rtry() { + unsafe { + core::intrinsics::r#try(|_| { + may_panic(); + }, core::ptr::null_mut(), |data, exception| { + log_number(data as usize); + log_number(exception as usize); + }); + } + + // CHECK-NOT: call + // CHECK: try + // CHECK: call may_panic + // CHECK: catch + // CHECK: call log_number + // CHECK: call log_number + // CHECK-NOT: rethrow + // CHECK: end_try +} diff --git a/tests/codegen/array-codegen.rs b/tests/codegen/array-codegen.rs index 98488eb92ee02..71acd781549bc 100644 --- a/tests/codegen/array-codegen.rs +++ b/tests/codegen/array-codegen.rs @@ -6,10 +6,10 @@ // CHECK-LABEL: @array_load #[no_mangle] pub fn array_load(a: &[u8; 4]) -> [u8; 4] { - // CHECK: %0 = alloca [4 x i8], align 1 + // CHECK: %_0 = alloca [4 x i8], align 1 // CHECK: %[[TEMP1:.+]] = load <4 x i8>, ptr %a, align 1 - // CHECK: store <4 x i8> %[[TEMP1]], ptr %0, align 1 - // CHECK: %[[TEMP2:.+]] = load i32, ptr %0, align 1 + // CHECK: store <4 x i8> %[[TEMP1]], ptr %_0, align 1 + // CHECK: %[[TEMP2:.+]] = load i32, ptr %_0, align 1 // CHECK: ret i32 %[[TEMP2]] *a } diff --git a/tests/codegen/avr/avr-func-addrspace.rs b/tests/codegen/avr/avr-func-addrspace.rs index bc11e1081244a..83baae9e432dd 100644 --- a/tests/codegen/avr/avr-func-addrspace.rs +++ b/tests/codegen/avr/avr-func-addrspace.rs @@ -116,7 +116,7 @@ pub enum Either { A(T), B(U) } // with the `ptr` field representing both `&i32` and `fn()` depending on the variant. // This is incorrect, because `fn()` should be `ptr addrspace(1)`, not `ptr`. -// CHECK: define{{.+}}void @should_not_combine_addrspace({{.+\*|ptr}}{{.+}}sret{{.+}}%0, {{.+\*|ptr}}{{.+}}%x) +// CHECK: define{{.+}}void @should_not_combine_addrspace({{.+\*|ptr}}{{.+}}sret{{.+}}%_0, {{.+\*|ptr}}{{.+}}%x) #[no_mangle] #[inline(never)] pub fn should_not_combine_addrspace(x: Either<&i32, fn()>) -> Either<&i32, fn()> { diff --git a/tests/codegen/consts.rs b/tests/codegen/consts.rs index fc2badc417c21..810da581ce9a9 100644 --- a/tests/codegen/consts.rs +++ b/tests/codegen/consts.rs @@ -1,4 +1,5 @@ // compile-flags: -C no-prepopulate-passes +// min-llvm-version: 15.0 (for opaque pointers) #![crate_type = "lib"] @@ -42,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: memcpy.{{.+}}({{i8\*|ptr}} align 2 %{{[0-9]+}}, {{i8\*|ptr}} align 2 {{.*}}[[LOW_HIGH]]{{.*}}, i{{(32|64)}} 8, i1 false) + // CHECK: memcpy.{{.+}}(ptr align 2 %_0, ptr align 2 {{.*}}[[LOW_HIGH]]{{.*}}, i{{(32|64)}} 8, i1 false) *&E::A(0) } @@ -50,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: memcpy.{{.+}}({{i8\*|ptr}} align 4 %{{[0-9]+}}, {{i8\*|ptr}} align 4 {{.*}}[[LOW_HIGH]]{{.*}}, i{{(32|64)}} 8, i1 false) + // CHECK: memcpy.{{.+}}(ptr align 4 %_0, ptr align 4 {{.*}}[[LOW_HIGH]]{{.*}}, i{{(32|64)}} 8, i1 false) *&E::A(0) } diff --git a/tests/codegen/enum-match.rs b/tests/codegen/enum-match.rs index 36c6be19012f1..5548cd251478b 100644 --- a/tests/codegen/enum-match.rs +++ b/tests/codegen/enum-match.rs @@ -15,7 +15,7 @@ pub enum Enum0 { // CHECK-NEXT: start: // CHECK-NEXT: %1 = icmp eq i8 %0, 2 // CHECK-NEXT: %2 = and i8 %0, 1 -// CHECK-NEXT: %.0 = select i1 %1, i8 13, i8 %2 +// CHECK-NEXT: %_0.0 = select i1 %1, i8 13, i8 %2 #[no_mangle] pub fn match0(e: Enum0) -> u8 { use Enum0::*; diff --git a/tests/codegen/fewer-names.rs b/tests/codegen/fewer-names.rs index a09c795924cd2..df1080bff2b1c 100644 --- a/tests/codegen/fewer-names.rs +++ b/tests/codegen/fewer-names.rs @@ -13,8 +13,8 @@ pub fn sum(x: u32, y: u32) -> u32 { // NO-LABEL: define{{.*}}i32 @sum(i32 noundef %x, i32 noundef %y) // NO-NEXT: start: - // NO-NEXT: %0 = add i32 %y, %x - // NO-NEXT: ret i32 %0 + // NO-NEXT: %z = add i32 %y, %x + // NO-NEXT: ret i32 %z let z = x + y; z } diff --git a/tests/codegen/function-arguments-noopt.rs b/tests/codegen/function-arguments-noopt.rs index 0c62e0d35e36d..35f31eba3b11e 100644 --- a/tests/codegen/function-arguments-noopt.rs +++ b/tests/codegen/function-arguments-noopt.rs @@ -42,7 +42,7 @@ pub fn borrow_call(x: &i32, f: fn(&i32) -> &i32) -> &i32 { f(x) } -// CHECK: void @struct_({{%S\*|ptr}} sret(%S){{( %0)?}}, {{%S\*|ptr}} %x) +// CHECK: void @struct_({{%S\*|ptr}} sret(%S){{( %_0)?}}, {{%S\*|ptr}} %x) #[no_mangle] pub fn struct_(x: S) -> S { x @@ -51,7 +51,7 @@ pub fn struct_(x: S) -> S { // CHECK-LABEL: @struct_call #[no_mangle] pub fn struct_call(x: S, f: fn(S) -> S) -> S { - // CHECK: call void %f({{%S\*|ptr}} sret(%S){{( %0)?}}, {{%S\*|ptr}} %{{.+}}) + // CHECK: call void %f({{%S\*|ptr}} sret(%S){{( %_0)?}}, {{%S\*|ptr}} %{{.+}}) f(x) } diff --git a/tests/codegen/function-arguments.rs b/tests/codegen/function-arguments.rs index d6f019016a5a7..ccf4a5de327e2 100644 --- a/tests/codegen/function-arguments.rs +++ b/tests/codegen/function-arguments.rs @@ -188,7 +188,7 @@ pub fn notunpin_box(x: Box) -> Box { x } -// CHECK: @struct_return({{%S\*|ptr}} noalias nocapture noundef sret(%S) dereferenceable(32){{( %0)?}}) +// CHECK: @struct_return({{%S\*|ptr}} noalias nocapture noundef sret(%S) dereferenceable(32){{( %_0)?}}) #[no_mangle] pub fn struct_return() -> S { S { diff --git a/tests/codegen/intrinsics/transmute-niched.rs b/tests/codegen/intrinsics/transmute-niched.rs index 69e9b1d12062e..fffc24a118117 100644 --- a/tests/codegen/intrinsics/transmute-niched.rs +++ b/tests/codegen/intrinsics/transmute-niched.rs @@ -169,16 +169,16 @@ pub unsafe fn check_bool_from_ordering(x: std::cmp::Ordering) -> bool { // CHECK-LABEL: @check_bool_to_ordering( #[no_mangle] pub unsafe fn check_bool_to_ordering(x: bool) -> std::cmp::Ordering { - // CHECK: %0 = zext i1 %x to i8 - // OPT: %1 = icmp ule i8 %0, 1 - // OPT: call void @llvm.assume(i1 %1) - // OPT: %2 = icmp uge i8 %0, -1 - // OPT: %3 = icmp ule i8 %0, 1 - // OPT: %4 = or i1 %2, %3 - // OPT: call void @llvm.assume(i1 %4) + // CHECK: %_0 = zext i1 %x to i8 + // OPT: %0 = icmp ule i8 %_0, 1 + // OPT: call void @llvm.assume(i1 %0) + // OPT: %1 = icmp uge i8 %_0, -1 + // OPT: %2 = icmp ule i8 %_0, 1 + // OPT: %3 = or i1 %1, %2 + // OPT: call void @llvm.assume(i1 %3) // DBG-NOT: icmp // DBG-NOT: assume - // CHECK: ret i8 %0 + // CHECK: ret i8 %_0 transmute(x) } diff --git a/tests/codegen/intrinsics/transmute-x64.rs b/tests/codegen/intrinsics/transmute-x64.rs index 99d258c62040f..168838ef4976a 100644 --- a/tests/codegen/intrinsics/transmute-x64.rs +++ b/tests/codegen/intrinsics/transmute-x64.rs @@ -11,8 +11,8 @@ use std::mem::transmute; #[no_mangle] pub unsafe fn check_sse_float_to_int(x: __m128) -> __m128i { // CHECK-NOT: alloca - // CHECK: %1 = load <4 x float>, ptr %x, align 16 - // CHECK: store <4 x float> %1, ptr %0, align 16 + // CHECK: %0 = load <4 x float>, ptr %x, align 16 + // CHECK: store <4 x float> %0, ptr %_0, align 16 transmute(x) } @@ -20,8 +20,8 @@ pub unsafe fn check_sse_float_to_int(x: __m128) -> __m128i { #[no_mangle] pub unsafe fn check_sse_pair_to_avx(x: (__m128i, __m128i)) -> __m256i { // CHECK-NOT: alloca - // CHECK: %1 = load <4 x i64>, ptr %x, align 16 - // CHECK: store <4 x i64> %1, ptr %0, align 32 + // CHECK: %0 = load <4 x i64>, ptr %x, align 16 + // CHECK: store <4 x i64> %0, ptr %_0, align 32 transmute(x) } @@ -29,7 +29,7 @@ pub unsafe fn check_sse_pair_to_avx(x: (__m128i, __m128i)) -> __m256i { #[no_mangle] pub unsafe fn check_sse_pair_from_avx(x: __m256i) -> (__m128i, __m128i) { // CHECK-NOT: alloca - // CHECK: %1 = load <4 x i64>, ptr %x, align 32 - // CHECK: store <4 x i64> %1, ptr %0, align 16 + // CHECK: %0 = load <4 x i64>, ptr %x, align 32 + // CHECK: store <4 x i64> %0, ptr %_0, align 16 transmute(x) } diff --git a/tests/codegen/intrinsics/transmute.rs b/tests/codegen/intrinsics/transmute.rs index fe42494000e17..f8c20960660de 100644 --- a/tests/codegen/intrinsics/transmute.rs +++ b/tests/codegen/intrinsics/transmute.rs @@ -8,8 +8,8 @@ #![feature(inline_const)] #![allow(unreachable_code)] -use std::mem::MaybeUninit; use std::intrinsics::{transmute, transmute_unchecked}; +use std::mem::MaybeUninit; // Some of these need custom MIR to not get removed by MIR optimizations. use std::intrinsics::mir::*; @@ -63,7 +63,7 @@ pub unsafe fn check_to_empty_array(x: [u32; 5]) -> [u32; 0] { // CHECK-NOT: trap // CHECK: call void @llvm.trap // CHECK-NOT: trap - mir!{ + mir! { { RET = CastTransmute(x); Return() @@ -78,7 +78,7 @@ pub unsafe fn check_from_empty_array(x: [u32; 0]) -> [u32; 5] { // CHECK-NOT: trap // CHECK: call void @llvm.trap // CHECK-NOT: trap - mir!{ + mir! { { RET = CastTransmute(x); Return() @@ -93,7 +93,7 @@ pub unsafe fn check_to_uninhabited(x: u16) { // CHECK-NOT: trap // CHECK: call void @llvm.trap // CHECK-NOT: trap - mir!{ + mir! { let temp: BigNever; { temp = CastTransmute(x); @@ -107,7 +107,7 @@ pub unsafe fn check_to_uninhabited(x: u16) { #[custom_mir(dialect = "runtime", phase = "optimized")] pub unsafe fn check_from_uninhabited(x: BigNever) -> u16 { // CHECK: ret i16 poison - mir!{ + mir! { { RET = CastTransmute(x); Return() @@ -122,9 +122,7 @@ pub unsafe fn check_intermediate_passthrough(x: u32) -> i32 { // CHECK: %[[TMP:.+]] = add i32 1, %x // CHECK: %[[RET:.+]] = add i32 %[[TMP]], 1 // CHECK: ret i32 %[[RET]] - unsafe { - transmute::(1 + x) + 1 - } + unsafe { transmute::(1 + x) + 1 } } // CHECK-LABEL: @check_nop_pair( @@ -134,9 +132,7 @@ pub unsafe fn check_nop_pair(x: (u8, i8)) -> (i8, u8) { // CHECK: %0 = insertvalue { i8, i8 } poison, i8 %x.0, 0 // CHECK: %1 = insertvalue { i8, i8 } %0, i8 %x.1, 1 // CHECK: ret { i8, i8 } %1 - unsafe { - transmute(x) - } + unsafe { transmute(x) } } // CHECK-LABEL: @check_to_newtype( @@ -168,9 +164,9 @@ pub unsafe fn check_aggregate_to_bool(x: Aggregate8) -> bool { // CHECK-LABEL: @check_aggregate_from_bool( #[no_mangle] pub unsafe fn check_aggregate_from_bool(x: bool) -> Aggregate8 { - // CHECK: %0 = alloca %Aggregate8, align 1 + // CHECK: %_0 = alloca %Aggregate8, align 1 // CHECK: %[[BYTE:.+]] = zext i1 %x to i8 - // CHECK: store i8 %[[BYTE]], ptr %0, align 1 + // CHECK: store i8 %[[BYTE]], ptr %_0, align 1 transmute(x) } @@ -195,8 +191,8 @@ pub unsafe fn check_byte_from_bool(x: bool) -> u8 { // CHECK-LABEL: @check_to_pair( #[no_mangle] pub unsafe fn check_to_pair(x: u64) -> Option { - // CHECK: %0 = alloca { i32, i32 }, align 4 - // CHECK: store i64 %x, ptr %0, align 4 + // CHECK: %_0 = alloca { i32, i32 }, align 4 + // CHECK: store i64 %x, ptr %_0, align 4 transmute(x) } @@ -207,11 +203,11 @@ pub unsafe fn check_from_pair(x: Option) -> u64 { // immediates so we can write using the destination alloca's alignment. const { assert!(std::mem::align_of::>() == 4) }; - // CHECK: %0 = alloca i64, align 8 - // CHECK: store i32 %x.0, ptr %1, align 8 - // CHECK: store i32 %x.1, ptr %2, align 4 - // CHECK: %3 = load i64, ptr %0, align 8 - // CHECK: ret i64 %3 + // CHECK: %_0 = alloca i64, align 8 + // CHECK: store i32 %x.0, ptr %0, align 8 + // CHECK: store i32 %x.1, ptr %1, align 4 + // CHECK: %2 = load i64, ptr %_0, align 8 + // CHECK: ret i64 %2 transmute(x) } @@ -219,8 +215,8 @@ pub unsafe fn check_from_pair(x: Option) -> u64 { #[no_mangle] pub unsafe fn check_to_float(x: u32) -> f32 { // CHECK-NOT: alloca - // CHECK: %0 = bitcast i32 %x to float - // CHECK: ret float %0 + // CHECK: %_0 = bitcast i32 %x to float + // CHECK: ret float %_0 transmute(x) } @@ -228,16 +224,16 @@ pub unsafe fn check_to_float(x: u32) -> f32 { #[no_mangle] pub unsafe fn check_from_float(x: f32) -> u32 { // CHECK-NOT: alloca - // CHECK: %0 = bitcast float %x to i32 - // CHECK: ret i32 %0 + // CHECK: %_0 = bitcast float %x to i32 + // CHECK: ret i32 %_0 transmute(x) } // CHECK-LABEL: @check_to_bytes( #[no_mangle] pub unsafe fn check_to_bytes(x: u32) -> [u8; 4] { - // CHECK: %0 = alloca [4 x i8], align 1 - // CHECK: store i32 %x, ptr %0, align 1 + // CHECK: %_0 = alloca [4 x i8], align 1 + // CHECK: store i32 %x, ptr %_0, align 1 transmute(x) } @@ -253,10 +249,10 @@ pub unsafe fn check_from_bytes(x: [u8; 4]) -> u32 { // CHECK-LABEL: @check_to_aggregate( #[no_mangle] pub unsafe fn check_to_aggregate(x: u64) -> Aggregate64 { - // CHECK: %0 = alloca %Aggregate64, align 4 - // CHECK: store i64 %x, ptr %0, align 4 - // CHECK: %1 = load i64, ptr %0, align 4 - // CHECK: ret i64 %1 + // CHECK: %_0 = alloca %Aggregate64, align 4 + // CHECK: store i64 %x, ptr %_0, align 4 + // CHECK: %0 = load i64, ptr %_0, align 4 + // CHECK: ret i64 %0 transmute(x) } @@ -273,7 +269,7 @@ pub unsafe fn check_from_aggregate(x: Aggregate64) -> u64 { #[no_mangle] pub unsafe fn check_long_array_less_aligned(x: [u64; 100]) -> [u16; 400] { // CHECK-NEXT: start - // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 2 %0, ptr align 8 %x, i64 800, i1 false) + // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 2 %_0, ptr align 8 %x, i64 800, i1 false) // CHECK-NEXT: ret void transmute(x) } @@ -282,7 +278,7 @@ pub unsafe fn check_long_array_less_aligned(x: [u64; 100]) -> [u16; 400] { #[no_mangle] pub unsafe fn check_long_array_more_aligned(x: [u8; 100]) -> [u32; 25] { // CHECK-NEXT: start - // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %0, ptr align 1 %x, i64 100, i1 false) + // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %_0, ptr align 1 %x, i64 100, i1 false) // CHECK-NEXT: ret void transmute(x) } @@ -301,8 +297,8 @@ pub unsafe fn check_pair_with_bool(x: (u8, bool)) -> (bool, i8) { pub unsafe fn check_float_to_pointer(x: f64) -> *const () { // CHECK-NOT: alloca // CHECK: %0 = bitcast double %x to i64 - // CHECK: %1 = inttoptr i64 %0 to ptr - // CHECK: ret ptr %1 + // CHECK: %_0 = inttoptr i64 %0 to ptr + // CHECK: ret ptr %_0 transmute(x) } @@ -311,8 +307,8 @@ pub unsafe fn check_float_to_pointer(x: f64) -> *const () { pub unsafe fn check_float_from_pointer(x: *const ()) -> f64 { // CHECK-NOT: alloca // CHECK: %0 = ptrtoint ptr %x to i64 - // CHECK: %1 = bitcast i64 %0 to double - // CHECK: ret double %1 + // CHECK: %_0 = bitcast i64 %0 to double + // CHECK: ret double %_0 transmute(x) } @@ -376,10 +372,10 @@ pub unsafe fn check_issue_110005(x: (usize, bool)) -> Option> { // CHECK-LABEL: @check_pair_to_dst_ref( #[no_mangle] pub unsafe fn check_pair_to_dst_ref<'a>(x: (usize, usize)) -> &'a [u8] { - // CHECK: %0 = inttoptr i64 %x.0 to ptr - // CHECK: %1 = insertvalue { ptr, i64 } poison, ptr %0, 0 - // CHECK: %2 = insertvalue { ptr, i64 } %1, i64 %x.1, 1 - // CHECK: ret { ptr, i64 } %2 + // CHECK: %_0.0 = inttoptr i64 %x.0 to ptr + // CHECK: %0 = insertvalue { ptr, i64 } poison, ptr %_0.0, 0 + // CHECK: %1 = insertvalue { ptr, i64 } %0, i64 %x.1, 1 + // CHECK: ret { ptr, i64 } %1 transmute(x) } @@ -391,7 +387,7 @@ pub unsafe fn check_issue_109992(x: ()) -> [(); 1] { // CHECK: start // CHECK-NEXT: ret void - mir!{ + mir! { { RET = CastTransmute(x); Return() @@ -408,7 +404,7 @@ pub unsafe fn check_unit_to_never(x: ()) { // CHECK-NOT: trap // CHECK: call void @llvm.trap // CHECK-NOT: trap - mir!{ + mir! { let temp: ZstNever; { temp = CastTransmute(x); @@ -425,7 +421,7 @@ pub unsafe fn check_unit_from_never(x: ZstNever) -> () { // CHECK: start // CHECK-NEXT: ret void - mir!{ + mir! { { RET = CastTransmute(x); Return() @@ -457,10 +453,10 @@ pub struct HighAlignScalar(u8); // CHECK-LABEL: @check_to_overalign( #[no_mangle] pub unsafe fn check_to_overalign(x: u64) -> HighAlignScalar { - // CHECK: %0 = alloca %HighAlignScalar, align 8 - // CHECK: store i64 %x, ptr %0, align 8 - // CHECK: %1 = load i64, ptr %0, align 8 - // CHECK: ret i64 %1 + // CHECK: %_0 = alloca %HighAlignScalar, align 8 + // CHECK: store i64 %x, ptr %_0, align 8 + // CHECK: %0 = load i64, ptr %_0, align 8 + // CHECK: ret i64 %0 transmute(x) } diff --git a/tests/codegen/match-optimized.rs b/tests/codegen/match-optimized.rs index 520c46a0d570f..59e6eeb7c5dea 100644 --- a/tests/codegen/match-optimized.rs +++ b/tests/codegen/match-optimized.rs @@ -20,13 +20,13 @@ pub fn exhaustive_match(e: E) -> u8 { // CHECK-NEXT: unreachable // // CHECK: [[A]]: -// CHECK-NEXT: store i8 0, {{i8\*|ptr}} %1, align 1 +// CHECK-NEXT: store i8 0, {{i8\*|ptr}} %_0, align 1 // CHECK-NEXT: br label %[[EXIT:[a-zA-Z0-9_]+]] // CHECK: [[B]]: -// CHECK-NEXT: store i8 1, {{i8\*|ptr}} %1, align 1 +// CHECK-NEXT: store i8 1, {{i8\*|ptr}} %_0, align 1 // CHECK-NEXT: br label %[[EXIT]] // CHECK: [[C]]: -// CHECK-NEXT: store i8 2, {{i8\*|ptr}} %1, align 1 +// CHECK-NEXT: store i8 2, {{i8\*|ptr}} %_0, align 1 // CHECK-NEXT: br label %[[EXIT]] match e { E::A => 0, diff --git a/tests/codegen/mem-replace-big-type.rs b/tests/codegen/mem-replace-big-type.rs index c6b920cf59936..55c2741faaf65 100644 --- a/tests/codegen/mem-replace-big-type.rs +++ b/tests/codegen/mem-replace-big-type.rs @@ -25,7 +25,7 @@ pub fn replace_big(dst: &mut Big, src: Big) -> Big { // For a large type, we expect exactly three `memcpy`s // CHECK-LABEL: define internal void @{{.+}}mem{{.+}}replace{{.+}}sret(%Big) // CHECK-NOT: call void @llvm.memcpy -// CHECK: call void @llvm.memcpy.{{.+}}({{i8\*|ptr}} align 8 %0, {{i8\*|ptr}} align 8 %dest, i{{.*}} 56, i1 false) +// CHECK: call void @llvm.memcpy.{{.+}}({{i8\*|ptr}} align 8 %result, {{i8\*|ptr}} align 8 %dest, i{{.*}} 56, i1 false) // CHECK-NOT: call void @llvm.memcpy // CHECK: call void @llvm.memcpy.{{.+}}({{i8\*|ptr}} align 8 %dest, {{i8\*|ptr}} align 8 %src, i{{.*}} 56, i1 false) // CHECK-NOT: call void @llvm.memcpy diff --git a/tests/codegen/mem-replace-simple-type.rs b/tests/codegen/mem-replace-simple-type.rs index 6151177de15b2..5c4acf813ea42 100644 --- a/tests/codegen/mem-replace-simple-type.rs +++ b/tests/codegen/mem-replace-simple-type.rs @@ -38,7 +38,7 @@ pub fn replace_ref_str<'a>(r: &mut &'a str, v: &'a str) -> &'a str { pub fn replace_short_array(r: &mut [u32; 3], v: [u32; 3]) -> [u32; 3] { // CHECK-NOT: alloca // CHECK: %[[R:.+]] = load <3 x i32>, ptr %r, align 4 - // CHECK: store <3 x i32> %[[R]], ptr %0 + // CHECK: store <3 x i32> %[[R]], ptr %result // CHECK: %[[V:.+]] = load <3 x i32>, ptr %v, align 4 // CHECK: store <3 x i32> %[[V]], ptr %r std::mem::replace(r, v) diff --git a/tests/codegen/repeat-trusted-len.rs b/tests/codegen/repeat-trusted-len.rs index 87c8fe1354d76..d06978f24350d 100644 --- a/tests/codegen/repeat-trusted-len.rs +++ b/tests/codegen/repeat-trusted-len.rs @@ -8,13 +8,13 @@ use std::iter; // CHECK-LABEL: @repeat_take_collect #[no_mangle] pub fn repeat_take_collect() -> Vec { -// CHECK: call void @llvm.memset.{{.+}}({{i8\*|ptr}} {{.*}}align 1{{.*}} %{{[0-9]+}}, i8 42, i{{[0-9]+}} 100000, i1 false) + // CHECK: call void @llvm.memset.{{.+}}({{i8\*|ptr}} {{.*}}align 1{{.*}} %{{.*}}, i8 42, i{{[0-9]+}} 100000, i1 false) iter::repeat(42).take(100000).collect() } // CHECK-LABEL: @repeat_with_take_collect #[no_mangle] pub fn repeat_with_take_collect() -> Vec { -// CHECK: call void @llvm.memset.{{.+}}({{i8\*|ptr}} {{.*}}align 1{{.*}} %{{[0-9]+}}, i8 13, i{{[0-9]+}} 12345, i1 false) + // CHECK: call void @llvm.memset.{{.+}}({{i8\*|ptr}} {{.*}}align 1{{.*}} %{{.*}}, i8 13, i{{[0-9]+}} 12345, i1 false) iter::repeat_with(|| 13).take(12345).collect() } diff --git a/tests/codegen/repr-transparent-aggregates-1.rs b/tests/codegen/repr-transparent-aggregates-1.rs index 9c4b0e58e7187..ba3ba272efbb8 100644 --- a/tests/codegen/repr-transparent-aggregates-1.rs +++ b/tests/codegen/repr-transparent-aggregates-1.rs @@ -11,6 +11,7 @@ // ignore-s390x // ignore-windows // ignore-loongarch64 +// ignore-wasm32-bare // See repr-transparent.rs #![feature(transparent_unions)] diff --git a/tests/codegen/riscv-abi/riscv64-lp64-lp64f-lp64d-abi.rs b/tests/codegen/riscv-abi/riscv64-lp64-lp64f-lp64d-abi.rs index 045f01985a57f..ec18fa9a328e8 100644 --- a/tests/codegen/riscv-abi/riscv64-lp64-lp64f-lp64d-abi.rs +++ b/tests/codegen/riscv-abi/riscv64-lp64-lp64f-lp64d-abi.rs @@ -152,7 +152,7 @@ pub extern "C" fn f_scalar_stack_1( ) { } -// CHECK: define void @f_scalar_stack_2({{%Large\*|ptr}} {{.*}}sret{{.*}} %0, i64 noundef %a, i128 %1, i128 %2, i64 noundef %d, i8 noundef zeroext %e, i8 noundef %f, i8 noundef %g) +// CHECK: define void @f_scalar_stack_2({{%Large\*|ptr}} {{.*}}sret{{.*}} %_0, i64 noundef %a, i128 %0, i128 %1, i64 noundef %d, i8 noundef zeroext %e, i8 noundef %f, i8 noundef %g) #[no_mangle] pub extern "C" fn f_scalar_stack_2( a: u64, diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-arithmetic-saturating.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-arithmetic-saturating.rs index faac7566a0c49..0bcfacec6d797 100644 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-arithmetic-saturating.rs +++ b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-arithmetic-saturating.rs @@ -116,150 +116,150 @@ extern "platform-intrinsic" { fn simd_saturating_sub(x: T, y: T) -> T; } -// NOTE(eddyb) `%{{x|1}}` is used because on some targets (e.g. WASM) +// NOTE(eddyb) `%{{x|0}}` is used because on some targets (e.g. WASM) // SIMD vectors are passed directly, resulting in `%x` being a vector, // while on others they're passed indirectly, resulting in `%x` being -// a pointer to a vector, and `%1` a vector loaded from that pointer. +// a pointer to a vector, and `%0` a vector loaded from that pointer. // This is controlled by the target spec option `simd_types_indirect`. -// The same applies to `%{{y|2}}` as well. +// The same applies to `%{{y|1}}` as well. // CHECK-LABEL: @sadd_i8x2 #[no_mangle] pub unsafe fn sadd_i8x2(x: i8x2, y: i8x2) -> i8x2 { - // CHECK: %{{[0-9]+}} = call <2 x i8> @llvm.sadd.sat.v2i8(<2 x i8> %{{x|1}}, <2 x i8> %{{y|2}}) + // CHECK: %{{[0-9]+}} = call <2 x i8> @llvm.sadd.sat.v2i8(<2 x i8> %{{x|0}}, <2 x i8> %{{y|1}}) simd_saturating_add(x, y) } // CHECK-LABEL: @sadd_i8x4 #[no_mangle] pub unsafe fn sadd_i8x4(x: i8x4, y: i8x4) -> i8x4 { - // CHECK: %{{[0-9]+}} = call <4 x i8> @llvm.sadd.sat.v4i8(<4 x i8> %{{x|1}}, <4 x i8> %{{y|2}}) + // CHECK: %{{[0-9]+}} = call <4 x i8> @llvm.sadd.sat.v4i8(<4 x i8> %{{x|0}}, <4 x i8> %{{y|1}}) simd_saturating_add(x, y) } // CHECK-LABEL: @sadd_i8x8 #[no_mangle] pub unsafe fn sadd_i8x8(x: i8x8, y: i8x8) -> i8x8 { - // CHECK: %{{[0-9]+}} = call <8 x i8> @llvm.sadd.sat.v8i8(<8 x i8> %{{x|1}}, <8 x i8> %{{y|2}}) + // CHECK: %{{[0-9]+}} = call <8 x i8> @llvm.sadd.sat.v8i8(<8 x i8> %{{x|0}}, <8 x i8> %{{y|1}}) simd_saturating_add(x, y) } // CHECK-LABEL: @sadd_i8x16 #[no_mangle] pub unsafe fn sadd_i8x16(x: i8x16, y: i8x16) -> i8x16 { - // CHECK: %{{[0-9]+}} = call <16 x i8> @llvm.sadd.sat.v16i8(<16 x i8> %{{x|1}}, <16 x i8> %{{y|2}}) + // CHECK: %{{[0-9]+}} = call <16 x i8> @llvm.sadd.sat.v16i8(<16 x i8> %{{x|0}}, <16 x i8> %{{y|1}}) simd_saturating_add(x, y) } // CHECK-LABEL: @sadd_i8x32 #[no_mangle] pub unsafe fn sadd_i8x32(x: i8x32, y: i8x32) -> i8x32 { - // CHECK: %{{[0-9]+}} = call <32 x i8> @llvm.sadd.sat.v32i8(<32 x i8> %{{x|1}}, <32 x i8> %{{y|2}}) + // CHECK: %{{[0-9]+}} = call <32 x i8> @llvm.sadd.sat.v32i8(<32 x i8> %{{x|0}}, <32 x i8> %{{y|1}}) simd_saturating_add(x, y) } // CHECK-LABEL: @sadd_i8x64 #[no_mangle] pub unsafe fn sadd_i8x64(x: i8x64, y: i8x64) -> i8x64 { - // CHECK: %{{[0-9]+}} = call <64 x i8> @llvm.sadd.sat.v64i8(<64 x i8> %{{x|1}}, <64 x i8> %{{y|2}}) + // CHECK: %{{[0-9]+}} = call <64 x i8> @llvm.sadd.sat.v64i8(<64 x i8> %{{x|0}}, <64 x i8> %{{y|1}}) simd_saturating_add(x, y) } // CHECK-LABEL: @sadd_i16x2 #[no_mangle] pub unsafe fn sadd_i16x2(x: i16x2, y: i16x2) -> i16x2 { - // CHECK: %{{[0-9]+}} = call <2 x i16> @llvm.sadd.sat.v2i16(<2 x i16> %{{x|1}}, <2 x i16> %{{y|2}}) + // CHECK: %{{[0-9]+}} = call <2 x i16> @llvm.sadd.sat.v2i16(<2 x i16> %{{x|0}}, <2 x i16> %{{y|1}}) simd_saturating_add(x, y) } // CHECK-LABEL: @sadd_i16x4 #[no_mangle] pub unsafe fn sadd_i16x4(x: i16x4, y: i16x4) -> i16x4 { - // CHECK: %{{[0-9]+}} = call <4 x i16> @llvm.sadd.sat.v4i16(<4 x i16> %{{x|1}}, <4 x i16> %{{y|2}}) + // CHECK: %{{[0-9]+}} = call <4 x i16> @llvm.sadd.sat.v4i16(<4 x i16> %{{x|0}}, <4 x i16> %{{y|1}}) simd_saturating_add(x, y) } // CHECK-LABEL: @sadd_i16x8 #[no_mangle] pub unsafe fn sadd_i16x8(x: i16x8, y: i16x8) -> i16x8 { - // CHECK: %{{[0-9]+}} = call <8 x i16> @llvm.sadd.sat.v8i16(<8 x i16> %{{x|1}}, <8 x i16> %{{y|2}}) + // CHECK: %{{[0-9]+}} = call <8 x i16> @llvm.sadd.sat.v8i16(<8 x i16> %{{x|0}}, <8 x i16> %{{y|1}}) simd_saturating_add(x, y) } // CHECK-LABEL: @sadd_i16x16 #[no_mangle] pub unsafe fn sadd_i16x16(x: i16x16, y: i16x16) -> i16x16 { - // CHECK: %{{[0-9]+}} = call <16 x i16> @llvm.sadd.sat.v16i16(<16 x i16> %{{x|1}}, <16 x i16> %{{y|2}}) + // CHECK: %{{[0-9]+}} = call <16 x i16> @llvm.sadd.sat.v16i16(<16 x i16> %{{x|0}}, <16 x i16> %{{y|1}}) simd_saturating_add(x, y) } // CHECK-LABEL: @sadd_i16x32 #[no_mangle] pub unsafe fn sadd_i16x32(x: i16x32, y: i16x32) -> i16x32 { - // CHECK: %{{[0-9]+}} = call <32 x i16> @llvm.sadd.sat.v32i16(<32 x i16> %{{x|1}}, <32 x i16> %{{y|2}}) + // CHECK: %{{[0-9]+}} = call <32 x i16> @llvm.sadd.sat.v32i16(<32 x i16> %{{x|0}}, <32 x i16> %{{y|1}}) simd_saturating_add(x, y) } // CHECK-LABEL: @sadd_i32x2 #[no_mangle] pub unsafe fn sadd_i32x2(x: i32x2, y: i32x2) -> i32x2 { - // CHECK: %{{[0-9]+}} = call <2 x i32> @llvm.sadd.sat.v2i32(<2 x i32> %{{x|1}}, <2 x i32> %{{y|2}}) + // CHECK: %{{[0-9]+}} = call <2 x i32> @llvm.sadd.sat.v2i32(<2 x i32> %{{x|0}}, <2 x i32> %{{y|1}}) simd_saturating_add(x, y) } // CHECK-LABEL: @sadd_i32x4 #[no_mangle] pub unsafe fn sadd_i32x4(x: i32x4, y: i32x4) -> i32x4 { - // CHECK: %{{[0-9]+}} = call <4 x i32> @llvm.sadd.sat.v4i32(<4 x i32> %{{x|1}}, <4 x i32> %{{y|2}}) + // CHECK: %{{[0-9]+}} = call <4 x i32> @llvm.sadd.sat.v4i32(<4 x i32> %{{x|0}}, <4 x i32> %{{y|1}}) simd_saturating_add(x, y) } // CHECK-LABEL: @sadd_i32x8 #[no_mangle] pub unsafe fn sadd_i32x8(x: i32x8, y: i32x8) -> i32x8 { - // CHECK: %{{[0-9]+}} = call <8 x i32> @llvm.sadd.sat.v8i32(<8 x i32> %{{x|1}}, <8 x i32> %{{y|2}}) + // CHECK: %{{[0-9]+}} = call <8 x i32> @llvm.sadd.sat.v8i32(<8 x i32> %{{x|0}}, <8 x i32> %{{y|1}}) simd_saturating_add(x, y) } // CHECK-LABEL: @sadd_i32x16 #[no_mangle] pub unsafe fn sadd_i32x16(x: i32x16, y: i32x16) -> i32x16 { - // CHECK: %{{[0-9]+}} = call <16 x i32> @llvm.sadd.sat.v16i32(<16 x i32> %{{x|1}}, <16 x i32> %{{y|2}}) + // CHECK: %{{[0-9]+}} = call <16 x i32> @llvm.sadd.sat.v16i32(<16 x i32> %{{x|0}}, <16 x i32> %{{y|1}}) simd_saturating_add(x, y) } // CHECK-LABEL: @sadd_i64x2 #[no_mangle] pub unsafe fn sadd_i64x2(x: i64x2, y: i64x2) -> i64x2 { - // CHECK: %{{[0-9]+}} = call <2 x i64> @llvm.sadd.sat.v2i64(<2 x i64> %{{x|1}}, <2 x i64> %{{y|2}}) + // CHECK: %{{[0-9]+}} = call <2 x i64> @llvm.sadd.sat.v2i64(<2 x i64> %{{x|0}}, <2 x i64> %{{y|1}}) simd_saturating_add(x, y) } // CHECK-LABEL: @sadd_i64x4 #[no_mangle] pub unsafe fn sadd_i64x4(x: i64x4, y: i64x4) -> i64x4 { - // CHECK: %{{[0-9]+}} = call <4 x i64> @llvm.sadd.sat.v4i64(<4 x i64> %{{x|1}}, <4 x i64> %{{y|2}}) + // CHECK: %{{[0-9]+}} = call <4 x i64> @llvm.sadd.sat.v4i64(<4 x i64> %{{x|0}}, <4 x i64> %{{y|1}}) simd_saturating_add(x, y) } // CHECK-LABEL: @sadd_i64x8 #[no_mangle] pub unsafe fn sadd_i64x8(x: i64x8, y: i64x8) -> i64x8 { - // CHECK: %{{[0-9]+}} = call <8 x i64> @llvm.sadd.sat.v8i64(<8 x i64> %{{x|1}}, <8 x i64> %{{y|2}}) + // CHECK: %{{[0-9]+}} = call <8 x i64> @llvm.sadd.sat.v8i64(<8 x i64> %{{x|0}}, <8 x i64> %{{y|1}}) simd_saturating_add(x, y) } // CHECK-LABEL: @sadd_i128x2 #[no_mangle] pub unsafe fn sadd_i128x2(x: i128x2, y: i128x2) -> i128x2 { - // CHECK: %{{[0-9]+}} = call <2 x i128> @llvm.sadd.sat.v2i128(<2 x i128> %{{x|1}}, <2 x i128> %{{y|2}}) + // CHECK: %{{[0-9]+}} = call <2 x i128> @llvm.sadd.sat.v2i128(<2 x i128> %{{x|0}}, <2 x i128> %{{y|1}}) simd_saturating_add(x, y) } // CHECK-LABEL: @sadd_i128x4 #[no_mangle] pub unsafe fn sadd_i128x4(x: i128x4, y: i128x4) -> i128x4 { - // CHECK: %{{[0-9]+}} = call <4 x i128> @llvm.sadd.sat.v4i128(<4 x i128> %{{x|1}}, <4 x i128> %{{y|2}}) + // CHECK: %{{[0-9]+}} = call <4 x i128> @llvm.sadd.sat.v4i128(<4 x i128> %{{x|0}}, <4 x i128> %{{y|1}}) simd_saturating_add(x, y) } @@ -268,140 +268,140 @@ pub unsafe fn sadd_i128x4(x: i128x4, y: i128x4) -> i128x4 { // CHECK-LABEL: @uadd_u8x2 #[no_mangle] pub unsafe fn uadd_u8x2(x: u8x2, y: u8x2) -> u8x2 { - // CHECK: %{{[0-9]+}} = call <2 x i8> @llvm.uadd.sat.v2i8(<2 x i8> %{{x|1}}, <2 x i8> %{{y|2}}) + // CHECK: %{{[0-9]+}} = call <2 x i8> @llvm.uadd.sat.v2i8(<2 x i8> %{{x|0}}, <2 x i8> %{{y|1}}) simd_saturating_add(x, y) } // CHECK-LABEL: @uadd_u8x4 #[no_mangle] pub unsafe fn uadd_u8x4(x: u8x4, y: u8x4) -> u8x4 { - // CHECK: %{{[0-9]+}} = call <4 x i8> @llvm.uadd.sat.v4i8(<4 x i8> %{{x|1}}, <4 x i8> %{{y|2}}) + // CHECK: %{{[0-9]+}} = call <4 x i8> @llvm.uadd.sat.v4i8(<4 x i8> %{{x|0}}, <4 x i8> %{{y|1}}) simd_saturating_add(x, y) } // CHECK-LABEL: @uadd_u8x8 #[no_mangle] pub unsafe fn uadd_u8x8(x: u8x8, y: u8x8) -> u8x8 { - // CHECK: %{{[0-9]+}} = call <8 x i8> @llvm.uadd.sat.v8i8(<8 x i8> %{{x|1}}, <8 x i8> %{{y|2}}) + // CHECK: %{{[0-9]+}} = call <8 x i8> @llvm.uadd.sat.v8i8(<8 x i8> %{{x|0}}, <8 x i8> %{{y|1}}) simd_saturating_add(x, y) } // CHECK-LABEL: @uadd_u8x16 #[no_mangle] pub unsafe fn uadd_u8x16(x: u8x16, y: u8x16) -> u8x16 { - // CHECK: %{{[0-9]+}} = call <16 x i8> @llvm.uadd.sat.v16i8(<16 x i8> %{{x|1}}, <16 x i8> %{{y|2}}) + // CHECK: %{{[0-9]+}} = call <16 x i8> @llvm.uadd.sat.v16i8(<16 x i8> %{{x|0}}, <16 x i8> %{{y|1}}) simd_saturating_add(x, y) } // CHECK-LABEL: @uadd_u8x32 #[no_mangle] pub unsafe fn uadd_u8x32(x: u8x32, y: u8x32) -> u8x32 { - // CHECK: %{{[0-9]+}} = call <32 x i8> @llvm.uadd.sat.v32i8(<32 x i8> %{{x|1}}, <32 x i8> %{{y|2}}) + // CHECK: %{{[0-9]+}} = call <32 x i8> @llvm.uadd.sat.v32i8(<32 x i8> %{{x|0}}, <32 x i8> %{{y|1}}) simd_saturating_add(x, y) } // CHECK-LABEL: @uadd_u8x64 #[no_mangle] pub unsafe fn uadd_u8x64(x: u8x64, y: u8x64) -> u8x64 { - // CHECK: %{{[0-9]+}} = call <64 x i8> @llvm.uadd.sat.v64i8(<64 x i8> %{{x|1}}, <64 x i8> %{{y|2}}) + // CHECK: %{{[0-9]+}} = call <64 x i8> @llvm.uadd.sat.v64i8(<64 x i8> %{{x|0}}, <64 x i8> %{{y|1}}) simd_saturating_add(x, y) } // CHECK-LABEL: @uadd_u16x2 #[no_mangle] pub unsafe fn uadd_u16x2(x: u16x2, y: u16x2) -> u16x2 { - // CHECK: %{{[0-9]+}} = call <2 x i16> @llvm.uadd.sat.v2i16(<2 x i16> %{{x|1}}, <2 x i16> %{{y|2}}) + // CHECK: %{{[0-9]+}} = call <2 x i16> @llvm.uadd.sat.v2i16(<2 x i16> %{{x|0}}, <2 x i16> %{{y|1}}) simd_saturating_add(x, y) } // CHECK-LABEL: @uadd_u16x4 #[no_mangle] pub unsafe fn uadd_u16x4(x: u16x4, y: u16x4) -> u16x4 { - // CHECK: %{{[0-9]+}} = call <4 x i16> @llvm.uadd.sat.v4i16(<4 x i16> %{{x|1}}, <4 x i16> %{{y|2}}) + // CHECK: %{{[0-9]+}} = call <4 x i16> @llvm.uadd.sat.v4i16(<4 x i16> %{{x|0}}, <4 x i16> %{{y|1}}) simd_saturating_add(x, y) } // CHECK-LABEL: @uadd_u16x8 #[no_mangle] pub unsafe fn uadd_u16x8(x: u16x8, y: u16x8) -> u16x8 { - // CHECK: %{{[0-9]+}} = call <8 x i16> @llvm.uadd.sat.v8i16(<8 x i16> %{{x|1}}, <8 x i16> %{{y|2}}) + // CHECK: %{{[0-9]+}} = call <8 x i16> @llvm.uadd.sat.v8i16(<8 x i16> %{{x|0}}, <8 x i16> %{{y|1}}) simd_saturating_add(x, y) } // CHECK-LABEL: @uadd_u16x16 #[no_mangle] pub unsafe fn uadd_u16x16(x: u16x16, y: u16x16) -> u16x16 { - // CHECK: %{{[0-9]+}} = call <16 x i16> @llvm.uadd.sat.v16i16(<16 x i16> %{{x|1}}, <16 x i16> %{{y|2}}) + // CHECK: %{{[0-9]+}} = call <16 x i16> @llvm.uadd.sat.v16i16(<16 x i16> %{{x|0}}, <16 x i16> %{{y|1}}) simd_saturating_add(x, y) } // CHECK-LABEL: @uadd_u16x32 #[no_mangle] pub unsafe fn uadd_u16x32(x: u16x32, y: u16x32) -> u16x32 { - // CHECK: %{{[0-9]+}} = call <32 x i16> @llvm.uadd.sat.v32i16(<32 x i16> %{{x|1}}, <32 x i16> %{{y|2}}) + // CHECK: %{{[0-9]+}} = call <32 x i16> @llvm.uadd.sat.v32i16(<32 x i16> %{{x|0}}, <32 x i16> %{{y|1}}) simd_saturating_add(x, y) } // CHECK-LABEL: @uadd_u32x2 #[no_mangle] pub unsafe fn uadd_u32x2(x: u32x2, y: u32x2) -> u32x2 { - // CHECK: %{{[0-9]+}} = call <2 x i32> @llvm.uadd.sat.v2i32(<2 x i32> %{{x|1}}, <2 x i32> %{{y|2}}) + // CHECK: %{{[0-9]+}} = call <2 x i32> @llvm.uadd.sat.v2i32(<2 x i32> %{{x|0}}, <2 x i32> %{{y|1}}) simd_saturating_add(x, y) } // CHECK-LABEL: @uadd_u32x4 #[no_mangle] pub unsafe fn uadd_u32x4(x: u32x4, y: u32x4) -> u32x4 { - // CHECK: %{{[0-9]+}} = call <4 x i32> @llvm.uadd.sat.v4i32(<4 x i32> %{{x|1}}, <4 x i32> %{{y|2}}) + // CHECK: %{{[0-9]+}} = call <4 x i32> @llvm.uadd.sat.v4i32(<4 x i32> %{{x|0}}, <4 x i32> %{{y|1}}) simd_saturating_add(x, y) } // CHECK-LABEL: @uadd_u32x8 #[no_mangle] pub unsafe fn uadd_u32x8(x: u32x8, y: u32x8) -> u32x8 { - // CHECK: %{{[0-9]+}} = call <8 x i32> @llvm.uadd.sat.v8i32(<8 x i32> %{{x|1}}, <8 x i32> %{{y|2}}) + // CHECK: %{{[0-9]+}} = call <8 x i32> @llvm.uadd.sat.v8i32(<8 x i32> %{{x|0}}, <8 x i32> %{{y|1}}) simd_saturating_add(x, y) } // CHECK-LABEL: @uadd_u32x16 #[no_mangle] pub unsafe fn uadd_u32x16(x: u32x16, y: u32x16) -> u32x16 { - // CHECK: %{{[0-9]+}} = call <16 x i32> @llvm.uadd.sat.v16i32(<16 x i32> %{{x|1}}, <16 x i32> %{{y|2}}) + // CHECK: %{{[0-9]+}} = call <16 x i32> @llvm.uadd.sat.v16i32(<16 x i32> %{{x|0}}, <16 x i32> %{{y|1}}) simd_saturating_add(x, y) } // CHECK-LABEL: @uadd_u64x2 #[no_mangle] pub unsafe fn uadd_u64x2(x: u64x2, y: u64x2) -> u64x2 { - // CHECK: %{{[0-9]+}} = call <2 x i64> @llvm.uadd.sat.v2i64(<2 x i64> %{{x|1}}, <2 x i64> %{{y|2}}) + // CHECK: %{{[0-9]+}} = call <2 x i64> @llvm.uadd.sat.v2i64(<2 x i64> %{{x|0}}, <2 x i64> %{{y|1}}) simd_saturating_add(x, y) } // CHECK-LABEL: @uadd_u64x4 #[no_mangle] pub unsafe fn uadd_u64x4(x: u64x4, y: u64x4) -> u64x4 { - // CHECK: %{{[0-9]+}} = call <4 x i64> @llvm.uadd.sat.v4i64(<4 x i64> %{{x|1}}, <4 x i64> %{{y|2}}) + // CHECK: %{{[0-9]+}} = call <4 x i64> @llvm.uadd.sat.v4i64(<4 x i64> %{{x|0}}, <4 x i64> %{{y|1}}) simd_saturating_add(x, y) } // CHECK-LABEL: @uadd_u64x8 #[no_mangle] pub unsafe fn uadd_u64x8(x: u64x8, y: u64x8) -> u64x8 { - // CHECK: %{{[0-9]+}} = call <8 x i64> @llvm.uadd.sat.v8i64(<8 x i64> %{{x|1}}, <8 x i64> %{{y|2}}) + // CHECK: %{{[0-9]+}} = call <8 x i64> @llvm.uadd.sat.v8i64(<8 x i64> %{{x|0}}, <8 x i64> %{{y|1}}) simd_saturating_add(x, y) } // CHECK-LABEL: @uadd_u128x2 #[no_mangle] pub unsafe fn uadd_u128x2(x: u128x2, y: u128x2) -> u128x2 { - // CHECK: %{{[0-9]+}} = call <2 x i128> @llvm.uadd.sat.v2i128(<2 x i128> %{{x|1}}, <2 x i128> %{{y|2}}) + // CHECK: %{{[0-9]+}} = call <2 x i128> @llvm.uadd.sat.v2i128(<2 x i128> %{{x|0}}, <2 x i128> %{{y|1}}) simd_saturating_add(x, y) } // CHECK-LABEL: @uadd_u128x4 #[no_mangle] pub unsafe fn uadd_u128x4(x: u128x4, y: u128x4) -> u128x4 { - // CHECK: %{{[0-9]+}} = call <4 x i128> @llvm.uadd.sat.v4i128(<4 x i128> %{{x|1}}, <4 x i128> %{{y|2}}) + // CHECK: %{{[0-9]+}} = call <4 x i128> @llvm.uadd.sat.v4i128(<4 x i128> %{{x|0}}, <4 x i128> %{{y|1}}) simd_saturating_add(x, y) } @@ -412,140 +412,140 @@ pub unsafe fn uadd_u128x4(x: u128x4, y: u128x4) -> u128x4 { // CHECK-LABEL: @ssub_i8x2 #[no_mangle] pub unsafe fn ssub_i8x2(x: i8x2, y: i8x2) -> i8x2 { - // CHECK: %{{[0-9]+}} = call <2 x i8> @llvm.ssub.sat.v2i8(<2 x i8> %{{x|1}}, <2 x i8> %{{y|2}}) + // CHECK: %{{[0-9]+}} = call <2 x i8> @llvm.ssub.sat.v2i8(<2 x i8> %{{x|0}}, <2 x i8> %{{y|1}}) simd_saturating_sub(x, y) } // CHECK-LABEL: @ssub_i8x4 #[no_mangle] pub unsafe fn ssub_i8x4(x: i8x4, y: i8x4) -> i8x4 { - // CHECK: %{{[0-9]+}} = call <4 x i8> @llvm.ssub.sat.v4i8(<4 x i8> %{{x|1}}, <4 x i8> %{{y|2}}) + // CHECK: %{{[0-9]+}} = call <4 x i8> @llvm.ssub.sat.v4i8(<4 x i8> %{{x|0}}, <4 x i8> %{{y|1}}) simd_saturating_sub(x, y) } // CHECK-LABEL: @ssub_i8x8 #[no_mangle] pub unsafe fn ssub_i8x8(x: i8x8, y: i8x8) -> i8x8 { - // CHECK: %{{[0-9]+}} = call <8 x i8> @llvm.ssub.sat.v8i8(<8 x i8> %{{x|1}}, <8 x i8> %{{y|2}}) + // CHECK: %{{[0-9]+}} = call <8 x i8> @llvm.ssub.sat.v8i8(<8 x i8> %{{x|0}}, <8 x i8> %{{y|1}}) simd_saturating_sub(x, y) } // CHECK-LABEL: @ssub_i8x16 #[no_mangle] pub unsafe fn ssub_i8x16(x: i8x16, y: i8x16) -> i8x16 { - // CHECK: %{{[0-9]+}} = call <16 x i8> @llvm.ssub.sat.v16i8(<16 x i8> %{{x|1}}, <16 x i8> %{{y|2}}) + // CHECK: %{{[0-9]+}} = call <16 x i8> @llvm.ssub.sat.v16i8(<16 x i8> %{{x|0}}, <16 x i8> %{{y|1}}) simd_saturating_sub(x, y) } // CHECK-LABEL: @ssub_i8x32 #[no_mangle] pub unsafe fn ssub_i8x32(x: i8x32, y: i8x32) -> i8x32 { - // CHECK: %{{[0-9]+}} = call <32 x i8> @llvm.ssub.sat.v32i8(<32 x i8> %{{x|1}}, <32 x i8> %{{y|2}}) + // CHECK: %{{[0-9]+}} = call <32 x i8> @llvm.ssub.sat.v32i8(<32 x i8> %{{x|0}}, <32 x i8> %{{y|1}}) simd_saturating_sub(x, y) } // CHECK-LABEL: @ssub_i8x64 #[no_mangle] pub unsafe fn ssub_i8x64(x: i8x64, y: i8x64) -> i8x64 { - // CHECK: %{{[0-9]+}} = call <64 x i8> @llvm.ssub.sat.v64i8(<64 x i8> %{{x|1}}, <64 x i8> %{{y|2}}) + // CHECK: %{{[0-9]+}} = call <64 x i8> @llvm.ssub.sat.v64i8(<64 x i8> %{{x|0}}, <64 x i8> %{{y|1}}) simd_saturating_sub(x, y) } // CHECK-LABEL: @ssub_i16x2 #[no_mangle] pub unsafe fn ssub_i16x2(x: i16x2, y: i16x2) -> i16x2 { - // CHECK: %{{[0-9]+}} = call <2 x i16> @llvm.ssub.sat.v2i16(<2 x i16> %{{x|1}}, <2 x i16> %{{y|2}}) + // CHECK: %{{[0-9]+}} = call <2 x i16> @llvm.ssub.sat.v2i16(<2 x i16> %{{x|0}}, <2 x i16> %{{y|1}}) simd_saturating_sub(x, y) } // CHECK-LABEL: @ssub_i16x4 #[no_mangle] pub unsafe fn ssub_i16x4(x: i16x4, y: i16x4) -> i16x4 { - // CHECK: %{{[0-9]+}} = call <4 x i16> @llvm.ssub.sat.v4i16(<4 x i16> %{{x|1}}, <4 x i16> %{{y|2}}) + // CHECK: %{{[0-9]+}} = call <4 x i16> @llvm.ssub.sat.v4i16(<4 x i16> %{{x|0}}, <4 x i16> %{{y|1}}) simd_saturating_sub(x, y) } // CHECK-LABEL: @ssub_i16x8 #[no_mangle] pub unsafe fn ssub_i16x8(x: i16x8, y: i16x8) -> i16x8 { - // CHECK: %{{[0-9]+}} = call <8 x i16> @llvm.ssub.sat.v8i16(<8 x i16> %{{x|1}}, <8 x i16> %{{y|2}}) + // CHECK: %{{[0-9]+}} = call <8 x i16> @llvm.ssub.sat.v8i16(<8 x i16> %{{x|0}}, <8 x i16> %{{y|1}}) simd_saturating_sub(x, y) } // CHECK-LABEL: @ssub_i16x16 #[no_mangle] pub unsafe fn ssub_i16x16(x: i16x16, y: i16x16) -> i16x16 { - // CHECK: %{{[0-9]+}} = call <16 x i16> @llvm.ssub.sat.v16i16(<16 x i16> %{{x|1}}, <16 x i16> %{{y|2}}) + // CHECK: %{{[0-9]+}} = call <16 x i16> @llvm.ssub.sat.v16i16(<16 x i16> %{{x|0}}, <16 x i16> %{{y|1}}) simd_saturating_sub(x, y) } // CHECK-LABEL: @ssub_i16x32 #[no_mangle] pub unsafe fn ssub_i16x32(x: i16x32, y: i16x32) -> i16x32 { - // CHECK: %{{[0-9]+}} = call <32 x i16> @llvm.ssub.sat.v32i16(<32 x i16> %{{x|1}}, <32 x i16> %{{y|2}}) + // CHECK: %{{[0-9]+}} = call <32 x i16> @llvm.ssub.sat.v32i16(<32 x i16> %{{x|0}}, <32 x i16> %{{y|1}}) simd_saturating_sub(x, y) } // CHECK-LABEL: @ssub_i32x2 #[no_mangle] pub unsafe fn ssub_i32x2(x: i32x2, y: i32x2) -> i32x2 { - // CHECK: %{{[0-9]+}} = call <2 x i32> @llvm.ssub.sat.v2i32(<2 x i32> %{{x|1}}, <2 x i32> %{{y|2}}) + // CHECK: %{{[0-9]+}} = call <2 x i32> @llvm.ssub.sat.v2i32(<2 x i32> %{{x|0}}, <2 x i32> %{{y|1}}) simd_saturating_sub(x, y) } // CHECK-LABEL: @ssub_i32x4 #[no_mangle] pub unsafe fn ssub_i32x4(x: i32x4, y: i32x4) -> i32x4 { - // CHECK: %{{[0-9]+}} = call <4 x i32> @llvm.ssub.sat.v4i32(<4 x i32> %{{x|1}}, <4 x i32> %{{y|2}}) + // CHECK: %{{[0-9]+}} = call <4 x i32> @llvm.ssub.sat.v4i32(<4 x i32> %{{x|0}}, <4 x i32> %{{y|1}}) simd_saturating_sub(x, y) } // CHECK-LABEL: @ssub_i32x8 #[no_mangle] pub unsafe fn ssub_i32x8(x: i32x8, y: i32x8) -> i32x8 { - // CHECK: %{{[0-9]+}} = call <8 x i32> @llvm.ssub.sat.v8i32(<8 x i32> %{{x|1}}, <8 x i32> %{{y|2}}) + // CHECK: %{{[0-9]+}} = call <8 x i32> @llvm.ssub.sat.v8i32(<8 x i32> %{{x|0}}, <8 x i32> %{{y|1}}) simd_saturating_sub(x, y) } // CHECK-LABEL: @ssub_i32x16 #[no_mangle] pub unsafe fn ssub_i32x16(x: i32x16, y: i32x16) -> i32x16 { - // CHECK: %{{[0-9]+}} = call <16 x i32> @llvm.ssub.sat.v16i32(<16 x i32> %{{x|1}}, <16 x i32> %{{y|2}}) + // CHECK: %{{[0-9]+}} = call <16 x i32> @llvm.ssub.sat.v16i32(<16 x i32> %{{x|0}}, <16 x i32> %{{y|1}}) simd_saturating_sub(x, y) } // CHECK-LABEL: @ssub_i64x2 #[no_mangle] pub unsafe fn ssub_i64x2(x: i64x2, y: i64x2) -> i64x2 { - // CHECK: %{{[0-9]+}} = call <2 x i64> @llvm.ssub.sat.v2i64(<2 x i64> %{{x|1}}, <2 x i64> %{{y|2}}) + // CHECK: %{{[0-9]+}} = call <2 x i64> @llvm.ssub.sat.v2i64(<2 x i64> %{{x|0}}, <2 x i64> %{{y|1}}) simd_saturating_sub(x, y) } // CHECK-LABEL: @ssub_i64x4 #[no_mangle] pub unsafe fn ssub_i64x4(x: i64x4, y: i64x4) -> i64x4 { - // CHECK: %{{[0-9]+}} = call <4 x i64> @llvm.ssub.sat.v4i64(<4 x i64> %{{x|1}}, <4 x i64> %{{y|2}}) + // CHECK: %{{[0-9]+}} = call <4 x i64> @llvm.ssub.sat.v4i64(<4 x i64> %{{x|0}}, <4 x i64> %{{y|1}}) simd_saturating_sub(x, y) } // CHECK-LABEL: @ssub_i64x8 #[no_mangle] pub unsafe fn ssub_i64x8(x: i64x8, y: i64x8) -> i64x8 { - // CHECK: %{{[0-9]+}} = call <8 x i64> @llvm.ssub.sat.v8i64(<8 x i64> %{{x|1}}, <8 x i64> %{{y|2}}) + // CHECK: %{{[0-9]+}} = call <8 x i64> @llvm.ssub.sat.v8i64(<8 x i64> %{{x|0}}, <8 x i64> %{{y|1}}) simd_saturating_sub(x, y) } // CHECK-LABEL: @ssub_i128x2 #[no_mangle] pub unsafe fn ssub_i128x2(x: i128x2, y: i128x2) -> i128x2 { - // CHECK: %{{[0-9]+}} = call <2 x i128> @llvm.ssub.sat.v2i128(<2 x i128> %{{x|1}}, <2 x i128> %{{y|2}}) + // CHECK: %{{[0-9]+}} = call <2 x i128> @llvm.ssub.sat.v2i128(<2 x i128> %{{x|0}}, <2 x i128> %{{y|1}}) simd_saturating_sub(x, y) } // CHECK-LABEL: @ssub_i128x4 #[no_mangle] pub unsafe fn ssub_i128x4(x: i128x4, y: i128x4) -> i128x4 { - // CHECK: %{{[0-9]+}} = call <4 x i128> @llvm.ssub.sat.v4i128(<4 x i128> %{{x|1}}, <4 x i128> %{{y|2}}) + // CHECK: %{{[0-9]+}} = call <4 x i128> @llvm.ssub.sat.v4i128(<4 x i128> %{{x|0}}, <4 x i128> %{{y|1}}) simd_saturating_sub(x, y) } @@ -554,139 +554,139 @@ pub unsafe fn ssub_i128x4(x: i128x4, y: i128x4) -> i128x4 { // CHECK-LABEL: @usub_u8x2 #[no_mangle] pub unsafe fn usub_u8x2(x: u8x2, y: u8x2) -> u8x2 { - // CHECK: %{{[0-9]+}} = call <2 x i8> @llvm.usub.sat.v2i8(<2 x i8> %{{x|1}}, <2 x i8> %{{y|2}}) + // CHECK: %{{[0-9]+}} = call <2 x i8> @llvm.usub.sat.v2i8(<2 x i8> %{{x|0}}, <2 x i8> %{{y|1}}) simd_saturating_sub(x, y) } // CHECK-LABEL: @usub_u8x4 #[no_mangle] pub unsafe fn usub_u8x4(x: u8x4, y: u8x4) -> u8x4 { - // CHECK: %{{[0-9]+}} = call <4 x i8> @llvm.usub.sat.v4i8(<4 x i8> %{{x|1}}, <4 x i8> %{{y|2}}) + // CHECK: %{{[0-9]+}} = call <4 x i8> @llvm.usub.sat.v4i8(<4 x i8> %{{x|0}}, <4 x i8> %{{y|1}}) simd_saturating_sub(x, y) } // CHECK-LABEL: @usub_u8x8 #[no_mangle] pub unsafe fn usub_u8x8(x: u8x8, y: u8x8) -> u8x8 { - // CHECK: %{{[0-9]+}} = call <8 x i8> @llvm.usub.sat.v8i8(<8 x i8> %{{x|1}}, <8 x i8> %{{y|2}}) + // CHECK: %{{[0-9]+}} = call <8 x i8> @llvm.usub.sat.v8i8(<8 x i8> %{{x|0}}, <8 x i8> %{{y|1}}) simd_saturating_sub(x, y) } // CHECK-LABEL: @usub_u8x16 #[no_mangle] pub unsafe fn usub_u8x16(x: u8x16, y: u8x16) -> u8x16 { - // CHECK: %{{[0-9]+}} = call <16 x i8> @llvm.usub.sat.v16i8(<16 x i8> %{{x|1}}, <16 x i8> %{{y|2}}) + // CHECK: %{{[0-9]+}} = call <16 x i8> @llvm.usub.sat.v16i8(<16 x i8> %{{x|0}}, <16 x i8> %{{y|1}}) simd_saturating_sub(x, y) } // CHECK-LABEL: @usub_u8x32 #[no_mangle] pub unsafe fn usub_u8x32(x: u8x32, y: u8x32) -> u8x32 { - // CHECK: %{{[0-9]+}} = call <32 x i8> @llvm.usub.sat.v32i8(<32 x i8> %{{x|1}}, <32 x i8> %{{y|2}}) + // CHECK: %{{[0-9]+}} = call <32 x i8> @llvm.usub.sat.v32i8(<32 x i8> %{{x|0}}, <32 x i8> %{{y|1}}) simd_saturating_sub(x, y) } // CHECK-LABEL: @usub_u8x64 #[no_mangle] pub unsafe fn usub_u8x64(x: u8x64, y: u8x64) -> u8x64 { - // CHECK: %{{[0-9]+}} = call <64 x i8> @llvm.usub.sat.v64i8(<64 x i8> %{{x|1}}, <64 x i8> %{{y|2}}) + // CHECK: %{{[0-9]+}} = call <64 x i8> @llvm.usub.sat.v64i8(<64 x i8> %{{x|0}}, <64 x i8> %{{y|1}}) simd_saturating_sub(x, y) } // CHECK-LABEL: @usub_u16x2 #[no_mangle] pub unsafe fn usub_u16x2(x: u16x2, y: u16x2) -> u16x2 { - // CHECK: %{{[0-9]+}} = call <2 x i16> @llvm.usub.sat.v2i16(<2 x i16> %{{x|1}}, <2 x i16> %{{y|2}}) + // CHECK: %{{[0-9]+}} = call <2 x i16> @llvm.usub.sat.v2i16(<2 x i16> %{{x|0}}, <2 x i16> %{{y|1}}) simd_saturating_sub(x, y) } // CHECK-LABEL: @usub_u16x4 #[no_mangle] pub unsafe fn usub_u16x4(x: u16x4, y: u16x4) -> u16x4 { - // CHECK: %{{[0-9]+}} = call <4 x i16> @llvm.usub.sat.v4i16(<4 x i16> %{{x|1}}, <4 x i16> %{{y|2}}) + // CHECK: %{{[0-9]+}} = call <4 x i16> @llvm.usub.sat.v4i16(<4 x i16> %{{x|0}}, <4 x i16> %{{y|1}}) simd_saturating_sub(x, y) } // CHECK-LABEL: @usub_u16x8 #[no_mangle] pub unsafe fn usub_u16x8(x: u16x8, y: u16x8) -> u16x8 { - // CHECK: %{{[0-9]+}} = call <8 x i16> @llvm.usub.sat.v8i16(<8 x i16> %{{x|1}}, <8 x i16> %{{y|2}}) + // CHECK: %{{[0-9]+}} = call <8 x i16> @llvm.usub.sat.v8i16(<8 x i16> %{{x|0}}, <8 x i16> %{{y|1}}) simd_saturating_sub(x, y) } // CHECK-LABEL: @usub_u16x16 #[no_mangle] pub unsafe fn usub_u16x16(x: u16x16, y: u16x16) -> u16x16 { - // CHECK: %{{[0-9]+}} = call <16 x i16> @llvm.usub.sat.v16i16(<16 x i16> %{{x|1}}, <16 x i16> %{{y|2}}) + // CHECK: %{{[0-9]+}} = call <16 x i16> @llvm.usub.sat.v16i16(<16 x i16> %{{x|0}}, <16 x i16> %{{y|1}}) simd_saturating_sub(x, y) } // CHECK-LABEL: @usub_u16x32 #[no_mangle] pub unsafe fn usub_u16x32(x: u16x32, y: u16x32) -> u16x32 { - // CHECK: %{{[0-9]+}} = call <32 x i16> @llvm.usub.sat.v32i16(<32 x i16> %{{x|1}}, <32 x i16> %{{y|2}}) + // CHECK: %{{[0-9]+}} = call <32 x i16> @llvm.usub.sat.v32i16(<32 x i16> %{{x|0}}, <32 x i16> %{{y|1}}) simd_saturating_sub(x, y) } // CHECK-LABEL: @usub_u32x2 #[no_mangle] pub unsafe fn usub_u32x2(x: u32x2, y: u32x2) -> u32x2 { - // CHECK: %{{[0-9]+}} = call <2 x i32> @llvm.usub.sat.v2i32(<2 x i32> %{{x|1}}, <2 x i32> %{{y|2}}) + // CHECK: %{{[0-9]+}} = call <2 x i32> @llvm.usub.sat.v2i32(<2 x i32> %{{x|0}}, <2 x i32> %{{y|1}}) simd_saturating_sub(x, y) } // CHECK-LABEL: @usub_u32x4 #[no_mangle] pub unsafe fn usub_u32x4(x: u32x4, y: u32x4) -> u32x4 { - // CHECK: %{{[0-9]+}} = call <4 x i32> @llvm.usub.sat.v4i32(<4 x i32> %{{x|1}}, <4 x i32> %{{y|2}}) + // CHECK: %{{[0-9]+}} = call <4 x i32> @llvm.usub.sat.v4i32(<4 x i32> %{{x|0}}, <4 x i32> %{{y|1}}) simd_saturating_sub(x, y) } // CHECK-LABEL: @usub_u32x8 #[no_mangle] pub unsafe fn usub_u32x8(x: u32x8, y: u32x8) -> u32x8 { - // CHECK: %{{[0-9]+}} = call <8 x i32> @llvm.usub.sat.v8i32(<8 x i32> %{{x|1}}, <8 x i32> %{{y|2}}) + // CHECK: %{{[0-9]+}} = call <8 x i32> @llvm.usub.sat.v8i32(<8 x i32> %{{x|0}}, <8 x i32> %{{y|1}}) simd_saturating_sub(x, y) } // CHECK-LABEL: @usub_u32x16 #[no_mangle] pub unsafe fn usub_u32x16(x: u32x16, y: u32x16) -> u32x16 { - // CHECK: %{{[0-9]+}} = call <16 x i32> @llvm.usub.sat.v16i32(<16 x i32> %{{x|1}}, <16 x i32> %{{y|2}}) + // CHECK: %{{[0-9]+}} = call <16 x i32> @llvm.usub.sat.v16i32(<16 x i32> %{{x|0}}, <16 x i32> %{{y|1}}) simd_saturating_sub(x, y) } // CHECK-LABEL: @usub_u64x2 #[no_mangle] pub unsafe fn usub_u64x2(x: u64x2, y: u64x2) -> u64x2 { - // CHECK: %{{[0-9]+}} = call <2 x i64> @llvm.usub.sat.v2i64(<2 x i64> %{{x|1}}, <2 x i64> %{{y|2}}) + // CHECK: %{{[0-9]+}} = call <2 x i64> @llvm.usub.sat.v2i64(<2 x i64> %{{x|0}}, <2 x i64> %{{y|1}}) simd_saturating_sub(x, y) } // CHECK-LABEL: @usub_u64x4 #[no_mangle] pub unsafe fn usub_u64x4(x: u64x4, y: u64x4) -> u64x4 { - // CHECK: %{{[0-9]+}} = call <4 x i64> @llvm.usub.sat.v4i64(<4 x i64> %{{x|1}}, <4 x i64> %{{y|2}}) + // CHECK: %{{[0-9]+}} = call <4 x i64> @llvm.usub.sat.v4i64(<4 x i64> %{{x|0}}, <4 x i64> %{{y|1}}) simd_saturating_sub(x, y) } // CHECK-LABEL: @usub_u64x8 #[no_mangle] pub unsafe fn usub_u64x8(x: u64x8, y: u64x8) -> u64x8 { - // CHECK: %{{[0-9]+}} = call <8 x i64> @llvm.usub.sat.v8i64(<8 x i64> %{{x|1}}, <8 x i64> %{{y|2}}) + // CHECK: %{{[0-9]+}} = call <8 x i64> @llvm.usub.sat.v8i64(<8 x i64> %{{x|0}}, <8 x i64> %{{y|1}}) simd_saturating_sub(x, y) } // CHECK-LABEL: @usub_u128x2 #[no_mangle] pub unsafe fn usub_u128x2(x: u128x2, y: u128x2) -> u128x2 { - // CHECK: %{{[0-9]+}} = call <2 x i128> @llvm.usub.sat.v2i128(<2 x i128> %{{x|1}}, <2 x i128> %{{y|2}}) + // CHECK: %{{[0-9]+}} = call <2 x i128> @llvm.usub.sat.v2i128(<2 x i128> %{{x|0}}, <2 x i128> %{{y|1}}) simd_saturating_sub(x, y) } // CHECK-LABEL: @usub_u128x4 #[no_mangle] pub unsafe fn usub_u128x4(x: u128x4, y: u128x4) -> u128x4 { - // CHECK: %{{[0-9]+}} = call <4 x i128> @llvm.usub.sat.v4i128(<4 x i128> %{{x|1}}, <4 x i128> %{{y|2}}) + // CHECK: %{{[0-9]+}} = call <4 x i128> @llvm.usub.sat.v4i128(<4 x i128> %{{x|0}}, <4 x i128> %{{y|1}}) simd_saturating_sub(x, y) } diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-extract-insert.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-extract-insert.rs index 80583dec19524..a5d2509d00051 100644 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-extract-insert.rs +++ b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-extract-insert.rs @@ -35,13 +35,13 @@ pub unsafe fn extract_s(v: S<4>, i: u32) -> f32 { // CHECK-LABEL: @insert_m #[no_mangle] pub unsafe fn insert_m(v: M, i: u32, j: f32) -> M { - // CHECK: insertelement <4 x float> %{{v|1|2}}, float %j, i32 %i + // CHECK: insertelement <4 x float> %{{v|0|1}}, float %j, i32 %i simd_insert(v, i, j) } // CHECK-LABEL: @insert_s #[no_mangle] pub unsafe fn insert_s(v: S<4>, i: u32, j: f32) -> S<4> { - // CHECK: insertelement <4 x float> %{{v|1|2}}, float %j, i32 %i + // CHECK: insertelement <4 x float> %{{v|0|1}}, float %j, i32 %i simd_insert(v, i, j) } diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-transmute-array.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-transmute-array.rs index fd488a14bd370..3a0e37de2f3c4 100644 --- a/tests/codegen/simd-intrinsic/simd-intrinsic-transmute-array.rs +++ b/tests/codegen/simd-intrinsic/simd-intrinsic-transmute-array.rs @@ -2,7 +2,6 @@ // compile-flags: -C no-prepopulate-passes #![crate_type = "lib"] - #![allow(non_camel_case_types)] #![feature(repr_simd, platform_intrinsics)] #![feature(inline_const)] @@ -44,7 +43,7 @@ pub fn build_array_s(x: [f32; 4]) -> S<4> { #[no_mangle] pub fn build_array_transmute_s(x: [f32; 4]) -> S<4> { // CHECK: %[[VAL:.+]] = load <4 x float>, {{ptr %x|.+>\* %.+}}, align [[ARRAY_ALIGN]] - // CHECK: store <4 x float> %[[VAL:.+]], {{ptr %0|.+>\* %.+}}, align [[VECTOR_ALIGN]] + // CHECK: store <4 x float> %[[VAL:.+]], {{ptr %_0|.+>\* %.+}}, align [[VECTOR_ALIGN]] unsafe { std::mem::transmute(x) } } @@ -59,7 +58,7 @@ pub fn build_array_t(x: [f32; 4]) -> T { #[no_mangle] pub fn build_array_transmute_t(x: [f32; 4]) -> T { // CHECK: %[[VAL:.+]] = load <4 x float>, {{ptr %x|.+>\* %.+}}, align [[ARRAY_ALIGN]] - // CHECK: store <4 x float> %[[VAL:.+]], {{ptr %0|.+>\* %.+}}, align [[VECTOR_ALIGN]] + // CHECK: store <4 x float> %[[VAL:.+]], {{ptr %_0|.+>\* %.+}}, align [[VECTOR_ALIGN]] unsafe { std::mem::transmute(x) } } @@ -78,6 +77,6 @@ pub fn build_array_u(x: [f32; 4]) -> U { #[no_mangle] pub fn build_array_transmute_u(x: [f32; 4]) -> U { // CHECK: %[[VAL:.+]] = load <4 x float>, {{ptr %x|.+>\* %.+}}, align [[ARRAY_ALIGN]] - // CHECK: store <4 x float> %[[VAL:.+]], {{ptr %0|.+>\* %.+}}, align [[VECTOR_ALIGN]] + // CHECK: store <4 x float> %[[VAL:.+]], {{ptr %_0|.+>\* %.+}}, align [[VECTOR_ALIGN]] unsafe { std::mem::transmute(x) } } diff --git a/tests/codegen/simd_arith_offset.rs b/tests/codegen/simd_arith_offset.rs index f2333777391f1..74d7edc70d73a 100644 --- a/tests/codegen/simd_arith_offset.rs +++ b/tests/codegen/simd_arith_offset.rs @@ -21,6 +21,6 @@ pub struct Simd([T; LANES]); // CHECK-LABEL: smoke #[no_mangle] pub fn smoke(ptrs: SimdConstPtr, offsets: Simd) -> SimdConstPtr { - // CHECK: getelementptr i8, <8 x {{i8\*|ptr}}> %1, <8 x i64> %2 + // CHECK: getelementptr i8, <8 x {{i8\*|ptr}}> %0, <8 x i64> %1 unsafe { simd_arith_offset(ptrs, offsets) } } diff --git a/tests/codegen/slice-iter-len-eq-zero.rs b/tests/codegen/slice-iter-len-eq-zero.rs index 894b0ec3de4f3..69f78cea56416 100644 --- a/tests/codegen/slice-iter-len-eq-zero.rs +++ b/tests/codegen/slice-iter-len-eq-zero.rs @@ -9,8 +9,8 @@ type Demo = [u8; 3]; #[no_mangle] pub fn slice_iter_len_eq_zero(y: std::slice::Iter<'_, Demo>) -> bool { // CHECK-NOT: sub - // CHECK: %2 = icmp eq {{i8\*|ptr}} {{%1|%0}}, {{%1|%0}} - // CHECK: ret i1 %2 + // CHECK: %_0 = icmp eq {{i8\*|ptr}} {{%1|%0}}, {{%1|%0}} + // CHECK: ret i1 %_0 y.len() == 0 } @@ -22,7 +22,7 @@ pub fn array_into_iter_len_eq_zero(y: std::array::IntoIter) -> bool { // CHECK-NOT: icmp // CHECK-NOT: sub - // CHECK: %1 = icmp eq {{i16|i32|i64}} - // CHECK: ret i1 %1 + // CHECK: %_0 = icmp eq {{i16|i32|i64}} + // CHECK: ret i1 %_0 y.len() == 0 } diff --git a/tests/codegen/transmute-scalar.rs b/tests/codegen/transmute-scalar.rs index a0894a505c7c6..293b0d664f62e 100644 --- a/tests/codegen/transmute-scalar.rs +++ b/tests/codegen/transmute-scalar.rs @@ -11,24 +11,24 @@ // that allows us to avoid the `alloca`s entirely; see `rvalue_creates_operand`. // CHECK-LABEL: define{{.*}}i32 @f32_to_bits(float %x) -// CHECK: %0 = bitcast float %x to i32 -// CHECK-NEXT: ret i32 %0 +// CHECK: %_0 = bitcast float %x to i32 +// CHECK-NEXT: ret i32 %_0 #[no_mangle] pub fn f32_to_bits(x: f32) -> u32 { unsafe { std::mem::transmute(x) } } // CHECK-LABEL: define{{.*}}i8 @bool_to_byte(i1 zeroext %b) -// CHECK: %0 = zext i1 %b to i8 -// CHECK-NEXT: ret i8 %0 +// CHECK: %_0 = zext i1 %b to i8 +// CHECK-NEXT: ret i8 %_0 #[no_mangle] pub fn bool_to_byte(b: bool) -> u8 { unsafe { std::mem::transmute(b) } } // CHECK-LABEL: define{{.*}}zeroext i1 @byte_to_bool(i8 %byte) -// CHECK: %0 = trunc i8 %byte to i1 -// CHECK-NEXT: ret i1 %0 +// CHECK: %_0 = trunc i8 %byte to i1 +// CHECK-NEXT: ret i1 %_0 #[no_mangle] pub unsafe fn byte_to_bool(byte: u8) -> bool { std::mem::transmute(byte) @@ -42,16 +42,16 @@ pub fn ptr_to_ptr(p: *mut u16) -> *mut u8 { } // CHECK: define{{.*}}[[USIZE:i[0-9]+]] @ptr_to_int(ptr %p) -// CHECK: %0 = ptrtoint ptr %p to [[USIZE]] -// CHECK-NEXT: ret [[USIZE]] %0 +// CHECK: %_0 = ptrtoint ptr %p to [[USIZE]] +// CHECK-NEXT: ret [[USIZE]] %_0 #[no_mangle] pub fn ptr_to_int(p: *mut u16) -> usize { unsafe { std::mem::transmute(p) } } // CHECK: define{{.*}}ptr @int_to_ptr([[USIZE]] %i) -// CHECK: %0 = inttoptr [[USIZE]] %i to ptr -// CHECK-NEXT: ret ptr %0 +// CHECK: %_0 = inttoptr [[USIZE]] %i to ptr +// CHECK-NEXT: ret ptr %_0 #[no_mangle] pub fn int_to_ptr(i: usize) -> *mut u16 { unsafe { std::mem::transmute(i) } diff --git a/tests/codegen/uninit-consts.rs b/tests/codegen/uninit-consts.rs index 54e9a9e9bb876..f169988e1f5a1 100644 --- a/tests/codegen/uninit-consts.rs +++ b/tests/codegen/uninit-consts.rs @@ -1,4 +1,5 @@ // compile-flags: -C no-prepopulate-passes +// min-llvm-version: 15.0 (for opaque pointers) // Check that we use undef (and not zero) for uninitialized bytes in constants. @@ -8,7 +9,7 @@ use std::mem::MaybeUninit; pub struct PartiallyUninit { x: u32, - y: MaybeUninit<[u8; 10]> + y: MaybeUninit<[u8; 10]>, } // CHECK: [[FULLY_UNINIT:@[0-9]+]] = private unnamed_addr constant <{ [10 x i8] }> undef @@ -25,7 +26,7 @@ pub struct PartiallyUninit { #[no_mangle] pub const fn fully_uninit() -> MaybeUninit<[u8; 10]> { const M: MaybeUninit<[u8; 10]> = MaybeUninit::uninit(); - // CHECK: call void @llvm.memcpy.{{.+}}({{i8\*|ptr}} align 1 %{{[0-9]+}}, {{i8\*|ptr}} align 1 {{.*}}[[FULLY_UNINIT]]{{.*}}, i{{(32|64)}} 10, i1 false) + // CHECK: call void @llvm.memcpy.{{.+}}(ptr align 1 %_0, ptr align 1 {{.*}}[[FULLY_UNINIT]]{{.*}}, i{{(32|64)}} 10, i1 false) M } @@ -33,7 +34,7 @@ pub const fn fully_uninit() -> MaybeUninit<[u8; 10]> { #[no_mangle] pub const fn partially_uninit() -> PartiallyUninit { const X: PartiallyUninit = PartiallyUninit { x: 0xdeadbeef, y: MaybeUninit::uninit() }; - // CHECK: call void @llvm.memcpy.{{.+}}({{i8\*|ptr}} align 4 %{{[0-9]+}}, {{i8\*|ptr}} align 4 {{.*}}[[PARTIALLY_UNINIT]]{{.*}}, i{{(32|64)}} 16, i1 false) + // CHECK: call void @llvm.memcpy.{{.+}}(ptr align 4 %_0, ptr align 4 {{.*}}[[PARTIALLY_UNINIT]]{{.*}}, i{{(32|64)}} 16, i1 false) X } @@ -41,7 +42,7 @@ pub const fn partially_uninit() -> PartiallyUninit { #[no_mangle] pub const fn uninit_padding_huge() -> [(u32, u8); 4096] { const X: [(u32, u8); 4096] = [(123, 45); 4096]; - // CHECK: call void @llvm.memcpy.{{.+}}({{i8\*|ptr}} align 4 %{{[0-9]+}}, {{i8\*|ptr}} align 4 {{.*}}[[UNINIT_PADDING_HUGE]]{{.*}}, i{{(32|64)}} 32768, i1 false) + // CHECK: call void @llvm.memcpy.{{.+}}(ptr align 4 %_0, ptr align 4 {{.*}}[[UNINIT_PADDING_HUGE]]{{.*}}, i{{(32|64)}} 32768, i1 false) X } @@ -49,6 +50,6 @@ pub const fn uninit_padding_huge() -> [(u32, u8); 4096] { #[no_mangle] pub const fn fully_uninit_huge() -> MaybeUninit<[u32; 4096]> { const F: MaybeUninit<[u32; 4096]> = MaybeUninit::uninit(); - // CHECK: call void @llvm.memcpy.{{.+}}({{i8\*|ptr}} align 4 %{{[0-9]+}}, {{i8\*|ptr}} align 4 {{.*}}[[FULLY_UNINIT_HUGE]]{{.*}}, i{{(32|64)}} 16384, i1 false) + // CHECK: call void @llvm.memcpy.{{.+}}(ptr align 4 %_0, ptr align 4 {{.*}}[[FULLY_UNINIT_HUGE]]{{.*}}, i{{(32|64)}} 16384, i1 false) F } diff --git a/tests/codegen/union-abi.rs b/tests/codegen/union-abi.rs index 8481ca8ccfa19..653c5837daf03 100644 --- a/tests/codegen/union-abi.rs +++ b/tests/codegen/union-abi.rs @@ -73,4 +73,4 @@ pub union UnionBool { b:bool } // CHECK: define {{(dso_local )?}}noundef zeroext i1 @test_UnionBool(i8 %b) #[no_mangle] pub fn test_UnionBool(b: UnionBool) -> bool { unsafe { b.b } } -// CHECK: %0 = trunc i8 %b to i1 +// CHECK: %_0 = trunc i8 %b to i1 diff --git a/tests/codegen/var-names.rs b/tests/codegen/var-names.rs index 53841df32e8d6..d4715efad73c0 100644 --- a/tests/codegen/var-names.rs +++ b/tests/codegen/var-names.rs @@ -9,7 +9,7 @@ pub fn test(a: u32, b: u32) -> u32 { // CHECK: %c = add i32 %a, %b let d = c; let e = d * a; - // CHECK-NEXT: %0 = mul i32 %c, %a + // CHECK-NEXT: %e = mul i32 %c, %a e - // CHECK-NEXT: ret i32 %0 + // CHECK-NEXT: ret i32 %e } diff --git a/tests/codegen/wasm_exceptions.rs b/tests/codegen/wasm_exceptions.rs new file mode 100644 index 0000000000000..2b2359f5b6caa --- /dev/null +++ b/tests/codegen/wasm_exceptions.rs @@ -0,0 +1,51 @@ +// only-wasm32-bare +// compile-flags: -C panic=unwind + +#![crate_type = "lib"] +#![feature(core_intrinsics)] +#![feature(rustc_attrs)] + +extern { + fn may_panic(); + + #[rustc_nounwind] + fn log_number(number: usize); +} + +struct LogOnDrop; + +impl Drop for LogOnDrop { + fn drop(&mut self) { + unsafe { log_number(0); } + } +} + +// CHECK-LABEL: @test_cleanup() {{.*}} @__gxx_wasm_personality_v0 +#[no_mangle] +pub fn test_cleanup() { + let _log_on_drop = LogOnDrop; + unsafe { may_panic(); } + + // CHECK-NOT: call + // CHECK: invoke void @may_panic() + // CHECK: %cleanuppad = cleanuppad within none [] +} + +// CHECK-LABEL: @test_rtry() {{.*}} @__gxx_wasm_personality_v0 +#[no_mangle] +pub fn test_rtry() { + unsafe { + core::intrinsics::r#try(|_| { + may_panic(); + }, core::ptr::null_mut(), |data, exception| { + log_number(data as usize); + log_number(exception as usize); + }); + } + + // CHECK-NOT: call + // CHECK: invoke void @may_panic() + // CHECK: {{.*}} = catchswitch within none [label {{.*}}] unwind to caller + // CHECK: {{.*}} = catchpad within {{.*}} [ptr null] + // CHECK: catchret +} diff --git a/tests/mir-opt/address_of.address_of_reborrow.SimplifyCfg-initial.after.mir b/tests/mir-opt/address_of.address_of_reborrow.SimplifyCfg-initial.after.mir index 93bf2b64deb4c..61aa89e445f50 100644 --- a/tests/mir-opt/address_of.address_of_reborrow.SimplifyCfg-initial.after.mir +++ b/tests/mir-opt/address_of.address_of_reborrow.SimplifyCfg-initial.after.mir @@ -150,7 +150,7 @@ fn address_of_reborrow() -> () { StorageLive(_9); StorageLive(_10); _10 = &raw const (*_1); - _9 = move _10 as *const dyn std::marker::Send (Pointer(Unsize)); + _9 = move _10 as *const dyn std::marker::Send (PointerCoercion(Unsize)); StorageDead(_10); AscribeUserType(_9, o, UserTypeProjection { base: UserType(1), projs: [] }); _8 = _9; @@ -159,13 +159,13 @@ fn address_of_reborrow() -> () { StorageLive(_11); StorageLive(_12); _12 = &raw const (*_1); - _11 = move _12 as *const [i32] (Pointer(Unsize)); + _11 = move _12 as *const [i32] (PointerCoercion(Unsize)); StorageDead(_12); StorageDead(_11); StorageLive(_13); StorageLive(_14); _14 = &raw const (*_1); - _13 = move _14 as *const i32 (Pointer(ArrayToPointer)); + _13 = move _14 as *const i32 (PointerCoercion(ArrayToPointer)); StorageDead(_14); StorageDead(_13); StorageLive(_15); @@ -179,14 +179,14 @@ fn address_of_reborrow() -> () { StorageLive(_17); StorageLive(_18); _18 = &raw const (*_1); - _17 = move _18 as *const dyn std::marker::Send (Pointer(Unsize)); + _17 = move _18 as *const dyn std::marker::Send (PointerCoercion(Unsize)); StorageDead(_18); FakeRead(ForLet(None), _17); AscribeUserType(_17, o, UserTypeProjection { base: UserType(7), projs: [] }); StorageLive(_19); StorageLive(_20); _20 = &raw const (*_1); - _19 = move _20 as *const [i32] (Pointer(Unsize)); + _19 = move _20 as *const [i32] (PointerCoercion(Unsize)); StorageDead(_20); FakeRead(ForLet(None), _19); AscribeUserType(_19, o, UserTypeProjection { base: UserType(9), projs: [] }); @@ -204,7 +204,7 @@ fn address_of_reborrow() -> () { StorageLive(_25); StorageLive(_26); _26 = &raw const (*_3); - _25 = move _26 as *const dyn std::marker::Send (Pointer(Unsize)); + _25 = move _26 as *const dyn std::marker::Send (PointerCoercion(Unsize)); StorageDead(_26); AscribeUserType(_25, o, UserTypeProjection { base: UserType(11), projs: [] }); _24 = _25; @@ -213,7 +213,7 @@ fn address_of_reborrow() -> () { StorageLive(_27); StorageLive(_28); _28 = &raw const (*_3); - _27 = move _28 as *const [i32] (Pointer(Unsize)); + _27 = move _28 as *const [i32] (PointerCoercion(Unsize)); StorageDead(_28); StorageDead(_27); StorageLive(_29); @@ -227,14 +227,14 @@ fn address_of_reborrow() -> () { StorageLive(_31); StorageLive(_32); _32 = &raw const (*_3); - _31 = move _32 as *const dyn std::marker::Send (Pointer(Unsize)); + _31 = move _32 as *const dyn std::marker::Send (PointerCoercion(Unsize)); StorageDead(_32); FakeRead(ForLet(None), _31); AscribeUserType(_31, o, UserTypeProjection { base: UserType(17), projs: [] }); StorageLive(_33); StorageLive(_34); _34 = &raw const (*_3); - _33 = move _34 as *const [i32] (Pointer(Unsize)); + _33 = move _34 as *const [i32] (PointerCoercion(Unsize)); StorageDead(_34); FakeRead(ForLet(None), _33); AscribeUserType(_33, o, UserTypeProjection { base: UserType(19), projs: [] }); @@ -252,7 +252,7 @@ fn address_of_reborrow() -> () { StorageLive(_39); StorageLive(_40); _40 = &raw mut (*_3); - _39 = move _40 as *mut dyn std::marker::Send (Pointer(Unsize)); + _39 = move _40 as *mut dyn std::marker::Send (PointerCoercion(Unsize)); StorageDead(_40); AscribeUserType(_39, o, UserTypeProjection { base: UserType(21), projs: [] }); _38 = _39; @@ -261,7 +261,7 @@ fn address_of_reborrow() -> () { StorageLive(_41); StorageLive(_42); _42 = &raw mut (*_3); - _41 = move _42 as *mut [i32] (Pointer(Unsize)); + _41 = move _42 as *mut [i32] (PointerCoercion(Unsize)); StorageDead(_42); StorageDead(_41); StorageLive(_43); @@ -275,14 +275,14 @@ fn address_of_reborrow() -> () { StorageLive(_45); StorageLive(_46); _46 = &raw mut (*_3); - _45 = move _46 as *mut dyn std::marker::Send (Pointer(Unsize)); + _45 = move _46 as *mut dyn std::marker::Send (PointerCoercion(Unsize)); StorageDead(_46); FakeRead(ForLet(None), _45); AscribeUserType(_45, o, UserTypeProjection { base: UserType(27), projs: [] }); StorageLive(_47); StorageLive(_48); _48 = &raw mut (*_3); - _47 = move _48 as *mut [i32] (Pointer(Unsize)); + _47 = move _48 as *mut [i32] (PointerCoercion(Unsize)); StorageDead(_48); FakeRead(ForLet(None), _47); AscribeUserType(_47, o, UserTypeProjection { base: UserType(29), projs: [] }); diff --git a/tests/mir-opt/building/issue_110508.rs b/tests/mir-opt/building/issue_110508.rs new file mode 100644 index 0000000000000..bcbb1c2983090 --- /dev/null +++ b/tests/mir-opt/building/issue_110508.rs @@ -0,0 +1,13 @@ +// EMIT_MIR issue_110508.{impl#0}-BAR.built.after.mir +// EMIT_MIR issue_110508.{impl#0}-SELF_BAR.built.after.mir + +enum Foo { + Bar(()), +} + +impl Foo { + const BAR: Foo = Foo::Bar(()); + const SELF_BAR: Foo = Self::Bar(()); +} + +fn main() {} diff --git a/tests/mir-opt/building/issue_110508.{impl#0}-BAR.built.after.mir b/tests/mir-opt/building/issue_110508.{impl#0}-BAR.built.after.mir new file mode 100644 index 0000000000000..5fc6d911af354 --- /dev/null +++ b/tests/mir-opt/building/issue_110508.{impl#0}-BAR.built.after.mir @@ -0,0 +1,14 @@ +// MIR for `::BAR` after built + +const ::BAR: Foo = { + let mut _0: Foo; + let mut _1: (); + + bb0: { + StorageLive(_1); + _1 = (); + _0 = Foo::Bar(move _1); + StorageDead(_1); + return; + } +} diff --git a/tests/mir-opt/building/issue_110508.{impl#0}-SELF_BAR.built.after.mir b/tests/mir-opt/building/issue_110508.{impl#0}-SELF_BAR.built.after.mir new file mode 100644 index 0000000000000..1a8925599717e --- /dev/null +++ b/tests/mir-opt/building/issue_110508.{impl#0}-SELF_BAR.built.after.mir @@ -0,0 +1,14 @@ +// MIR for `::SELF_BAR` after built + +const ::SELF_BAR: Foo = { + let mut _0: Foo; + let mut _1: (); + + bb0: { + StorageLive(_1); + _1 = (); + _0 = Foo::Bar(move _1); + StorageDead(_1); + return; + } +} diff --git a/tests/mir-opt/building/receiver_ptr_mutability.main.built.after.mir b/tests/mir-opt/building/receiver_ptr_mutability.main.built.after.mir index b3db1d76ca706..fed5e68c3c97d 100644 --- a/tests/mir-opt/building/receiver_ptr_mutability.main.built.after.mir +++ b/tests/mir-opt/building/receiver_ptr_mutability.main.built.after.mir @@ -39,7 +39,7 @@ fn main() -> () { StorageLive(_3); StorageLive(_4); _4 = _1; - _3 = move _4 as *const Test (Pointer(MutToConstPointer)); + _3 = move _4 as *const Test (PointerCoercion(MutToConstPointer)); StorageDead(_4); _2 = Test::x(move _3) -> [return: bb2, unwind: bb4]; } @@ -64,7 +64,7 @@ fn main() -> () { StorageLive(_11); StorageLive(_12); _12 = (*(*(*(*_5)))); - _11 = move _12 as *const Test (Pointer(MutToConstPointer)); + _11 = move _12 as *const Test (PointerCoercion(MutToConstPointer)); StorageDead(_12); _10 = Test::x(move _11) -> [return: bb3, unwind: bb4]; } diff --git a/tests/mir-opt/building/storage_live_dead_in_statics.XXX.built.after.mir b/tests/mir-opt/building/storage_live_dead_in_statics.XXX.built.after.mir index 1d7adfde4edea..683f63065f76b 100644 --- a/tests/mir-opt/building/storage_live_dead_in_statics.XXX.built.after.mir +++ b/tests/mir-opt/building/storage_live_dead_in_statics.XXX.built.after.mir @@ -187,7 +187,7 @@ static XXX: &Foo = { StorageDead(_7); _5 = &_6; _4 = &(*_5); - _3 = move _4 as &[(u32, u32)] (Pointer(Unsize)); + _3 = move _4 as &[(u32, u32)] (PointerCoercion(Unsize)); StorageDead(_4); _2 = Foo { tup: const "hi", data: move _3 }; StorageDead(_3); diff --git a/tests/mir-opt/casts.roundtrip.PreCodegen.after.mir b/tests/mir-opt/casts.roundtrip.PreCodegen.after.mir index aca7b12c4c6d2..f0c35fe9782cb 100644 --- a/tests/mir-opt/casts.roundtrip.PreCodegen.after.mir +++ b/tests/mir-opt/casts.roundtrip.PreCodegen.after.mir @@ -8,7 +8,7 @@ fn roundtrip(_1: *const u8) -> *const u8 { bb0: { StorageLive(_2); _2 = _1 as *mut u8 (PtrToPtr); - _0 = move _2 as *const u8 (Pointer(MutToConstPointer)); + _0 = move _2 as *const u8 (PointerCoercion(MutToConstPointer)); StorageDead(_2); return; } diff --git a/tests/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff b/tests/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff index 0eee91469e648..14d2d7fc85cf9 100644 --- a/tests/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff +++ b/tests/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff @@ -22,7 +22,7 @@ - _2 = &_3; + _6 = const _; + _2 = &(*_6); - _1 = move _2 as &[&i32] (Pointer(Unsize)); + _1 = move _2 as &[&i32] (PointerCoercion(Unsize)); - StorageDead(_4); StorageDead(_2); _0 = core::slice::::as_ptr(move _1) -> [return: bb1, unwind: bb2]; diff --git a/tests/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff b/tests/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff index 0b117f4aaa51b..ffdd195eca367 100644 --- a/tests/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff +++ b/tests/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff @@ -24,7 +24,7 @@ - _2 = &_3; + _6 = const _; + _2 = &(*_6); - _1 = move _2 as &[&i32] (Pointer(Unsize)); + _1 = move _2 as &[&i32] (PointerCoercion(Unsize)); - StorageDead(_4); StorageDead(_2); _0 = core::slice::::as_ptr(move _1) -> [return: bb1, unwind: bb2]; diff --git a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.panic-abort.diff b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.panic-abort.diff index 6d5e34f23e845..30402df47c2c3 100644 --- a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.panic-abort.diff +++ b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.panic-abort.diff @@ -28,7 +28,7 @@ _9 = const _; _3 = &(*_9); _2 = &raw const (*_3); - _1 = move _2 as *const [i32] (Pointer(Unsize)); + _1 = move _2 as *const [i32] (PointerCoercion(Unsize)); StorageDead(_2); StorageDead(_3); StorageLive(_5); diff --git a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.panic-unwind.diff b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.panic-unwind.diff index 2c0e4844ecc3b..16d62daed2997 100644 --- a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.panic-unwind.diff +++ b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.panic-unwind.diff @@ -28,7 +28,7 @@ _9 = const _; _3 = &(*_9); _2 = &raw const (*_3); - _1 = move _2 as *const [i32] (Pointer(Unsize)); + _1 = move _2 as *const [i32] (PointerCoercion(Unsize)); StorageDead(_2); StorageDead(_3); StorageLive(_5); diff --git a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.panic-abort.diff b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.panic-abort.diff index 6d5e34f23e845..30402df47c2c3 100644 --- a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.panic-abort.diff +++ b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.panic-abort.diff @@ -28,7 +28,7 @@ _9 = const _; _3 = &(*_9); _2 = &raw const (*_3); - _1 = move _2 as *const [i32] (Pointer(Unsize)); + _1 = move _2 as *const [i32] (PointerCoercion(Unsize)); StorageDead(_2); StorageDead(_3); StorageLive(_5); diff --git a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.panic-unwind.diff b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.panic-unwind.diff index 2c0e4844ecc3b..16d62daed2997 100644 --- a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.panic-unwind.diff +++ b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.panic-unwind.diff @@ -28,7 +28,7 @@ _9 = const _; _3 = &(*_9); _2 = &raw const (*_3); - _1 = move _2 as *const [i32] (Pointer(Unsize)); + _1 = move _2 as *const [i32] (PointerCoercion(Unsize)); StorageDead(_2); StorageDead(_3); StorageLive(_5); diff --git a/tests/mir-opt/const_prop/reify_fn_ptr.main.ConstProp.diff b/tests/mir-opt/const_prop/reify_fn_ptr.main.ConstProp.diff index 533a92f78a50d..e7aa015d078ec 100644 --- a/tests/mir-opt/const_prop/reify_fn_ptr.main.ConstProp.diff +++ b/tests/mir-opt/const_prop/reify_fn_ptr.main.ConstProp.diff @@ -13,7 +13,7 @@ StorageLive(_1); StorageLive(_2); StorageLive(_3); - _3 = main as fn() (Pointer(ReifyFnPointer)); + _3 = main as fn() (PointerCoercion(ReifyFnPointer)); _2 = move _3 as usize (PointerExposeAddress); StorageDead(_3); _1 = move _2 as *const fn() (PointerFromExposedAddress); diff --git a/tests/mir-opt/const_prop/slice_len.main.ConstProp.32bit.panic-abort.diff b/tests/mir-opt/const_prop/slice_len.main.ConstProp.32bit.panic-abort.diff index 2f64a18510658..3c2b8e111cbe4 100644 --- a/tests/mir-opt/const_prop/slice_len.main.ConstProp.32bit.panic-abort.diff +++ b/tests/mir-opt/const_prop/slice_len.main.ConstProp.32bit.panic-abort.diff @@ -21,7 +21,7 @@ _9 = const _; _4 = _9; _3 = _4; - _2 = move _3 as &[u32] (Pointer(Unsize)); + _2 = move _3 as &[u32] (PointerCoercion(Unsize)); StorageDead(_3); StorageLive(_6); _6 = const 1_usize; diff --git a/tests/mir-opt/const_prop/slice_len.main.ConstProp.32bit.panic-unwind.diff b/tests/mir-opt/const_prop/slice_len.main.ConstProp.32bit.panic-unwind.diff index c0f290a9ab491..303096030b483 100644 --- a/tests/mir-opt/const_prop/slice_len.main.ConstProp.32bit.panic-unwind.diff +++ b/tests/mir-opt/const_prop/slice_len.main.ConstProp.32bit.panic-unwind.diff @@ -21,7 +21,7 @@ _9 = const _; _4 = _9; _3 = _4; - _2 = move _3 as &[u32] (Pointer(Unsize)); + _2 = move _3 as &[u32] (PointerCoercion(Unsize)); StorageDead(_3); StorageLive(_6); _6 = const 1_usize; diff --git a/tests/mir-opt/const_prop/slice_len.main.ConstProp.64bit.panic-abort.diff b/tests/mir-opt/const_prop/slice_len.main.ConstProp.64bit.panic-abort.diff index 2f64a18510658..3c2b8e111cbe4 100644 --- a/tests/mir-opt/const_prop/slice_len.main.ConstProp.64bit.panic-abort.diff +++ b/tests/mir-opt/const_prop/slice_len.main.ConstProp.64bit.panic-abort.diff @@ -21,7 +21,7 @@ _9 = const _; _4 = _9; _3 = _4; - _2 = move _3 as &[u32] (Pointer(Unsize)); + _2 = move _3 as &[u32] (PointerCoercion(Unsize)); StorageDead(_3); StorageLive(_6); _6 = const 1_usize; diff --git a/tests/mir-opt/const_prop/slice_len.main.ConstProp.64bit.panic-unwind.diff b/tests/mir-opt/const_prop/slice_len.main.ConstProp.64bit.panic-unwind.diff index c0f290a9ab491..303096030b483 100644 --- a/tests/mir-opt/const_prop/slice_len.main.ConstProp.64bit.panic-unwind.diff +++ b/tests/mir-opt/const_prop/slice_len.main.ConstProp.64bit.panic-unwind.diff @@ -21,7 +21,7 @@ _9 = const _; _4 = _9; _3 = _4; - _2 = move _3 as &[u32] (Pointer(Unsize)); + _2 = move _3 as &[u32] (PointerCoercion(Unsize)); StorageDead(_3); StorageLive(_6); _6 = const 1_usize; diff --git a/tests/mir-opt/copy-prop/issue_107511.main.CopyProp.panic-abort.diff b/tests/mir-opt/copy-prop/issue_107511.main.CopyProp.panic-abort.diff index a16d79d0e64f6..a802d0256d486 100644 --- a/tests/mir-opt/copy-prop/issue_107511.main.CopyProp.panic-abort.diff +++ b/tests/mir-opt/copy-prop/issue_107511.main.CopyProp.panic-abort.diff @@ -47,7 +47,7 @@ StorageLive(_6); StorageLive(_7); _7 = &_2; - _6 = move _7 as &[i32] (Pointer(Unsize)); + _6 = move _7 as &[i32] (PointerCoercion(Unsize)); StorageDead(_7); _5 = core::slice::::len(move _6) -> [return: bb1, unwind unreachable]; } diff --git a/tests/mir-opt/copy-prop/issue_107511.main.CopyProp.panic-unwind.diff b/tests/mir-opt/copy-prop/issue_107511.main.CopyProp.panic-unwind.diff index c2d892be35dc8..35f852098c354 100644 --- a/tests/mir-opt/copy-prop/issue_107511.main.CopyProp.panic-unwind.diff +++ b/tests/mir-opt/copy-prop/issue_107511.main.CopyProp.panic-unwind.diff @@ -47,7 +47,7 @@ StorageLive(_6); StorageLive(_7); _7 = &_2; - _6 = move _7 as &[i32] (Pointer(Unsize)); + _6 = move _7 as &[i32] (PointerCoercion(Unsize)); StorageDead(_7); _5 = core::slice::::len(move _6) -> [return: bb1, unwind continue]; } diff --git a/tests/mir-opt/inline/dyn_trait.get_query.Inline.panic-abort.diff b/tests/mir-opt/inline/dyn_trait.get_query.Inline.panic-abort.diff index 1f5e2428095bf..57b0849e111dc 100644 --- a/tests/mir-opt/inline/dyn_trait.get_query.Inline.panic-abort.diff +++ b/tests/mir-opt/inline/dyn_trait.get_query.Inline.panic-abort.diff @@ -31,7 +31,7 @@ _4 = &(*_2); - _0 = try_execute_query::<::C>(move _4) -> [return: bb2, unwind unreachable]; + StorageLive(_5); -+ _5 = _4 as &dyn Cache::V> (Pointer(Unsize)); ++ _5 = _4 as &dyn Cache::V> (PointerCoercion(Unsize)); + _0 = ::V> as Cache>::store_nocache(_5) -> [return: bb2, unwind unreachable]; } diff --git a/tests/mir-opt/inline/dyn_trait.get_query.Inline.panic-unwind.diff b/tests/mir-opt/inline/dyn_trait.get_query.Inline.panic-unwind.diff index 941ba24605cd5..706c1d481950b 100644 --- a/tests/mir-opt/inline/dyn_trait.get_query.Inline.panic-unwind.diff +++ b/tests/mir-opt/inline/dyn_trait.get_query.Inline.panic-unwind.diff @@ -31,7 +31,7 @@ _4 = &(*_2); - _0 = try_execute_query::<::C>(move _4) -> [return: bb2, unwind continue]; + StorageLive(_5); -+ _5 = _4 as &dyn Cache::V> (Pointer(Unsize)); ++ _5 = _4 as &dyn Cache::V> (PointerCoercion(Unsize)); + _0 = ::V> as Cache>::store_nocache(_5) -> [return: bb2, unwind continue]; } diff --git a/tests/mir-opt/inline/dyn_trait.try_execute_query.Inline.panic-abort.diff b/tests/mir-opt/inline/dyn_trait.try_execute_query.Inline.panic-abort.diff index 1e4c6fcca7ac2..9a6d3596fb96f 100644 --- a/tests/mir-opt/inline/dyn_trait.try_execute_query.Inline.panic-abort.diff +++ b/tests/mir-opt/inline/dyn_trait.try_execute_query.Inline.panic-abort.diff @@ -14,7 +14,7 @@ StorageLive(_2); StorageLive(_3); _3 = &(*_1); - _2 = move _3 as &dyn Cache::V> (Pointer(Unsize)); + _2 = move _3 as &dyn Cache::V> (PointerCoercion(Unsize)); StorageDead(_3); - _0 = mk_cycle::<::V>(move _2) -> [return: bb1, unwind unreachable]; + _0 = ::V> as Cache>::store_nocache(_2) -> [return: bb1, unwind unreachable]; diff --git a/tests/mir-opt/inline/dyn_trait.try_execute_query.Inline.panic-unwind.diff b/tests/mir-opt/inline/dyn_trait.try_execute_query.Inline.panic-unwind.diff index 5e30da400d294..1a08df2b09b9d 100644 --- a/tests/mir-opt/inline/dyn_trait.try_execute_query.Inline.panic-unwind.diff +++ b/tests/mir-opt/inline/dyn_trait.try_execute_query.Inline.panic-unwind.diff @@ -14,7 +14,7 @@ StorageLive(_2); StorageLive(_3); _3 = &(*_1); - _2 = move _3 as &dyn Cache::V> (Pointer(Unsize)); + _2 = move _3 as &dyn Cache::V> (PointerCoercion(Unsize)); StorageDead(_3); - _0 = mk_cycle::<::V>(move _2) -> [return: bb1, unwind continue]; + _0 = ::V> as Cache>::store_nocache(_2) -> [return: bb1, unwind continue]; diff --git a/tests/mir-opt/inline/inline_into_box_place.main.Inline.panic-abort.diff b/tests/mir-opt/inline/inline_into_box_place.main.Inline.panic-abort.diff index f3a6923415a14..dfc00026ad0c9 100644 --- a/tests/mir-opt/inline/inline_into_box_place.main.Inline.panic-abort.diff +++ b/tests/mir-opt/inline/inline_into_box_place.main.Inline.panic-abort.diff @@ -164,7 +164,7 @@ + StorageDead(_17); + StorageLive(_19); + StorageLive(_20); -+ _19 = _16 as *const u8 (Pointer(MutToConstPointer)); ++ _19 = _16 as *const u8 (PointerCoercion(MutToConstPointer)); + _15 = NonNull:: { pointer: _19 }; + StorageDead(_20); + StorageDead(_19); diff --git a/tests/mir-opt/inline/inline_into_box_place.main.Inline.panic-unwind.diff b/tests/mir-opt/inline/inline_into_box_place.main.Inline.panic-unwind.diff index 0b643b3c7a921..f582adda88fd6 100644 --- a/tests/mir-opt/inline/inline_into_box_place.main.Inline.panic-unwind.diff +++ b/tests/mir-opt/inline/inline_into_box_place.main.Inline.panic-unwind.diff @@ -181,7 +181,7 @@ + StorageDead(_17); + StorageLive(_19); + StorageLive(_20); -+ _19 = _16 as *const u8 (Pointer(MutToConstPointer)); ++ _19 = _16 as *const u8 (PointerCoercion(MutToConstPointer)); + _15 = NonNull:: { pointer: _19 }; + StorageDead(_20); + StorageDead(_19); diff --git a/tests/mir-opt/inline/inline_trait_method_2.test2.Inline.after.panic-abort.mir b/tests/mir-opt/inline/inline_trait_method_2.test2.Inline.after.panic-abort.mir index 62c0805548bc7..503f153089cee 100644 --- a/tests/mir-opt/inline/inline_trait_method_2.test2.Inline.after.panic-abort.mir +++ b/tests/mir-opt/inline/inline_trait_method_2.test2.Inline.after.panic-abort.mir @@ -13,7 +13,7 @@ fn test2(_1: &dyn X) -> bool { StorageLive(_2); StorageLive(_3); _3 = &(*_1); - _2 = move _3 as &dyn X (Pointer(Unsize)); + _2 = move _3 as &dyn X (PointerCoercion(Unsize)); StorageDead(_3); _0 = ::y(_2) -> [return: bb1, unwind unreachable]; } diff --git a/tests/mir-opt/inline/inline_trait_method_2.test2.Inline.after.panic-unwind.mir b/tests/mir-opt/inline/inline_trait_method_2.test2.Inline.after.panic-unwind.mir index 5d4979680a48b..37bb53e79c64d 100644 --- a/tests/mir-opt/inline/inline_trait_method_2.test2.Inline.after.panic-unwind.mir +++ b/tests/mir-opt/inline/inline_trait_method_2.test2.Inline.after.panic-unwind.mir @@ -13,7 +13,7 @@ fn test2(_1: &dyn X) -> bool { StorageLive(_2); StorageLive(_3); _3 = &(*_1); - _2 = move _3 as &dyn X (Pointer(Unsize)); + _2 = move _3 as &dyn X (PointerCoercion(Unsize)); StorageDead(_3); _0 = ::y(_2) -> [return: bb1, unwind continue]; } diff --git a/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-abort.diff b/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-abort.diff index f2a925273dbb5..1cc44ce06cff6 100644 --- a/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-abort.diff +++ b/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-abort.diff @@ -32,7 +32,7 @@ StorageLive(_5); _5 = [_1, _1, _1]; _4 = &_5; - _2 = _4 as &[T] (Pointer(Unsize)); + _2 = _4 as &[T] (PointerCoercion(Unsize)); _9 = Len((*_2)); _10 = const 3_usize; - _11 = Eq(move _9, const 3_usize); diff --git a/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-unwind.diff b/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-unwind.diff index 25df839c2db9d..b708f667438e6 100644 --- a/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-unwind.diff +++ b/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-unwind.diff @@ -32,7 +32,7 @@ StorageLive(_5); _5 = [_1, _1, _1]; _4 = &_5; - _2 = _4 as &[T] (Pointer(Unsize)); + _2 = _4 as &[T] (PointerCoercion(Unsize)); _9 = Len((*_2)); _10 = const 3_usize; - _11 = Eq(move _9, const 3_usize); diff --git a/tests/mir-opt/lower_array_len.array_bound.NormalizeArrayLen.panic-abort.diff b/tests/mir-opt/lower_array_len.array_bound.NormalizeArrayLen.panic-abort.diff index de6c2366dbb30..6174d5259d0a0 100644 --- a/tests/mir-opt/lower_array_len.array_bound.NormalizeArrayLen.panic-abort.diff +++ b/tests/mir-opt/lower_array_len.array_bound.NormalizeArrayLen.panic-abort.diff @@ -22,7 +22,7 @@ StorageLive(_6); StorageLive(_7); _7 = &(*_2); - _6 = move _7 as &[u8] (Pointer(Unsize)); + _6 = move _7 as &[u8] (PointerCoercion(Unsize)); StorageDead(_7); - _5 = Len((*_6)); + _5 = const N; diff --git a/tests/mir-opt/lower_array_len.array_bound.NormalizeArrayLen.panic-unwind.diff b/tests/mir-opt/lower_array_len.array_bound.NormalizeArrayLen.panic-unwind.diff index 1cba0f27afaab..60c0772d8ecc2 100644 --- a/tests/mir-opt/lower_array_len.array_bound.NormalizeArrayLen.panic-unwind.diff +++ b/tests/mir-opt/lower_array_len.array_bound.NormalizeArrayLen.panic-unwind.diff @@ -22,7 +22,7 @@ StorageLive(_6); StorageLive(_7); _7 = &(*_2); - _6 = move _7 as &[u8] (Pointer(Unsize)); + _6 = move _7 as &[u8] (PointerCoercion(Unsize)); StorageDead(_7); - _5 = Len((*_6)); + _5 = const N; diff --git a/tests/mir-opt/lower_array_len.array_bound_mut.NormalizeArrayLen.panic-abort.diff b/tests/mir-opt/lower_array_len.array_bound_mut.NormalizeArrayLen.panic-abort.diff index 76175afc2f827..e2de184529689 100644 --- a/tests/mir-opt/lower_array_len.array_bound_mut.NormalizeArrayLen.panic-abort.diff +++ b/tests/mir-opt/lower_array_len.array_bound_mut.NormalizeArrayLen.panic-abort.diff @@ -25,7 +25,7 @@ StorageLive(_6); StorageLive(_7); _7 = &(*_2); - _6 = move _7 as &[u8] (Pointer(Unsize)); + _6 = move _7 as &[u8] (PointerCoercion(Unsize)); StorageDead(_7); - _5 = Len((*_6)); + _5 = const N; diff --git a/tests/mir-opt/lower_array_len.array_bound_mut.NormalizeArrayLen.panic-unwind.diff b/tests/mir-opt/lower_array_len.array_bound_mut.NormalizeArrayLen.panic-unwind.diff index 6c450067cc4a3..eb81e0eea2cf0 100644 --- a/tests/mir-opt/lower_array_len.array_bound_mut.NormalizeArrayLen.panic-unwind.diff +++ b/tests/mir-opt/lower_array_len.array_bound_mut.NormalizeArrayLen.panic-unwind.diff @@ -25,7 +25,7 @@ StorageLive(_6); StorageLive(_7); _7 = &(*_2); - _6 = move _7 as &[u8] (Pointer(Unsize)); + _6 = move _7 as &[u8] (PointerCoercion(Unsize)); StorageDead(_7); - _5 = Len((*_6)); + _5 = const N; diff --git a/tests/mir-opt/lower_array_len.array_len.NormalizeArrayLen.panic-abort.diff b/tests/mir-opt/lower_array_len.array_len.NormalizeArrayLen.panic-abort.diff index a20d5288c402f..1bdc62183c37f 100644 --- a/tests/mir-opt/lower_array_len.array_len.NormalizeArrayLen.panic-abort.diff +++ b/tests/mir-opt/lower_array_len.array_len.NormalizeArrayLen.panic-abort.diff @@ -11,7 +11,7 @@ StorageLive(_2); StorageLive(_3); _3 = &(*_1); - _2 = move _3 as &[u8] (Pointer(Unsize)); + _2 = move _3 as &[u8] (PointerCoercion(Unsize)); StorageDead(_3); - _0 = Len((*_2)); + _0 = const N; diff --git a/tests/mir-opt/lower_array_len.array_len.NormalizeArrayLen.panic-unwind.diff b/tests/mir-opt/lower_array_len.array_len.NormalizeArrayLen.panic-unwind.diff index a20d5288c402f..1bdc62183c37f 100644 --- a/tests/mir-opt/lower_array_len.array_len.NormalizeArrayLen.panic-unwind.diff +++ b/tests/mir-opt/lower_array_len.array_len.NormalizeArrayLen.panic-unwind.diff @@ -11,7 +11,7 @@ StorageLive(_2); StorageLive(_3); _3 = &(*_1); - _2 = move _3 as &[u8] (Pointer(Unsize)); + _2 = move _3 as &[u8] (PointerCoercion(Unsize)); StorageDead(_3); - _0 = Len((*_2)); + _0 = const N; diff --git a/tests/mir-opt/lower_array_len.array_len_by_value.NormalizeArrayLen.panic-abort.diff b/tests/mir-opt/lower_array_len.array_len_by_value.NormalizeArrayLen.panic-abort.diff index c3842bf4edcde..9862b2fad8eec 100644 --- a/tests/mir-opt/lower_array_len.array_len_by_value.NormalizeArrayLen.panic-abort.diff +++ b/tests/mir-opt/lower_array_len.array_len_by_value.NormalizeArrayLen.panic-abort.diff @@ -11,7 +11,7 @@ StorageLive(_2); StorageLive(_3); _3 = &_1; - _2 = move _3 as &[u8] (Pointer(Unsize)); + _2 = move _3 as &[u8] (PointerCoercion(Unsize)); StorageDead(_3); - _0 = Len((*_2)); + _0 = const N; diff --git a/tests/mir-opt/lower_array_len.array_len_by_value.NormalizeArrayLen.panic-unwind.diff b/tests/mir-opt/lower_array_len.array_len_by_value.NormalizeArrayLen.panic-unwind.diff index c3842bf4edcde..9862b2fad8eec 100644 --- a/tests/mir-opt/lower_array_len.array_len_by_value.NormalizeArrayLen.panic-unwind.diff +++ b/tests/mir-opt/lower_array_len.array_len_by_value.NormalizeArrayLen.panic-unwind.diff @@ -11,7 +11,7 @@ StorageLive(_2); StorageLive(_3); _3 = &_1; - _2 = move _3 as &[u8] (Pointer(Unsize)); + _2 = move _3 as &[u8] (PointerCoercion(Unsize)); StorageDead(_3); - _0 = Len((*_2)); + _0 = const N; diff --git a/tests/mir-opt/lower_array_len.array_len_raw.NormalizeArrayLen.panic-abort.diff b/tests/mir-opt/lower_array_len.array_len_raw.NormalizeArrayLen.panic-abort.diff index c407482d17b61..f9f73bf991d13 100644 --- a/tests/mir-opt/lower_array_len.array_len_raw.NormalizeArrayLen.panic-abort.diff +++ b/tests/mir-opt/lower_array_len.array_len_raw.NormalizeArrayLen.panic-abort.diff @@ -25,7 +25,7 @@ StorageLive(_4); _4 = &_1; _3 = &(*_4); - _2 = move _3 as &[u8] (Pointer(Unsize)); + _2 = move _3 as &[u8] (PointerCoercion(Unsize)); StorageDead(_3); StorageDead(_4); StorageLive(_5); diff --git a/tests/mir-opt/lower_array_len.array_len_raw.NormalizeArrayLen.panic-unwind.diff b/tests/mir-opt/lower_array_len.array_len_raw.NormalizeArrayLen.panic-unwind.diff index c407482d17b61..f9f73bf991d13 100644 --- a/tests/mir-opt/lower_array_len.array_len_raw.NormalizeArrayLen.panic-unwind.diff +++ b/tests/mir-opt/lower_array_len.array_len_raw.NormalizeArrayLen.panic-unwind.diff @@ -25,7 +25,7 @@ StorageLive(_4); _4 = &_1; _3 = &(*_4); - _2 = move _3 as &[u8] (Pointer(Unsize)); + _2 = move _3 as &[u8] (PointerCoercion(Unsize)); StorageDead(_3); StorageDead(_4); StorageLive(_5); diff --git a/tests/mir-opt/lower_array_len.array_len_reborrow.NormalizeArrayLen.panic-abort.diff b/tests/mir-opt/lower_array_len.array_len_reborrow.NormalizeArrayLen.panic-abort.diff index f50f7baa6e340..ecba06a2e4de7 100644 --- a/tests/mir-opt/lower_array_len.array_len_reborrow.NormalizeArrayLen.panic-abort.diff +++ b/tests/mir-opt/lower_array_len.array_len_reborrow.NormalizeArrayLen.panic-abort.diff @@ -22,7 +22,7 @@ StorageLive(_4); _4 = &mut _1; _3 = &mut (*_4); - _2 = move _3 as &mut [u8] (Pointer(Unsize)); + _2 = move _3 as &mut [u8] (PointerCoercion(Unsize)); StorageDead(_3); StorageDead(_4); StorageLive(_5); diff --git a/tests/mir-opt/lower_array_len.array_len_reborrow.NormalizeArrayLen.panic-unwind.diff b/tests/mir-opt/lower_array_len.array_len_reborrow.NormalizeArrayLen.panic-unwind.diff index f50f7baa6e340..ecba06a2e4de7 100644 --- a/tests/mir-opt/lower_array_len.array_len_reborrow.NormalizeArrayLen.panic-unwind.diff +++ b/tests/mir-opt/lower_array_len.array_len_reborrow.NormalizeArrayLen.panic-unwind.diff @@ -22,7 +22,7 @@ StorageLive(_4); _4 = &mut _1; _3 = &mut (*_4); - _2 = move _3 as &mut [u8] (Pointer(Unsize)); + _2 = move _3 as &mut [u8] (PointerCoercion(Unsize)); StorageDead(_3); StorageDead(_4); StorageLive(_5); diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir index a337ca89992a6..e07e2bb7bfe58 100644 --- a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir @@ -78,7 +78,7 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range) -> StorageLive(_12); StorageLive(_11); StorageLive(_10); - _10 = _9 as *const () (Pointer(MutToConstPointer)); + _10 = _9 as *const () (PointerCoercion(MutToConstPointer)); _11 = ptr::metadata::PtrComponents::<[u32]> { data_address: move _10, metadata: _6 }; StorageDead(_10); _12 = ptr::metadata::PtrRepr::<[u32]> { const_ptr: move _11 }; diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir index a337ca89992a6..e07e2bb7bfe58 100644 --- a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir @@ -78,7 +78,7 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range) -> StorageLive(_12); StorageLive(_11); StorageLive(_10); - _10 = _9 as *const () (Pointer(MutToConstPointer)); + _10 = _9 as *const () (PointerCoercion(MutToConstPointer)); _11 = ptr::metadata::PtrComponents::<[u32]> { data_address: move _10, metadata: _6 }; StorageDead(_10); _12 = ptr::metadata::PtrRepr::<[u32]> { const_ptr: move _11 }; diff --git a/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-abort.mir index 1e401c60bf3ec..d1ab16697a606 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-abort.mir @@ -131,7 +131,7 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { _9 = _4 as *mut T (PtrToPtr); StorageLive(_10); StorageLive(_24); - _10 = _9 as *const T (Pointer(MutToConstPointer)); + _10 = _9 as *const T (PointerCoercion(MutToConstPointer)); _11 = NonNull:: { pointer: _10 }; StorageDead(_24); StorageDead(_10); diff --git a/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-unwind.mir index 8294a5cb6dc50..03751f7fdf719 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-unwind.mir @@ -131,7 +131,7 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { _9 = _4 as *mut T (PtrToPtr); StorageLive(_10); StorageLive(_24); - _10 = _9 as *const T (Pointer(MutToConstPointer)); + _10 = _9 as *const T (PointerCoercion(MutToConstPointer)); _11 = NonNull:: { pointer: _10 }; StorageDead(_24); StorageDead(_10); diff --git a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-abort.mir index c1c7861b9c9e6..db971e10f3225 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-abort.mir @@ -121,7 +121,7 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { _9 = _4 as *mut T (PtrToPtr); StorageLive(_10); StorageLive(_22); - _10 = _9 as *const T (Pointer(MutToConstPointer)); + _10 = _9 as *const T (PointerCoercion(MutToConstPointer)); _11 = NonNull:: { pointer: _10 }; StorageDead(_22); StorageDead(_10); diff --git a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-unwind.mir index ff40e450968a5..74597799168f4 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-unwind.mir @@ -121,7 +121,7 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { _9 = _4 as *mut T (PtrToPtr); StorageLive(_10); StorageLive(_22); - _10 = _9 as *const T (Pointer(MutToConstPointer)); + _10 = _9 as *const T (PointerCoercion(MutToConstPointer)); _11 = NonNull:: { pointer: _10 }; StorageDead(_22); StorageDead(_10); diff --git a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir index 851d331136517..e546140e0c17e 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir @@ -133,7 +133,7 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { _9 = _4 as *mut T (PtrToPtr); StorageLive(_10); StorageLive(_24); - _10 = _9 as *const T (Pointer(MutToConstPointer)); + _10 = _9 as *const T (PointerCoercion(MutToConstPointer)); _11 = NonNull:: { pointer: _10 }; StorageDead(_24); StorageDead(_10); diff --git a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir index b40d9209d2538..551cac46bdf5f 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir @@ -133,7 +133,7 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { _9 = _4 as *mut T (PtrToPtr); StorageLive(_10); StorageLive(_24); - _10 = _9 as *const T (Pointer(MutToConstPointer)); + _10 = _9 as *const T (PointerCoercion(MutToConstPointer)); _11 = NonNull:: { pointer: _10 }; StorageDead(_24); StorageDead(_10); diff --git a/tests/mir-opt/retag.array_casts.SimplifyCfg-elaborate-drops.after.panic-abort.mir b/tests/mir-opt/retag.array_casts.SimplifyCfg-elaborate-drops.after.panic-abort.mir index 3c48e798ef73a..70efdbf4b34d9 100644 --- a/tests/mir-opt/retag.array_casts.SimplifyCfg-elaborate-drops.after.panic-abort.mir +++ b/tests/mir-opt/retag.array_casts.SimplifyCfg-elaborate-drops.after.panic-abort.mir @@ -69,7 +69,7 @@ fn array_casts() -> () { StorageLive(_4); _4 = &mut _1; _3 = &raw mut (*_4); - _2 = move _3 as *mut usize (Pointer(ArrayToPointer)); + _2 = move _3 as *mut usize (PointerCoercion(ArrayToPointer)); StorageDead(_3); StorageDead(_4); StorageLive(_5); @@ -92,7 +92,7 @@ fn array_casts() -> () { StorageLive(_11); _11 = &_8; _10 = &raw const (*_11); - _9 = move _10 as *const usize (Pointer(ArrayToPointer)); + _9 = move _10 as *const usize (PointerCoercion(ArrayToPointer)); StorageDead(_10); StorageDead(_11); StorageLive(_12); diff --git a/tests/mir-opt/retag.array_casts.SimplifyCfg-elaborate-drops.after.panic-unwind.mir b/tests/mir-opt/retag.array_casts.SimplifyCfg-elaborate-drops.after.panic-unwind.mir index 93f14af29b4e9..cfa9628d49841 100644 --- a/tests/mir-opt/retag.array_casts.SimplifyCfg-elaborate-drops.after.panic-unwind.mir +++ b/tests/mir-opt/retag.array_casts.SimplifyCfg-elaborate-drops.after.panic-unwind.mir @@ -69,7 +69,7 @@ fn array_casts() -> () { StorageLive(_4); _4 = &mut _1; _3 = &raw mut (*_4); - _2 = move _3 as *mut usize (Pointer(ArrayToPointer)); + _2 = move _3 as *mut usize (PointerCoercion(ArrayToPointer)); StorageDead(_3); StorageDead(_4); StorageLive(_5); @@ -92,7 +92,7 @@ fn array_casts() -> () { StorageLive(_11); _11 = &_8; _10 = &raw const (*_11); - _9 = move _10 as *const usize (Pointer(ArrayToPointer)); + _9 = move _10 as *const usize (PointerCoercion(ArrayToPointer)); StorageDead(_10); StorageDead(_11); StorageLive(_12); diff --git a/tests/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.panic-abort.mir b/tests/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.panic-abort.mir index 606a8ec44ecbe..fb37bec109a07 100644 --- a/tests/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.panic-abort.mir +++ b/tests/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.panic-abort.mir @@ -105,7 +105,7 @@ fn main() -> () { StorageLive(_14); _14 = [closure@main::{closure#0}]; Retag(_14); - _13 = move _14 as for<'a> fn(&'a i32) -> &'a i32 (Pointer(ClosureFnPointer(Normal))); + _13 = move _14 as for<'a> fn(&'a i32) -> &'a i32 (PointerCoercion(ClosureFnPointer(Normal))); StorageDead(_14); StorageLive(_15); StorageLive(_16); diff --git a/tests/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.panic-unwind.mir b/tests/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.panic-unwind.mir index 4503494632874..508f964099a16 100644 --- a/tests/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.panic-unwind.mir +++ b/tests/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.panic-unwind.mir @@ -105,7 +105,7 @@ fn main() -> () { StorageLive(_14); _14 = [closure@main::{closure#0}]; Retag(_14); - _13 = move _14 as for<'a> fn(&'a i32) -> &'a i32 (Pointer(ClosureFnPointer(Normal))); + _13 = move _14 as for<'a> fn(&'a i32) -> &'a i32 (PointerCoercion(ClosureFnPointer(Normal))); StorageDead(_14); StorageLive(_15); StorageLive(_16); diff --git a/tests/mir-opt/simplify_locals.c.SimplifyLocals-before-const-prop.diff b/tests/mir-opt/simplify_locals.c.SimplifyLocals-before-const-prop.diff index 7546b3878d681..7cc5e335cb00a 100644 --- a/tests/mir-opt/simplify_locals.c.SimplifyLocals-before-const-prop.diff +++ b/tests/mir-opt/simplify_locals.c.SimplifyLocals-before-const-prop.diff @@ -21,7 +21,7 @@ - StorageLive(_4); - _4 = &_1; - _3 = &(*_4); -- _2 = move _3 as &[u8] (Pointer(Unsize)); +- _2 = move _3 as &[u8] (PointerCoercion(Unsize)); - StorageDead(_3); - StorageDead(_4); - StorageDead(_2); diff --git a/tests/mir-opt/sroa/lifetimes.foo.ScalarReplacementOfAggregates.diff b/tests/mir-opt/sroa/lifetimes.foo.ScalarReplacementOfAggregates.diff index 84247c0e8d513..bb14b909a956c 100644 --- a/tests/mir-opt/sroa/lifetimes.foo.ScalarReplacementOfAggregates.diff +++ b/tests/mir-opt/sroa/lifetimes.foo.ScalarReplacementOfAggregates.diff @@ -62,7 +62,7 @@ } bb1: { - _3 = move _4 as std::boxed::Box (Pointer(Unsize)); + _3 = move _4 as std::boxed::Box (PointerCoercion(Unsize)); StorageDead(_4); _2 = Result::, ::Err>::Ok(move _3); StorageDead(_3); @@ -95,7 +95,7 @@ _26 = const _; _14 = &(*_26); _13 = &(*_14); - _12 = move _13 as &[&str] (Pointer(Unsize)); + _12 = move _13 as &[&str] (PointerCoercion(Unsize)); StorageDead(_13); StorageLive(_16); StorageLive(_17); @@ -126,7 +126,7 @@ StorageDead(_20); _18 = &_19; _17 = &(*_18); - _16 = move _17 as &[core::fmt::rt::Argument<'_>] (Pointer(Unsize)); + _16 = move _17 as &[core::fmt::rt::Argument<'_>] (PointerCoercion(Unsize)); StorageDead(_17); _11 = Arguments::<'_>::new_v1(move _12, move _16) -> [return: bb5, unwind unreachable]; } diff --git a/tests/run-coverage/uses_crate.coverage b/tests/run-coverage/uses_crate.coverage index a3b78e21405a1..ccdcf35033499 100644 --- a/tests/run-coverage/uses_crate.coverage +++ b/tests/run-coverage/uses_crate.coverage @@ -148,8 +148,8 @@ $DIR/auxiliary/used_crate.rs: 100| |// `unused_generic_function()`, below. $DIR/uses_crate.rs: - 1| |// FIXME #110395 - 2| |// ignore-linux + 1| |// This test was failing on Linux for a while due to #110393 somehow making + 2| |// the unused functions not instrumented, but it seems to be fine now. 3| | 4| |// Validates coverage now works with optimizations 5| |// compile-flags: -C opt-level=3 diff --git a/tests/run-coverage/uses_crate.rs b/tests/run-coverage/uses_crate.rs index ab466970f8e99..ab203ad781d66 100644 --- a/tests/run-coverage/uses_crate.rs +++ b/tests/run-coverage/uses_crate.rs @@ -1,5 +1,5 @@ -// FIXME #110395 -// ignore-linux +// This test was failing on Linux for a while due to #110393 somehow making +// the unused functions not instrumented, but it seems to be fine now. // Validates coverage now works with optimizations // compile-flags: -C opt-level=3 diff --git a/tests/run-coverage/uses_inline_crate.coverage b/tests/run-coverage/uses_inline_crate.coverage index f878d8107c53f..64308c796d6f5 100644 --- a/tests/run-coverage/uses_inline_crate.coverage +++ b/tests/run-coverage/uses_inline_crate.coverage @@ -139,8 +139,8 @@ $DIR/auxiliary/used_inline_crate.rs: 90| 2|} $DIR/uses_inline_crate.rs: - 1| |// FIXME #110395 - 2| |// ignore-linux + 1| |// This test was failing on Linux for a while due to #110393 somehow making + 2| |// the unused functions not instrumented, but it seems to be fine now. 3| | 4| |// Validates coverage now works with optimizations 5| |// compile-flags: -C opt-level=3 diff --git a/tests/run-coverage/uses_inline_crate.rs b/tests/run-coverage/uses_inline_crate.rs index 4bd66d2f89cb8..d7b4c3c057f46 100644 --- a/tests/run-coverage/uses_inline_crate.rs +++ b/tests/run-coverage/uses_inline_crate.rs @@ -1,5 +1,5 @@ -// FIXME #110395 -// ignore-linux +// This test was failing on Linux for a while due to #110393 somehow making +// the unused functions not instrumented, but it seems to be fine now. // Validates coverage now works with optimizations // compile-flags: -C opt-level=3 diff --git a/tests/run-make/wasm-exceptions-nostd/Makefile b/tests/run-make/wasm-exceptions-nostd/Makefile new file mode 100644 index 0000000000000..34755ec14b745 --- /dev/null +++ b/tests/run-make/wasm-exceptions-nostd/Makefile @@ -0,0 +1,12 @@ +include ../tools.mk + +# only-wasm32-bare + +# Add a few command line args to make exceptions work +RUSTC := $(RUSTC) -C llvm-args=-wasm-enable-eh +RUSTC := $(RUSTC) -C target-feature=+exception-handling +RUSTC := $(RUSTC) -C panic=unwind + +all: + $(RUSTC) src/lib.rs --target wasm32-unknown-unknown + $(NODE) verify.mjs $(TMPDIR)/lib.wasm diff --git a/tests/run-make/wasm-exceptions-nostd/src/arena_alloc.rs b/tests/run-make/wasm-exceptions-nostd/src/arena_alloc.rs new file mode 100644 index 0000000000000..572d253309cee --- /dev/null +++ b/tests/run-make/wasm-exceptions-nostd/src/arena_alloc.rs @@ -0,0 +1,67 @@ +use core::alloc::{GlobalAlloc, Layout}; +use core::cell::UnsafeCell; + +#[global_allocator] +static ALLOCATOR: ArenaAllocator = ArenaAllocator::new(); + +/// Very simple allocator which never deallocates memory +/// +/// Based on the example from +/// https://doc.rust-lang.org/stable/std/alloc/trait.GlobalAlloc.html +pub struct ArenaAllocator { + arena: UnsafeCell, +} + +impl ArenaAllocator { + pub const fn new() -> Self { + Self { + arena: UnsafeCell::new(Arena::new()), + } + } +} + +/// Safe because we are singlethreaded +unsafe impl Sync for ArenaAllocator {} + +unsafe impl GlobalAlloc for ArenaAllocator { + unsafe fn alloc(&self, layout: Layout) -> *mut u8 { + let arena = &mut *self.arena.get(); + arena.alloc(layout) + } + + unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {} +} + +const ARENA_SIZE: usize = 64 * 1024; // more than enough + +#[repr(C, align(4096))] +struct Arena { + buf: [u8; ARENA_SIZE], // aligned at 4096 + allocated: usize, +} + +impl Arena { + pub const fn new() -> Self { + Self { + buf: [0x55; ARENA_SIZE], + allocated: 0, + } + } + + pub unsafe fn alloc(&mut self, layout: Layout) -> *mut u8 { + if layout.align() > 4096 || layout.size() > ARENA_SIZE { + return core::ptr::null_mut(); + } + + let align_minus_one = layout.align() - 1; + let start = (self.allocated + align_minus_one) & !align_minus_one; // round up + let new_cursor = start + layout.size(); + + if new_cursor >= ARENA_SIZE { + return core::ptr::null_mut(); + } + + self.allocated = new_cursor; + self.buf.as_mut_ptr().add(start) + } +} diff --git a/tests/run-make/wasm-exceptions-nostd/src/lib.rs b/tests/run-make/wasm-exceptions-nostd/src/lib.rs new file mode 100644 index 0000000000000..7049d2fd9e0d1 --- /dev/null +++ b/tests/run-make/wasm-exceptions-nostd/src/lib.rs @@ -0,0 +1,60 @@ +#![no_std] +#![crate_type = "cdylib"] + +// Allow a few unstable features because we create a panic +// runtime for native wasm exceptions from scratch + +#![feature(core_intrinsics)] +#![feature(lang_items)] +#![feature(link_llvm_intrinsics)] +#![feature(panic_info_message)] + +extern crate alloc; + +/// This module allows us to use `Box`, `String`, ... even in no-std +mod arena_alloc; + +/// This module allows logging text, even in no-std +mod logging; + +/// This module allows exceptions, even in no-std +#[cfg(target_arch = "wasm32")] +mod panicking; + +use alloc::boxed::Box; +use alloc::string::String; + +struct LogOnDrop; + +impl Drop for LogOnDrop { + fn drop(&mut self) { + logging::log_str("Dropped"); + } +} + +#[allow(unreachable_code)] +#[allow(unconditional_panic)] +#[no_mangle] +pub extern "C" fn start() -> usize { + let data = 0x1234usize as *mut u8; // Something to recognize + + unsafe { + core::intrinsics::r#try(|data: *mut u8| { + let _log_on_drop = LogOnDrop; + + logging::log_str(&alloc::format!("`r#try` called with ptr {:?}", data)); + let x = [12]; + let _ = x[4]; // should panic + + logging::log_str("This line should not be visible! :("); + }, data, |data, exception| { + let exception = *Box::from_raw(exception as *mut String); + logging::log_str("Caught something!"); + logging::log_str(&alloc::format!(" data : {:?}", data)); + logging::log_str(&alloc::format!(" exception: {:?}", exception)); + }); + } + + logging::log_str("This program terminates correctly."); + 0 +} diff --git a/tests/run-make/wasm-exceptions-nostd/src/logging.rs b/tests/run-make/wasm-exceptions-nostd/src/logging.rs new file mode 100644 index 0000000000000..569d03ec82f57 --- /dev/null +++ b/tests/run-make/wasm-exceptions-nostd/src/logging.rs @@ -0,0 +1,9 @@ +extern "C" { + fn __log_utf8(ptr: *const u8, size: usize); +} + +pub fn log_str(text: &str) { + unsafe { + __log_utf8(text.as_ptr(), text.len()); + } +} diff --git a/tests/run-make/wasm-exceptions-nostd/src/panicking.rs b/tests/run-make/wasm-exceptions-nostd/src/panicking.rs new file mode 100644 index 0000000000000..4a8923fd43db6 --- /dev/null +++ b/tests/run-make/wasm-exceptions-nostd/src/panicking.rs @@ -0,0 +1,29 @@ +#[lang = "eh_personality"] +fn eh_personality() {} + +mod internal { + extern "C" { + #[link_name = "llvm.wasm.throw"] + pub fn wasm_throw(tag: i32, ptr: *mut u8) -> !; + } +} + +unsafe fn wasm_throw(ptr: *mut u8) -> ! { + internal::wasm_throw(0, ptr); +} + +#[panic_handler] +fn panic_handler(info: &core::panic::PanicInfo<'_>) -> ! { + use alloc::boxed::Box; + use alloc::string::ToString; + + let msg = info + .message() + .map(|msg| msg.to_string()) + .unwrap_or("(no message)".to_string()); + let exception = Box::new(msg.to_string()); + unsafe { + let exception_raw = Box::into_raw(exception); + wasm_throw(exception_raw as *mut u8); + } +} diff --git a/tests/run-make/wasm-exceptions-nostd/verify.mjs b/tests/run-make/wasm-exceptions-nostd/verify.mjs new file mode 100644 index 0000000000000..e6c44d89d331d --- /dev/null +++ b/tests/run-make/wasm-exceptions-nostd/verify.mjs @@ -0,0 +1,75 @@ +import fs from 'fs'; + +const dec = new TextDecoder("utf-8"); + +if (process.argv.length != 3) { + console.log("Usage: node verify.mjs "); + process.exit(0); +} + +const wasmfile = process.argv[2]; +if (!fs.existsSync(wasmfile)) { + console.log("Error: File not found:", wasmfile); + process.exit(1); +} + +const wasmBuffer = fs.readFileSync(wasmfile); + +async function main() { + + let memory = new ArrayBuffer(0) // will be changed after instantiate + + const captured_output = []; + + const imports = { + env: { + __log_utf8: (ptr, size) => { + const str = dec.decode(new DataView(memory, ptr, size)); + captured_output.push(str); + console.log(str); + } + } + }; + + const wasmModule = await WebAssembly.instantiate(wasmBuffer, imports); + memory = wasmModule.instance.exports.memory.buffer; + + const start = wasmModule.instance.exports.start; + const return_code = start(); + + console.log("Return-Code:", return_code); + + if (return_code !== 0) { + console.error("Expected return code 0"); + process.exit(return_code); + } + + const expected_output = [ + '`r#try` called with ptr 0x1234', + 'Dropped', + 'Caught something!', + ' data : 0x1234', + ' exception: "index out of bounds: the len is 1 but the index is 4"', + 'This program terminates correctly.', + ]; + + assert_equal(captured_output, expected_output); +} + +function assert_equal(captured_output, expected_output) { + if (captured_output.length != expected_output.length) { + console.error("Unexpected number of output lines. Got", captured_output.length, "but expected", expected_output.length); + process.exit(1); // exit with error + } + + for (let idx = 0; idx < expected_output.length; ++idx) { + if (captured_output[idx] !== expected_output[idx]) { + console.error("Unexpected output"); + console.error("[got] ", captured_output[idx]); + console.error("[expected]", expected_output[idx]); + process.exit(2); // exit with error + } + } +} + +await main(); \ No newline at end of file diff --git a/tests/rustdoc-gui/sidebar-source-code.goml b/tests/rustdoc-gui/sidebar-source-code.goml index 520b2c59b0f89..2cb888178847f 100644 --- a/tests/rustdoc-gui/sidebar-source-code.goml +++ b/tests/rustdoc-gui/sidebar-source-code.goml @@ -25,24 +25,24 @@ call-function: ( "check-colors", { "theme": "ayu", - "color": "rgb(197, 197, 197)", - "background_color": "rgb(20, 25, 31)", + "color": "#c5c5c5", + "background_color": "#14191f", } ) call-function: ( "check-colors", { "theme": "dark", - "color": "rgb(221, 221, 221)", - "background_color": "rgb(80, 80, 80)", + "color": "#ddd", + "background_color": "#505050", } ) call-function: ( "check-colors", { "theme": "light", - "color": "rgb(0, 0, 0)", - "background_color": "rgb(245, 245, 245)", + "color": "black", + "background_color": "#F5F5F5", } ) diff --git a/tests/rustdoc/generic-consts.rs b/tests/rustdoc/generic-consts.rs new file mode 100644 index 0000000000000..cddf98e60a1cd --- /dev/null +++ b/tests/rustdoc/generic-consts.rs @@ -0,0 +1,38 @@ +#![feature(generic_consts)] +#![allow(incomplete_features)] + +// @has 'generic_consts/constant.K.html' +// @has - '//*[@class="rust item-decl"]//code' \ +// "pub const K<'a, T: 'a + Copy, const N: usize>: Option<[T; N]> \ +// where \ +// String: From;" +pub const K<'a, T: 'a + Copy, const N: usize>: Option<[T; N]> = None +where + String: From; + +// @has generic_consts/trait.Trait.html +pub trait Trait { + // @has - '//*[@id="associatedconstant.C"]' \ + // "const C<'a>: &'a T \ + // where \ + // T: 'a + Eq" + const C<'a>: &'a T + where + T: 'a + Eq; +} + +pub struct Implementor; + +// @has generic_consts/struct.Implementor.html +// @has - '//h3[@class="code-header"]' 'impl Trait for Implementor' +impl Trait for Implementor { + // @has - '//*[@id="associatedconstant.C"]' \ + // "const C<'a>: &'a str = \"C\" \ + // where \ + // str: 'a" + const C<'a>: &'a str = "C" + // In real code we could've left off this bound but adding it explicitly allows us to test if + // we render where-clauses on associated consts inside impl blocks correctly. + where + str: 'a; +} diff --git a/tests/rustdoc/inline_cross/auxiliary/generic-consts.rs b/tests/rustdoc/inline_cross/auxiliary/generic-consts.rs new file mode 100644 index 0000000000000..26435b07f86e2 --- /dev/null +++ b/tests/rustdoc/inline_cross/auxiliary/generic-consts.rs @@ -0,0 +1,22 @@ +#![feature(generic_consts)] +#![allow(incomplete_features)] + +pub const K<'a, T: 'a + Copy, const N: usize>: Option<[T; N]> = None +where + String: From; + +pub trait Trait { + const C<'a>: &'a T + where + T: 'a + Eq; +} + +pub struct Implementor; + +impl Trait for Implementor { + const C<'a>: &'a str = "C" + // In real code we could've left off this bound but adding it explicitly allows us to test if + // we render where-clauses on associated consts inside impl blocks correctly. + where + str: 'a; +} diff --git a/tests/rustdoc/inline_cross/generic-consts.rs b/tests/rustdoc/inline_cross/generic-consts.rs new file mode 100644 index 0000000000000..95bb06c2771c7 --- /dev/null +++ b/tests/rustdoc/inline_cross/generic-consts.rs @@ -0,0 +1,26 @@ +#![crate_name = "user"] + +// aux-crate:generic_consts=generic-consts.rs +// edition:2021 + +// @has 'user/constant.K.html' +// @has - '//*[@class="rust item-decl"]//code' \ +// "pub const K<'a, T: 'a + Copy, const N: usize>: Option<[T; N]> \ +// where \ +// String: From;" +pub use generic_consts::K; + +// @has user/trait.Trait.html +// @has - '//*[@id="associatedconstant.C"]' \ +// "const C<'a>: &'a T \ +// where \ +// T: 'a + Eq" +pub use generic_consts::Trait; + +// @has user/struct.Implementor.html +// @has - '//h3[@class="code-header"]' 'impl Trait for Implementor' +// @has - '//*[@id="associatedconstant.C"]' \ +// "const C<'a>: &'a str = \"C\" \ +// where \ +// str: 'a" +pub use generic_consts::Implementor; diff --git a/tests/ui-fulldeps/stable-mir/crate-info.rs b/tests/ui-fulldeps/stable-mir/crate-info.rs index 9ef208a14b223..f55d7d599f1e4 100644 --- a/tests/ui-fulldeps/stable-mir/crate-info.rs +++ b/tests/ui-fulldeps/stable-mir/crate-info.rs @@ -7,6 +7,7 @@ // edition: 2021 #![feature(rustc_private)] +#![feature(assert_matches)] extern crate rustc_driver; extern crate rustc_hir; @@ -21,6 +22,7 @@ use rustc_interface::{interface, Queries}; use rustc_middle::ty::TyCtxt; use rustc_session::EarlyErrorHandler; use rustc_smir::{rustc_internal, stable_mir}; +use std::assert_matches::assert_matches; use std::io::Write; const CRATE_NAME: &str = "input"; @@ -65,6 +67,36 @@ fn test_stable_mir(tcx: TyCtxt<'_>) { other => panic!("{other:?}"), } + let types = get_item(tcx, &items, (DefKind::Fn, "types")).unwrap(); + let body = types.body(); + assert_eq!(body.locals.len(), 6); + assert_matches!( + body.locals[0].kind(), + stable_mir::ty::TyKind::RigidTy(stable_mir::ty::RigidTy::Bool) + ); + assert_matches!( + body.locals[1].kind(), + stable_mir::ty::TyKind::RigidTy(stable_mir::ty::RigidTy::Bool) + ); + assert_matches!( + body.locals[2].kind(), + stable_mir::ty::TyKind::RigidTy(stable_mir::ty::RigidTy::Char) + ); + assert_matches!( + body.locals[3].kind(), + stable_mir::ty::TyKind::RigidTy(stable_mir::ty::RigidTy::Int(stable_mir::ty::IntTy::I32)) + ); + assert_matches!( + body.locals[4].kind(), + stable_mir::ty::TyKind::RigidTy(stable_mir::ty::RigidTy::Uint(stable_mir::ty::UintTy::U64)) + ); + assert_matches!( + body.locals[5].kind(), + stable_mir::ty::TyKind::RigidTy(stable_mir::ty::RigidTy::Float( + stable_mir::ty::FloatTy::F64 + )) + ); + let drop = get_item(tcx, &items, (DefKind::Fn, "drop")).unwrap(); let body = drop.body(); assert_eq!(body.blocks.len(), 2); @@ -156,6 +188,10 @@ fn generate_input(path: &str) -> std::io::Result<()> { x_64.wrapping_add(y_64) }} + pub fn types(b: bool, _: char, _: i32, _: u64, _: f64) -> bool {{ + b + }} + pub fn drop(_: String) {{}} pub fn assert(x: i32) -> i32 {{ diff --git a/tests/ui/async-await/in-trait/async-associated-types2.rs b/tests/ui/async-await/in-trait/async-associated-types2.rs deleted file mode 100644 index b889f616a0311..0000000000000 --- a/tests/ui/async-await/in-trait/async-associated-types2.rs +++ /dev/null @@ -1,30 +0,0 @@ -// check-pass -// edition: 2021 -// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty -// revisions: current next - -#![feature(async_fn_in_trait)] -#![feature(impl_trait_in_assoc_type)] -#![allow(incomplete_features)] - -use std::future::Future; - -trait MyTrait { - type Fut<'a>: Future - where - Self: 'a; - - fn foo<'a>(&'a self) -> Self::Fut<'a>; -} - -impl MyTrait for i32 { - type Fut<'a> = impl Future + 'a - where - Self: 'a; - - fn foo<'a>(&'a self) -> Self::Fut<'a> { - async { *self } - } -} - -fn main() {} diff --git a/tests/ui/async-await/in-trait/missing-feature-flag.current.stderr b/tests/ui/async-await/in-trait/missing-feature-flag.current.stderr new file mode 100644 index 0000000000000..e6ac9bc2277ba --- /dev/null +++ b/tests/ui/async-await/in-trait/missing-feature-flag.current.stderr @@ -0,0 +1,30 @@ +error[E0046]: not all trait items implemented, missing: `foo` + --> $DIR/missing-feature-flag.rs:14:1 + | +LL | async fn foo(_: T) -> &'static str; + | ----------------------------------- `foo` from trait +... +LL | impl MyTrait for MyStruct {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `foo` in implementation + +error[E0520]: `foo` specializes an item from a parent `impl`, but that item is not marked `default` + --> $DIR/missing-feature-flag.rs:18:5 + | +LL | impl MyTrait for MyStruct {} + | ------------------------------- parent `impl` is here +... +LL | async fn foo(_: i32) -> &'static str {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot specialize default item `foo` + | + = note: to specialize, `foo` in the parent `impl` must be marked `default` + +error[E0308]: mismatched types + --> $DIR/missing-feature-flag.rs:18:42 + | +LL | async fn foo(_: i32) -> &'static str {} + | ^^ expected `&str`, found `()` + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0046, E0308, E0520. +For more information about an error, try `rustc --explain E0046`. diff --git a/tests/ui/async-await/in-trait/missing-feature-flag.next.stderr b/tests/ui/async-await/in-trait/missing-feature-flag.next.stderr new file mode 100644 index 0000000000000..e6ac9bc2277ba --- /dev/null +++ b/tests/ui/async-await/in-trait/missing-feature-flag.next.stderr @@ -0,0 +1,30 @@ +error[E0046]: not all trait items implemented, missing: `foo` + --> $DIR/missing-feature-flag.rs:14:1 + | +LL | async fn foo(_: T) -> &'static str; + | ----------------------------------- `foo` from trait +... +LL | impl MyTrait for MyStruct {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `foo` in implementation + +error[E0520]: `foo` specializes an item from a parent `impl`, but that item is not marked `default` + --> $DIR/missing-feature-flag.rs:18:5 + | +LL | impl MyTrait for MyStruct {} + | ------------------------------- parent `impl` is here +... +LL | async fn foo(_: i32) -> &'static str {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot specialize default item `foo` + | + = note: to specialize, `foo` in the parent `impl` must be marked `default` + +error[E0308]: mismatched types + --> $DIR/missing-feature-flag.rs:18:42 + | +LL | async fn foo(_: i32) -> &'static str {} + | ^^ expected `&str`, found `()` + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0046, E0308, E0520. +For more information about an error, try `rustc --explain E0046`. diff --git a/tests/ui/async-await/in-trait/missing-feature-flag.rs b/tests/ui/async-await/in-trait/missing-feature-flag.rs new file mode 100644 index 0000000000000..6481f4a70595f --- /dev/null +++ b/tests/ui/async-await/in-trait/missing-feature-flag.rs @@ -0,0 +1,23 @@ +// edition:2018 +// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty +// revisions: current next + +#![feature(async_fn_in_trait)] +#![feature(min_specialization)] + +struct MyStruct; + +trait MyTrait { + async fn foo(_: T) -> &'static str; +} + +impl MyTrait for MyStruct {} +//~^ ERROR: not all trait items implemented, missing: `foo` [E0046] + +impl MyTrait for MyStruct { + async fn foo(_: i32) -> &'static str {} + //~^ ERROR: `foo` specializes an item from a parent `impl`, but that item is not marked `default` [E0520] + //~| ERROR: mismatched types [E0308] +} + +fn main() {} diff --git a/tests/ui/async-await/return-type-notation/rtn-in-impl-signature.rs b/tests/ui/async-await/return-type-notation/rtn-in-impl-signature.rs new file mode 100644 index 0000000000000..1b16a492a7a1a --- /dev/null +++ b/tests/ui/async-await/return-type-notation/rtn-in-impl-signature.rs @@ -0,0 +1,13 @@ +#![feature(return_type_notation)] +//~^ WARN the feature `return_type_notation` is incomplete + +// Shouldn't ICE when we have a (bad) RTN in an impl header + +trait Super1<'a> { + fn bar<'b>() -> bool; +} + +impl Super1<'_, bar(): Send> for () {} +//~^ ERROR associated type bindings are not allowed here + +fn main() {} diff --git a/tests/ui/async-await/return-type-notation/rtn-in-impl-signature.stderr b/tests/ui/async-await/return-type-notation/rtn-in-impl-signature.stderr new file mode 100644 index 0000000000000..52d8168c9d836 --- /dev/null +++ b/tests/ui/async-await/return-type-notation/rtn-in-impl-signature.stderr @@ -0,0 +1,18 @@ +warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/rtn-in-impl-signature.rs:1:12 + | +LL | #![feature(return_type_notation)] + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #109417 for more information + = note: `#[warn(incomplete_features)]` on by default + +error[E0229]: associated type bindings are not allowed here + --> $DIR/rtn-in-impl-signature.rs:10:17 + | +LL | impl Super1<'_, bar(): Send> for () {} + | ^^^^^^^^^^^ associated type not allowed here + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0229`. diff --git a/tests/ui/binop/binop-mul-i32-f32.stderr b/tests/ui/binop/binop-mul-i32-f32.stderr index c986bc3fd1e3e..115e700061981 100644 --- a/tests/ui/binop/binop-mul-i32-f32.stderr +++ b/tests/ui/binop/binop-mul-i32-f32.stderr @@ -6,10 +6,10 @@ LL | x * y | = help: the trait `Mul` is not implemented for `i32` = help: the following other types implement trait `Mul`: + + > <&'a i32 as Mul> <&i32 as Mul<&i32>> - > - error: aborting due to previous error diff --git a/tests/ui/binop/shift-various-bad-types.stderr b/tests/ui/binop/shift-various-bad-types.stderr index 38db66f86b461..b43672ef3b568 100644 --- a/tests/ui/binop/shift-various-bad-types.stderr +++ b/tests/ui/binop/shift-various-bad-types.stderr @@ -6,14 +6,14 @@ LL | 22 >> p.char; | = help: the trait `Shr` is not implemented for `{integer}` = help: the following other types implement trait `Shr`: - <&'a i128 as Shr> - <&'a i128 as Shr> - <&'a i128 as Shr> - <&'a i128 as Shr> - <&'a i128 as Shr> - <&'a i128 as Shr> - <&'a i128 as Shr> - <&'a i128 as Shr> + + > + > + > + > + > + > + > and 568 others error[E0277]: no implementation for `{integer} >> &str` @@ -24,14 +24,14 @@ LL | 22 >> p.str; | = help: the trait `Shr<&str>` is not implemented for `{integer}` = help: the following other types implement trait `Shr`: - <&'a i128 as Shr> - <&'a i128 as Shr> - <&'a i128 as Shr> - <&'a i128 as Shr> - <&'a i128 as Shr> - <&'a i128 as Shr> - <&'a i128 as Shr> - <&'a i128 as Shr> + + > + > + > + > + > + > + > and 568 others error[E0277]: no implementation for `{integer} >> &Panolpy` @@ -42,14 +42,14 @@ LL | 22 >> p; | = help: the trait `Shr<&Panolpy>` is not implemented for `{integer}` = help: the following other types implement trait `Shr`: - <&'a i128 as Shr> - <&'a i128 as Shr> - <&'a i128 as Shr> - <&'a i128 as Shr> - <&'a i128 as Shr> - <&'a i128 as Shr> - <&'a i128 as Shr> - <&'a i128 as Shr> + + > + > + > + > + > + > + > and 568 others error[E0308]: mismatched types diff --git a/tests/ui/conditional-compilation/cfg-arg-invalid-1.rs b/tests/ui/conditional-compilation/cfg-arg-invalid-1.rs index d20e79b9db338..0898ca9cda4df 100644 --- a/tests/ui/conditional-compilation/cfg-arg-invalid-1.rs +++ b/tests/ui/conditional-compilation/cfg-arg-invalid-1.rs @@ -1,3 +1,3 @@ -// compile-flags: --cfg a(b=c) +// compile-flags: --error-format=human --cfg a(b=c) // error-pattern: invalid `--cfg` argument: `a(b=c)` (expected `key` or `key="value"`, ensure escaping is appropriate for your shell, try 'key="value"' or key=\"value\") fn main() {} diff --git a/tests/ui/conditional-compilation/cfg-arg-invalid-2.rs b/tests/ui/conditional-compilation/cfg-arg-invalid-2.rs index 48d656a4a28d9..70e4256006677 100644 --- a/tests/ui/conditional-compilation/cfg-arg-invalid-2.rs +++ b/tests/ui/conditional-compilation/cfg-arg-invalid-2.rs @@ -1,3 +1,3 @@ -// compile-flags: --cfg a{b} +// compile-flags: --error-format=human --cfg a{b} // error-pattern: invalid `--cfg` argument: `a{b}` (expected `key` or `key="value"`) fn main() {} diff --git a/tests/ui/conditional-compilation/cfg-arg-invalid-4.rs b/tests/ui/conditional-compilation/cfg-arg-invalid-4.rs index e7dfa17b4b6c4..2adc27eb932eb 100644 --- a/tests/ui/conditional-compilation/cfg-arg-invalid-4.rs +++ b/tests/ui/conditional-compilation/cfg-arg-invalid-4.rs @@ -1,3 +1,3 @@ -// compile-flags: --cfg a(b) +// compile-flags: --error-format=human --cfg a(b) // error-pattern: invalid `--cfg` argument: `a(b)` (expected `key` or `key="value"`) fn main() {} diff --git a/tests/ui/conditional-compilation/cfg-arg-invalid-6.rs b/tests/ui/conditional-compilation/cfg-arg-invalid-6.rs index 9fa726f93e3ea..be3ded7dd8b4a 100644 --- a/tests/ui/conditional-compilation/cfg-arg-invalid-6.rs +++ b/tests/ui/conditional-compilation/cfg-arg-invalid-6.rs @@ -1,3 +1,3 @@ -// compile-flags: --cfg a{ +// compile-flags: --error-format=human --cfg a{ // error-pattern: invalid `--cfg` argument: `a{` (expected `key` or `key="value"`) fn main() {} diff --git a/tests/ui/conditional-compilation/cfg-arg-invalid-8.rs b/tests/ui/conditional-compilation/cfg-arg-invalid-8.rs index 1d7fa7885348e..4a2f16f113330 100644 --- a/tests/ui/conditional-compilation/cfg-arg-invalid-8.rs +++ b/tests/ui/conditional-compilation/cfg-arg-invalid-8.rs @@ -1,3 +1,3 @@ -// compile-flags: --cfg ) +// compile-flags: --error-format=human --cfg ) // error-pattern: invalid `--cfg` argument: `)` (expected `key` or `key="value"`) fn main() {} diff --git a/tests/ui/conditional-compilation/cfg-arg-invalid-9.rs b/tests/ui/conditional-compilation/cfg-arg-invalid-9.rs index 628b335c87302..a61989a3e9fe1 100644 --- a/tests/ui/conditional-compilation/cfg-arg-invalid-9.rs +++ b/tests/ui/conditional-compilation/cfg-arg-invalid-9.rs @@ -1,4 +1,4 @@ // Test for missing quotes around value, issue #66450. -// compile-flags: --cfg key=value +// compile-flags: --error-format=human --cfg key=value // error-pattern: invalid `--cfg` argument: `key=value` (expected `key` or `key="value"`, ensure escaping is appropriate for your shell, try 'key="value"' or key=\"value\") fn main() {} diff --git a/tests/ui/conditional-compilation/cfg-empty-codemap.rs b/tests/ui/conditional-compilation/cfg-empty-codemap.rs index 9e34cacf74d2a..c7aded7338a20 100644 --- a/tests/ui/conditional-compilation/cfg-empty-codemap.rs +++ b/tests/ui/conditional-compilation/cfg-empty-codemap.rs @@ -1,6 +1,6 @@ // Tests that empty source_maps don't ICE (#23301) -// compile-flags: --cfg "" +// compile-flags: --error-format=human --cfg "" // error-pattern: invalid `--cfg` argument: `""` (expected `key` or `key="value"`) diff --git a/tests/ui/const-generics/exhaustive-value.stderr b/tests/ui/const-generics/exhaustive-value.stderr index 76a83ba67ce79..4a26e09772dc4 100644 --- a/tests/ui/const-generics/exhaustive-value.stderr +++ b/tests/ui/const-generics/exhaustive-value.stderr @@ -6,13 +6,13 @@ LL | <() as Foo>::test() | = help: the following other types implement trait `Foo`: <() as Foo<0>> - <() as Foo<100>> - <() as Foo<101>> - <() as Foo<102>> - <() as Foo<103>> - <() as Foo<104>> - <() as Foo<105>> - <() as Foo<106>> + <() as Foo<1>> + <() as Foo<2>> + <() as Foo<3>> + <() as Foo<4>> + <() as Foo<5>> + <() as Foo<6>> + <() as Foo<7>> and 248 others error: aborting due to previous error diff --git a/tests/ui/const-generics/generic_arg_infer/issue-91614.stderr b/tests/ui/const-generics/generic_arg_infer/issue-91614.stderr index 13ea4a295afd7..0096d4ee23d11 100644 --- a/tests/ui/const-generics/generic_arg_infer/issue-91614.stderr +++ b/tests/ui/const-generics/generic_arg_infer/issue-91614.stderr @@ -6,11 +6,11 @@ LL | let y = Mask::<_, _>::splat(false); | = note: cannot satisfy `_: MaskElement` = help: the following types implement trait `MaskElement`: + isize + i8 i16 i32 i64 - i8 - isize note: required by a bound in `Mask::::splat` --> $SRC_DIR/core/src/../../portable-simd/crates/core_simd/src/masks.rs:LL:COL help: consider giving `y` an explicit type, where the type for type parameter `T` is specified diff --git a/tests/ui/const-generics/issues/issue-67185-2.stderr b/tests/ui/const-generics/issues/issue-67185-2.stderr index 032b0c41047fc..a2e5b8053688b 100644 --- a/tests/ui/const-generics/issues/issue-67185-2.stderr +++ b/tests/ui/const-generics/issues/issue-67185-2.stderr @@ -5,8 +5,8 @@ LL | ::Quaks: Bar, | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Bar` is not implemented for `[u16; 3]` | = help: the following other types implement trait `Bar`: - [[u16; 3]; 3] [u16; 4] + [[u16; 3]; 3] = help: see issue #48214 = help: add `#![feature(trivial_bounds)]` to the crate attributes to enable @@ -17,8 +17,8 @@ LL | [::Quaks; 2]: Bar, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Bar` is not implemented for `[[u16; 3]; 2]` | = help: the following other types implement trait `Bar`: - [[u16; 3]; 3] [u16; 4] + [[u16; 3]; 3] = help: see issue #48214 = help: add `#![feature(trivial_bounds)]` to the crate attributes to enable @@ -29,8 +29,8 @@ LL | impl Foo for FooImpl {} | ^^^ the trait `Bar` is not implemented for `[u16; 3]` | = help: the following other types implement trait `Bar`: - [[u16; 3]; 3] [u16; 4] + [[u16; 3]; 3] note: required by a bound in `Foo` --> $DIR/issue-67185-2.rs:15:25 | @@ -47,8 +47,8 @@ LL | impl Foo for FooImpl {} | ^^^ the trait `Bar` is not implemented for `[[u16; 3]; 2]` | = help: the following other types implement trait `Bar`: - [[u16; 3]; 3] [u16; 4] + [[u16; 3]; 3] note: required by a bound in `Foo` --> $DIR/issue-67185-2.rs:14:30 | @@ -65,8 +65,8 @@ LL | fn f(_: impl Foo) {} | ^^^ the trait `Bar` is not implemented for `[[u16; 3]; 2]` | = help: the following other types implement trait `Bar`: - [[u16; 3]; 3] [u16; 4] + [[u16; 3]; 3] note: required by a bound in `Foo` --> $DIR/issue-67185-2.rs:14:30 | @@ -83,8 +83,8 @@ LL | fn f(_: impl Foo) {} | ^^^ the trait `Bar` is not implemented for `[u16; 3]` | = help: the following other types implement trait `Bar`: - [[u16; 3]; 3] [u16; 4] + [[u16; 3]; 3] note: required by a bound in `Foo` --> $DIR/issue-67185-2.rs:15:25 | diff --git a/tests/ui/consts/const-eval/const-eval-overflow-3b.stderr b/tests/ui/consts/const-eval/const-eval-overflow-3b.stderr index 05f33c33946a8..06e398edca9af 100644 --- a/tests/ui/consts/const-eval/const-eval-overflow-3b.stderr +++ b/tests/ui/consts/const-eval/const-eval-overflow-3b.stderr @@ -12,10 +12,10 @@ LL | = [0; (i8::MAX + 1u8) as usize]; | = help: the trait `Add` is not implemented for `i8` = help: the following other types implement trait `Add`: + + > <&'a i8 as Add> <&i8 as Add<&i8>> - > - error: aborting due to 2 previous errors diff --git a/tests/ui/consts/const-eval/const-eval-overflow-4b.stderr b/tests/ui/consts/const-eval/const-eval-overflow-4b.stderr index d019f5920b517..07ef2ac090f7b 100644 --- a/tests/ui/consts/const-eval/const-eval-overflow-4b.stderr +++ b/tests/ui/consts/const-eval/const-eval-overflow-4b.stderr @@ -12,10 +12,10 @@ LL | : [u32; (i8::MAX as i8 + 1u8) as usize] | = help: the trait `Add` is not implemented for `i8` = help: the following other types implement trait `Add`: + + > <&'a i8 as Add> <&i8 as Add<&i8>> - > - error[E0604]: only `u8` can be cast as `char`, not `i8` --> $DIR/const-eval-overflow-4b.rs:22:13 diff --git a/tests/ui/consts/const_in_pattern/issue-73431.rs b/tests/ui/consts/const_in_pattern/issue-73431.rs index fa18a3af1b09f..835f502b40730 100644 --- a/tests/ui/consts/const_in_pattern/issue-73431.rs +++ b/tests/ui/consts/const_in_pattern/issue-73431.rs @@ -1,4 +1,5 @@ // run-pass +// unset-rustc-env:RUSTC_LOG_COLOR // Regression test for https://github.com/rust-lang/rust/issues/73431. diff --git a/tests/ui/consts/missing-larger-array-impl.rs b/tests/ui/consts/missing-larger-array-impl.rs new file mode 100644 index 0000000000000..e6c879c8ebdab --- /dev/null +++ b/tests/ui/consts/missing-larger-array-impl.rs @@ -0,0 +1,9 @@ +struct X; + +// Make sure that we show the impl trait refs in the help message with +// their evaluated constants, rather than `core::::array::{impl#30}::{constant#0}` + +fn main() { + <[X; 35] as Default>::default(); + //~^ ERROR the trait bound `[X; 35]: Default` is not satisfied +} diff --git a/tests/ui/consts/missing-larger-array-impl.stderr b/tests/ui/consts/missing-larger-array-impl.stderr new file mode 100644 index 0000000000000..b8f6cb5ef9772 --- /dev/null +++ b/tests/ui/consts/missing-larger-array-impl.stderr @@ -0,0 +1,20 @@ +error[E0277]: the trait bound `[X; 35]: Default` is not satisfied + --> $DIR/missing-larger-array-impl.rs:7:5 + | +LL | <[X; 35] as Default>::default(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Default` is not implemented for `[X; 35]` + | + = help: the following other types implement trait `Default`: + [T; 0] + [T; 1] + [T; 2] + [T; 3] + [T; 4] + [T; 5] + [T; 6] + [T; 7] + and 27 others + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/consts/too_generic_eval_ice.stderr b/tests/ui/consts/too_generic_eval_ice.stderr index 5af82a3e34bf5..843d6d9e04ba7 100644 --- a/tests/ui/consts/too_generic_eval_ice.stderr +++ b/tests/ui/consts/too_generic_eval_ice.stderr @@ -22,14 +22,14 @@ LL | [5; Self::HOST_SIZE] == [6; 0] | = help: the trait `PartialEq<[{integer}; 0]>` is not implemented for `[{integer}; Self::HOST_SIZE]` = help: the following other types implement trait `PartialEq`: - <&[B] as PartialEq<[A; N]>> - <&[T] as PartialEq>> - <&mut [B] as PartialEq<[A; N]>> - <&mut [T] as PartialEq>> - <[A; N] as PartialEq<&[B]>> - <[A; N] as PartialEq<&mut [B]>> <[A; N] as PartialEq<[B; N]>> <[A; N] as PartialEq<[B]>> + <[A; N] as PartialEq<&[B]>> + <[A; N] as PartialEq<&mut [B]>> + <[T] as PartialEq>> + <[A] as PartialEq<[B]>> + <[B] as PartialEq<[A; N]>> + <&[T] as PartialEq>> and 3 others error: aborting due to 3 previous errors diff --git a/tests/ui/deriving/issue-103157.stderr b/tests/ui/deriving/issue-103157.stderr index b18e1e5098b34..01cce2a397ab3 100644 --- a/tests/ui/deriving/issue-103157.stderr +++ b/tests/ui/deriving/issue-103157.stderr @@ -8,14 +8,14 @@ LL | Float(Option), | ^^^^^^^^^^^ the trait `Eq` is not implemented for `f64` | = help: the following other types implement trait `Eq`: - i128 + isize + i8 i16 i32 i64 - i8 - isize - u128 - u16 + i128 + usize + u8 and 4 others = note: required for `Option` to implement `Eq` note: required by a bound in `AssertParamIsEq` diff --git a/tests/ui/diagnostic-flags/colored-session-opt-error.rs b/tests/ui/diagnostic-flags/colored-session-opt-error.rs new file mode 100644 index 0000000000000..b9f47285c1454 --- /dev/null +++ b/tests/ui/diagnostic-flags/colored-session-opt-error.rs @@ -0,0 +1,4 @@ +// check-pass +// ignore-windows +// compile-flags: -Cremark=foo --error-format=human --color always +fn main() {} diff --git a/tests/ui/diagnostic-flags/colored-session-opt-error.stderr b/tests/ui/diagnostic-flags/colored-session-opt-error.stderr new file mode 100644 index 0000000000000..ef79d5b0f2f82 --- /dev/null +++ b/tests/ui/diagnostic-flags/colored-session-opt-error.stderr @@ -0,0 +1,2 @@ +warning: -C remark requires "-C debuginfo=n" to show source locations + diff --git a/tests/ui/did_you_mean/issue-21659-show-relevant-trait-impls-2.stderr b/tests/ui/did_you_mean/issue-21659-show-relevant-trait-impls-2.stderr index 5e0e4a0115a0e..2d50c09645d7c 100644 --- a/tests/ui/did_you_mean/issue-21659-show-relevant-trait-impls-2.stderr +++ b/tests/ui/did_you_mean/issue-21659-show-relevant-trait-impls-2.stderr @@ -7,12 +7,12 @@ LL | f1.foo(1usize); | required by a bound introduced by this call | = help: the following other types implement trait `Foo`: + > > > - > + > > > - > error: aborting due to previous error diff --git a/tests/ui/did_you_mean/issue-39802-show-5-trait-impls.stderr b/tests/ui/did_you_mean/issue-39802-show-5-trait-impls.stderr index 7229b9ac986ac..ae15e054f6288 100644 --- a/tests/ui/did_you_mean/issue-39802-show-5-trait-impls.stderr +++ b/tests/ui/did_you_mean/issue-39802-show-5-trait-impls.stderr @@ -8,10 +8,10 @@ LL | Foo::::bar(&1i8); | = help: the following other types implement trait `Foo`: > + > > > > - > error[E0277]: the trait bound `u8: Foo` is not satisfied --> $DIR/issue-39802-show-5-trait-impls.rs:25:21 @@ -38,10 +38,10 @@ LL | Foo::::bar(&true); = help: the following other types implement trait `Foo`: > > + > > > > - > error: aborting due to 3 previous errors diff --git a/tests/ui/did_you_mean/issue-49746-unicode-confusable-in-float-literal-expt.stderr b/tests/ui/did_you_mean/issue-49746-unicode-confusable-in-float-literal-expt.stderr index 26986684f0c0a..44bdbb93ff51c 100644 --- a/tests/ui/did_you_mean/issue-49746-unicode-confusable-in-float-literal-expt.stderr +++ b/tests/ui/did_you_mean/issue-49746-unicode-confusable-in-float-literal-expt.stderr @@ -23,14 +23,14 @@ LL | const UNIVERSAL_GRAVITATIONAL_CONSTANT: f64 = 6.674e−11; // m³⋅kg⁻¹ | = help: the trait `Sub<{integer}>` is not implemented for `{float}` = help: the following other types implement trait `Sub`: - <&'a f32 as Sub> - <&'a f64 as Sub> - <&'a i128 as Sub> - <&'a i16 as Sub> - <&'a i32 as Sub> - <&'a i64 as Sub> - <&'a i8 as Sub> - <&'a isize as Sub> + + > + + > + + > + + > and 48 others error: aborting due to 3 previous errors diff --git a/tests/ui/dyn-star/param-env-region-infer.current.stderr b/tests/ui/dyn-star/param-env-region-infer.current.stderr index c606a50c8a9cb..902053ecfef62 100644 --- a/tests/ui/dyn-star/param-env-region-infer.current.stderr +++ b/tests/ui/dyn-star/param-env-region-infer.current.stderr @@ -1,5 +1,5 @@ error[E0282]: type annotations needed - --> $DIR/param-env-region-infer.rs:16:10 + --> $DIR/param-env-region-infer.rs:18:10 | LL | t as _ | ^ cannot infer type diff --git a/tests/ui/dyn-star/param-env-region-infer.next.stderr b/tests/ui/dyn-star/param-env-region-infer.next.stderr new file mode 100644 index 0000000000000..dd724a6590829 --- /dev/null +++ b/tests/ui/dyn-star/param-env-region-infer.next.stderr @@ -0,0 +1,29 @@ +error[E0391]: cycle detected when computing type of `make_dyn_star::{opaque#0}` + --> $DIR/param-env-region-infer.rs:16:60 + | +LL | fn make_dyn_star<'a, T: PointerLike + Debug + 'a>(t: T) -> impl PointerLike + Debug + 'a { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: ...which requires type-checking `make_dyn_star`... + --> $DIR/param-env-region-infer.rs:16:1 + | +LL | fn make_dyn_star<'a, T: PointerLike + Debug + 'a>(t: T) -> impl PointerLike + Debug + 'a { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: ...which requires computing layout of `make_dyn_star::{opaque#0}`... + = note: ...which requires normalizing `make_dyn_star::{opaque#0}`... + = note: ...which again requires computing type of `make_dyn_star::{opaque#0}`, completing the cycle +note: cycle used when checking item types in top-level module + --> $DIR/param-env-region-infer.rs:10:1 + | +LL | / #![feature(dyn_star, pointer_like_trait)] +LL | | #![allow(incomplete_features)] +LL | | +LL | | use std::fmt::Debug; +... | +LL | | +LL | | fn main() {} + | |____________^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0391`. diff --git a/tests/ui/dyn-star/param-env-region-infer.rs b/tests/ui/dyn-star/param-env-region-infer.rs index 9c337e4a89bd3..537473abc3a5b 100644 --- a/tests/ui/dyn-star/param-env-region-infer.rs +++ b/tests/ui/dyn-star/param-env-region-infer.rs @@ -1,6 +1,7 @@ // revisions: current next -//[next] compile-flags: -Ztrait-solver=next -//[next] check-pass +// Need `-Zdeduplicate-diagnostics=yes` because the number of cycle errors +// emitted is for some horrible reason platform-specific. +//[next] compile-flags: -Ztrait-solver=next -Zdeduplicate-diagnostics=yes // incremental // checks that we don't ICE if there are region inference variables in the environment @@ -13,6 +14,7 @@ use std::fmt::Debug; use std::marker::PointerLike; fn make_dyn_star<'a, T: PointerLike + Debug + 'a>(t: T) -> impl PointerLike + Debug + 'a { + //[next]~^ ERROR cycle detected when computing t as _ //[current]~^ ERROR type annotations needed } diff --git a/tests/ui/feature-gates/feature-gate-type_alias_impl_trait.rs b/tests/ui/feature-gates/feature-gate-type_alias_impl_trait.rs index 0d019b1f50206..3f49020bbea38 100644 --- a/tests/ui/feature-gates/feature-gate-type_alias_impl_trait.rs +++ b/tests/ui/feature-gates/feature-gate-type_alias_impl_trait.rs @@ -11,7 +11,7 @@ fn define() -> Bar { type Foo2 = impl Debug; -fn define2() { +fn define2(_: Foo2) { let x = || -> Foo2 { 42 }; } @@ -20,13 +20,13 @@ type Foo3 = impl Debug; fn define3(x: Foo3) { let y: i32 = x; } -fn define3_1() { +fn define3_1(_: Foo3) { define3(42) } type Foo4 = impl Debug; -fn define4() { +fn define4(_: Foo4) { let y: Foo4 = 42; } diff --git a/tests/ui/fmt/ifmt-unimpl.stderr b/tests/ui/fmt/ifmt-unimpl.stderr index b0dddd3b1e8d0..4c0ac52865d77 100644 --- a/tests/ui/fmt/ifmt-unimpl.stderr +++ b/tests/ui/fmt/ifmt-unimpl.stderr @@ -7,14 +7,14 @@ LL | format!("{:X}", "3"); | required by a bound introduced by this call | = help: the following other types implement trait `UpperHex`: - &T - &mut T - NonZeroI128 - NonZeroI16 - NonZeroI32 - NonZeroI64 - NonZeroI8 - NonZeroIsize + isize + i8 + i16 + i32 + i64 + i128 + usize + u8 and 20 others = note: required for `&str` to implement `UpperHex` note: required by a bound in `core::fmt::rt::Argument::<'a>::new_upper_hex` diff --git a/tests/ui/generic-associated-types/issue-90014-tait.rs b/tests/ui/generic-associated-types/issue-90014-tait.rs new file mode 100644 index 0000000000000..bc3a4e1296513 --- /dev/null +++ b/tests/ui/generic-associated-types/issue-90014-tait.rs @@ -0,0 +1,23 @@ +//! This test is reporting the wrong error. We need +//! more inherent associated type tests that use opaque types +//! in general. Some variant of this test should compile successfully. +// known-bug: unknown +// edition:2018 + +#![feature(impl_trait_in_assoc_type, inherent_associated_types)] +#![allow(incomplete_features)] + +use std::future::Future; + +struct Foo<'a>(&'a mut ()); + +impl Foo<'_> { + type Fut<'a> = impl Future; + //^ ERROR: the type `&mut ()` does not fulfill the required lifetime + + fn make_fut<'a>(&'a self) -> Self::Fut<'a> { + async { () } + } +} + +fn main() {} diff --git a/tests/ui/generic-associated-types/issue-90014-tait.stderr b/tests/ui/generic-associated-types/issue-90014-tait.stderr new file mode 100644 index 0000000000000..8330a387ecd55 --- /dev/null +++ b/tests/ui/generic-associated-types/issue-90014-tait.stderr @@ -0,0 +1,22 @@ +error[E0308]: mismatched types + --> $DIR/issue-90014-tait.rs:19:9 + | +LL | type Fut<'a> = impl Future; + | ------------------------ the expected future +... +LL | fn make_fut<'a>(&'a self) -> Self::Fut<'a> { + | ------------- expected `Foo<'_>::Fut<'a>` because of return type +LL | async { () } + | ^^^^^^^^^^^^ expected future, found `async` block + | + = note: expected opaque type `Foo<'_>::Fut<'a>` + found `async` block `[async block@$DIR/issue-90014-tait.rs:19:9: 19:21]` +note: this item must have the opaque type in its signature in order to be able to register hidden types + --> $DIR/issue-90014-tait.rs:18:8 + | +LL | fn make_fut<'a>(&'a self) -> Self::Fut<'a> { + | ^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/generic-associated-types/issue-90014-tait2.rs b/tests/ui/generic-associated-types/issue-90014-tait2.rs new file mode 100644 index 0000000000000..dacbc93dec880 --- /dev/null +++ b/tests/ui/generic-associated-types/issue-90014-tait2.rs @@ -0,0 +1,46 @@ +//! This test checks that opaque type collection doesn't try to normalize the projection +//! without respecting its binders (which would ICE). +//! Unfortunately we don't even reach opaque type collection, as we ICE in typeck before that. +// known-bug: #109281 +// failure-status: 101 +// error-pattern:internal compiler error +// normalize-stderr-test "internal compiler error.*" -> "" +// normalize-stderr-test "DefId\([^)]*\)" -> "..." +// 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" -> "" +// normalize-stderr-test "thread.*panicked.*\n" -> "" +// normalize-stderr-test "stack backtrace:\n" -> "" +// normalize-stderr-test "\s\d{1,}: .*\n" -> "" +// normalize-stderr-test "\s at .*\n" -> "" +// normalize-stderr-test ".*note: Some details.*\n" -> "" +// normalize-stderr-test "\n\n[ ]*\n" -> "" +// normalize-stderr-test "compiler/.*: projection" -> "projection" +// edition:2018 + +#![feature(type_alias_impl_trait)] +#![allow(incomplete_features)] + +use std::future::Future; + +struct Foo<'a>(&'a mut ()); + +type Fut<'a> = impl Future; + +trait Trait<'x> { + type Thing; +} + +impl<'x, T: 'x> Trait<'x> for (T,) { + type Thing = T; +} + +impl Foo<'_> { + fn make_fut(&self) -> Box Trait<'a, Thing = Fut<'a>>> { + Box::new((async { () },)) + } +} + +fn main() {} diff --git a/tests/ui/generic-associated-types/issue-90014-tait2.stderr b/tests/ui/generic-associated-types/issue-90014-tait2.stderr new file mode 100644 index 0000000000000..3187be3334c5f --- /dev/null +++ b/tests/ui/generic-associated-types/issue-90014-tait2.stderr @@ -0,0 +1,12 @@ +error: + --> $DIR/issue-90014-tait2.rs:41:27 + | +LL | fn make_fut(&self) -> Box Trait<'a, Thing = Fut<'a>>> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^query stack during panic: +#0 [typeck] type-checking `::make_fut` +#1 [type_of] computing type of `Fut::{opaque#0}` +#2 [check_mod_item_types] checking item types in top-level module +#3 [analysis] running analysis passes on this crate +end of query stack +error: aborting due to previous error + diff --git a/tests/ui/generic-consts/associated-const-equality.rs b/tests/ui/generic-consts/associated-const-equality.rs new file mode 100644 index 0000000000000..2ea03689b6627 --- /dev/null +++ b/tests/ui/generic-consts/associated-const-equality.rs @@ -0,0 +1,22 @@ +// check-pass + +#![feature(generic_consts, associated_const_equality, non_lifetime_binders)] +#![allow(incomplete_features)] + +trait Owner { + const C: u32; + const K: u32; +} + +impl Owner for () { + const C: u32 = N; + const K: u32 = N + 1; +} + +fn take0(_: impl Owner = {N}>) {} +fn take1(_: impl Owner = 100>) {} + +fn main() { + take0::<128>(()); + take1(()); +} diff --git a/tests/ui/generic-consts/basic.rs b/tests/ui/generic-consts/basic.rs new file mode 100644 index 0000000000000..1e2707f0bc0e3 --- /dev/null +++ b/tests/ui/generic-consts/basic.rs @@ -0,0 +1,61 @@ +// check-pass + +// Basic usage patterns of free & associated generic consts. + +#![feature(generic_consts)] +#![allow(incomplete_features)] + +fn main() { + const NULL: Option = None::; + const NOTHING: Option = None; // arg inferred + + let _ = NOTHING::; + let _: Option = NULL; // arg inferred + + const IDENTITY: u64 = X; + + const COUNT: u64 = IDENTITY::<48>; + const AMOUNT: u64 = IDENTITY::; + const NUMBER: u64 = IDENTITY::<{ AMOUNT * 2 }>; + let _ = NUMBER; + let _ = IDENTITY::<0>; + + let _ = match 0 { + IDENTITY::<1> => 2, + IDENTITY::<{ 1 + 1 }> => 4, + _ => 0, + }; + + const CREATE: I = I::PROOF; + let _ = CREATE::; + let _: u64 = CREATE; // arg inferred + + let _ = <() as Main>::MAKE::; + let _: (u64, u64) = <()>::MAKE; // args inferred +} + +pub fn usage<'any>() { + const REGION_POLY<'a>: &'a () = &(); + + let _: &'any () = REGION_POLY::<'any>; + let _: &'any () = REGION_POLY::<'_>; + let _: &'static () = REGION_POLY; +} + +trait Main { + type Output; + const MAKE: Self::Output; +} + +impl Main for () { + type Output = (O, I); + const MAKE: Self::Output = (O::PROOF, I::PROOF); +} + +trait Inhabited { + const PROOF: Self; +} + +impl Inhabited for u64 { + const PROOF: Self = 512; +} diff --git a/tests/ui/generic-consts/compare-impl-item.rs b/tests/ui/generic-consts/compare-impl-item.rs new file mode 100644 index 0000000000000..0c238d70280a4 --- /dev/null +++ b/tests/ui/generic-consts/compare-impl-item.rs @@ -0,0 +1,30 @@ +#![feature(generic_consts)] +#![allow(incomplete_features)] + +trait Trait

{ + const A: (); + const B: u64; + const C: T; + const D: usize; + + const E: usize; + const F: (); +} + +impl

Trait

for () { + const A: () = (); + //~^ ERROR const `A` has 1 type parameter but its trait declaration has 0 type parameters + const B: u64 = 0; + //~^ ERROR const `B` has 1 const parameter but its trait declaration has 2 const parameters + const C<'a>: &'a str = ""; + //~^ ERROR const `C` has 0 type parameters but its trait declaration has 1 type parameter + const D: u16 = N; + //~^ ERROR const `D` has an incompatible generic parameter for trait `Trait` + + const E: usize = 1024 + where + P: Copy; //~ ERROR impl has stricter requirements than trait + const F: () = (); //~ ERROR impl has stricter requirements than trait +} + +fn main() {} diff --git a/tests/ui/generic-consts/compare-impl-item.stderr b/tests/ui/generic-consts/compare-impl-item.stderr new file mode 100644 index 0000000000000..8610d8cba0004 --- /dev/null +++ b/tests/ui/generic-consts/compare-impl-item.stderr @@ -0,0 +1,66 @@ +error[E0049]: const `A` has 1 type parameter but its trait declaration has 0 type parameters + --> $DIR/compare-impl-item.rs:15:13 + | +LL | const A: (); + | - expected 0 type parameters +... +LL | const A: () = (); + | ^ found 1 type parameter + +error[E0049]: const `B` has 1 const parameter but its trait declaration has 2 const parameters + --> $DIR/compare-impl-item.rs:17:13 + | +LL | const B: u64; + | ------------ ------------ + | | + | expected 2 const parameters +... +LL | const B: u64 = 0; + | ^^^^^^^^^^^^ found 1 const parameter + +error[E0049]: const `C` has 0 type parameters but its trait declaration has 1 type parameter + --> $DIR/compare-impl-item.rs:19:13 + | +LL | const C: T; + | - expected 1 type parameter +... +LL | const C<'a>: &'a str = ""; + | ^^ found 0 type parameters + +error[E0053]: const `D` has an incompatible generic parameter for trait `Trait` + --> $DIR/compare-impl-item.rs:21:13 + | +LL | trait Trait

{ + | ----- +... +LL | const D: usize; + | -------------- expected const parameter of type `usize` +... +LL | impl

Trait

for () { + | ----------------------- +... +LL | const D: u16 = N; + | ^^^^^^^^^^^^ found const parameter of type `u16` + +error[E0276]: impl has stricter requirements than trait + --> $DIR/compare-impl-item.rs:26:12 + | +LL | const E: usize; + | -------------- definition of `E` from trait +... +LL | P: Copy; + | ^^^^ impl has extra requirement `P: Copy` + +error[E0276]: impl has stricter requirements than trait + --> $DIR/compare-impl-item.rs:27:16 + | +LL | const F: (); + | ------------------------- definition of `F` from trait +... +LL | const F: () = (); + | ^^ impl has extra requirement `T: Eq` + +error: aborting due to 6 previous errors + +Some errors have detailed explanations: E0049, E0053, E0276. +For more information about an error, try `rustc --explain E0049`. diff --git a/tests/ui/generic-consts/const-trait-impl.rs b/tests/ui/generic-consts/const-trait-impl.rs new file mode 100644 index 0000000000000..0b0800d5f066a --- /dev/null +++ b/tests/ui/generic-consts/const-trait-impl.rs @@ -0,0 +1,23 @@ +// check-pass + +// Test that we can call methods from const trait impls from inside of generic consts. + +#![feature(generic_consts, const_trait_impl)] +#![allow(incomplete_features)] +#![crate_type = "lib"] + +const CREATE: T = T::create(); + +pub const K0: i32 = CREATE::; +pub const K1: i32 = CREATE; // arg inferred + +#[const_trait] +trait Create { + fn create() -> Self; +} + +impl const Create for i32 { + fn create() -> i32 { + 4096 + } +} diff --git a/tests/ui/generic-consts/duplicate-where-clause.rs b/tests/ui/generic-consts/duplicate-where-clause.rs new file mode 100644 index 0000000000000..ca244c2eceb94 --- /dev/null +++ b/tests/ui/generic-consts/duplicate-where-clause.rs @@ -0,0 +1,27 @@ +#![feature(generic_consts)] +#![allow(incomplete_features)] + +trait Tr

{ + const K: () + where + P: Copy + where + P: Eq; + //~^ ERROR cannot define duplicate `where` clauses on an item +} + +// Test that we error on the first where-clause but also that we don't suggest to swap it with the +// body as it would conflict with the second where-clause. +// FIXME(generic_consts): We should provide a structured sugg to merge the 1st into the 2nd WC. + +impl

Tr

for () { + const K: () + where + P: Eq + = () + where + P: Copy; + //~^^^^^ ERROR where clauses are not allowed before const item bodies +} + +fn main() {} diff --git a/tests/ui/generic-consts/duplicate-where-clause.stderr b/tests/ui/generic-consts/duplicate-where-clause.stderr new file mode 100644 index 0000000000000..5fa61b01ee9db --- /dev/null +++ b/tests/ui/generic-consts/duplicate-where-clause.stderr @@ -0,0 +1,27 @@ +error: cannot define duplicate `where` clauses on an item + --> $DIR/duplicate-where-clause.rs:9:9 + | +LL | P: Copy + | - previous `where` clause starts here +LL | where +LL | P: Eq; + | ^ + | +help: consider joining the two `where` clauses into one + | +LL | P: Copy, + | ~ + +error: where clauses are not allowed before const item bodies + --> $DIR/duplicate-where-clause.rs:19:5 + | +LL | const K: () + | - while parsing this const item +LL | / where +LL | | P: Eq + | |_____________^ unexpected where clause +LL | = () + | -- the item body + +error: aborting due to 2 previous errors + diff --git a/tests/ui/generic-consts/evaluatable-bounds.rs b/tests/ui/generic-consts/evaluatable-bounds.rs new file mode 100644 index 0000000000000..c16a7e0e99bc5 --- /dev/null +++ b/tests/ui/generic-consts/evaluatable-bounds.rs @@ -0,0 +1,31 @@ +// This is a regression test for issue #104400. + +// revisions: unconstrained constrained +//[constrained] check-pass + +// Test that we can constrain generic consts that appear inside associated consts by +// adding a (makeshift) "evaluatable"-bound to the item. + +#![feature(generic_consts, generic_const_exprs)] +#![allow(incomplete_features)] + +trait Trait { + const LEN: usize; + + #[cfg(unconstrained)] + const ARRAY: [i32; Self::LEN]; //[unconstrained]~ ERROR unconstrained generic constant + + #[cfg(constrained)] + const ARRAY: [i32; Self::LEN] + where + [(); Self::LEN]:; +} + +impl Trait for () { + const LEN: usize = 2; + const ARRAY: [i32; Self::LEN] = [360, 720]; +} + +fn main() { + let [_, _] = <() as Trait>::ARRAY; +} diff --git a/tests/ui/generic-consts/evaluatable-bounds.unconstrained.stderr b/tests/ui/generic-consts/evaluatable-bounds.unconstrained.stderr new file mode 100644 index 0000000000000..930080f7c378d --- /dev/null +++ b/tests/ui/generic-consts/evaluatable-bounds.unconstrained.stderr @@ -0,0 +1,10 @@ +error: unconstrained generic constant + --> $DIR/evaluatable-bounds.rs:16:5 + | +LL | const ARRAY: [i32; Self::LEN]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: try adding a `where` bound using this expression: `where [(); Self::LEN]:` + +error: aborting due to previous error + diff --git a/tests/ui/generic-consts/feature-gate-generic_consts.rs b/tests/ui/generic-consts/feature-gate-generic_consts.rs new file mode 100644 index 0000000000000..9bab813175d18 --- /dev/null +++ b/tests/ui/generic-consts/feature-gate-generic_consts.rs @@ -0,0 +1,37 @@ +pub trait Trait { + const ONE: i32; + //~^ ERROR generic consts are experimental + + const TWO: () + where + A: Copy; + //~^^ ERROR generic consts are experimental +} + +const CONST: i32 = 0; +//~^ ERROR generic consts are experimental + +const EMPTY<>: i32 = 0; +//~^ ERROR generic consts are experimental + +const TRUE: () = () +where + String: Clone; +//~^^ ERROR generic consts are experimental + +// Ensure that we flag generic consts inside macro calls as well: + +macro_rules! discard { + ($item:item) => {} +} + +discard! { const FREE: () = (); } +//~^ ERROR generic consts are experimental + +discard! { impl () { const ASSOC: () = (); } } +//~^ ERROR generic consts are experimental + +discard! { impl () { const ASSOC: i32 = 0 where String: Copy; } } +//~^ ERROR generic consts are experimental + +fn main() {} diff --git a/tests/ui/generic-consts/feature-gate-generic_consts.stderr b/tests/ui/generic-consts/feature-gate-generic_consts.stderr new file mode 100644 index 0000000000000..46b1a18694c00 --- /dev/null +++ b/tests/ui/generic-consts/feature-gate-generic_consts.stderr @@ -0,0 +1,77 @@ +error[E0658]: generic consts are experimental + --> $DIR/feature-gate-generic_consts.rs:2:14 + | +LL | const ONE: i32; + | ^^^ + | + = note: see issue #4294967295 for more information + = help: add `#![feature(generic_consts)]` to the crate attributes to enable + +error[E0658]: generic consts are experimental + --> $DIR/feature-gate-generic_consts.rs:6:5 + | +LL | / where +LL | | A: Copy; + | |_______________^ + | + = note: see issue #4294967295 for more information + = help: add `#![feature(generic_consts)]` to the crate attributes to enable + +error[E0658]: generic consts are experimental + --> $DIR/feature-gate-generic_consts.rs:11:12 + | +LL | const CONST: i32 = 0; + | ^^^ + | + = note: see issue #4294967295 for more information + = help: add `#![feature(generic_consts)]` to the crate attributes to enable + +error[E0658]: generic consts are experimental + --> $DIR/feature-gate-generic_consts.rs:14:12 + | +LL | const EMPTY<>: i32 = 0; + | ^^ + | + = note: see issue #4294967295 for more information + = help: add `#![feature(generic_consts)]` to the crate attributes to enable + +error[E0658]: generic consts are experimental + --> $DIR/feature-gate-generic_consts.rs:18:1 + | +LL | / where +LL | | String: Clone; + | |_________________^ + | + = note: see issue #4294967295 for more information + = help: add `#![feature(generic_consts)]` to the crate attributes to enable + +error[E0658]: generic consts are experimental + --> $DIR/feature-gate-generic_consts.rs:28:22 + | +LL | discard! { const FREE: () = (); } + | ^^^ + | + = note: see issue #4294967295 for more information + = help: add `#![feature(generic_consts)]` to the crate attributes to enable + +error[E0658]: generic consts are experimental + --> $DIR/feature-gate-generic_consts.rs:31:33 + | +LL | discard! { impl () { const ASSOC: () = (); } } + | ^^^^^^^^^^^^^ + | + = note: see issue #4294967295 for more information + = help: add `#![feature(generic_consts)]` to the crate attributes to enable + +error[E0658]: generic consts are experimental + --> $DIR/feature-gate-generic_consts.rs:34:43 + | +LL | discard! { impl () { const ASSOC: i32 = 0 where String: Copy; } } + | ^^^^^^^^^^^^^^^^^^ + | + = note: see issue #4294967295 for more information + = help: add `#![feature(generic_consts)]` 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/tests/ui/generic-consts/inference-failure.rs b/tests/ui/generic-consts/inference-failure.rs new file mode 100644 index 0000000000000..a4b309371796c --- /dev/null +++ b/tests/ui/generic-consts/inference-failure.rs @@ -0,0 +1,8 @@ +#![feature(generic_consts)] +#![allow(incomplete_features)] + +const NONE: Option = None::; + +fn main() { + let _ = NONE; //~ ERROR type annotations needed +} diff --git a/tests/ui/generic-consts/inference-failure.stderr b/tests/ui/generic-consts/inference-failure.stderr new file mode 100644 index 0000000000000..31d1e8565e81b --- /dev/null +++ b/tests/ui/generic-consts/inference-failure.stderr @@ -0,0 +1,14 @@ +error[E0282]: type annotations needed for `Option` + --> $DIR/inference-failure.rs:7:9 + | +LL | let _ = NONE; + | ^ + | +help: consider giving this pattern a type, where the type for type parameter `T` is specified + | +LL | let _: Option = NONE; + | +++++++++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0282`. diff --git a/tests/ui/generic-consts/lifetime-elision.rs b/tests/ui/generic-consts/lifetime-elision.rs new file mode 100644 index 0000000000000..71039300bf7db --- /dev/null +++ b/tests/ui/generic-consts/lifetime-elision.rs @@ -0,0 +1,11 @@ +#![feature(generic_consts)] +#![allow(incomplete_features)] + +// Check that we deny lifetime elision inside where-clauses of consts. +// FIXME(generic_consts): Are there other places we should check? + +const K: () = () +where + &T: Copy; //~ ERROR `&` without an explicit lifetime name cannot be used here + +fn main() {} diff --git a/tests/ui/generic-consts/lifetime-elision.stderr b/tests/ui/generic-consts/lifetime-elision.stderr new file mode 100644 index 0000000000000..7dc028471ba7c --- /dev/null +++ b/tests/ui/generic-consts/lifetime-elision.stderr @@ -0,0 +1,14 @@ +error[E0637]: `&` without an explicit lifetime name cannot be used here + --> $DIR/lifetime-elision.rs:9:5 + | +LL | &T: Copy; + | ^ explicit lifetime name needed here + | +help: consider introducing a higher-ranked lifetime here + | +LL | for<'a> &'a T: Copy; + | +++++++ ++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0637`. diff --git a/tests/ui/generic-consts/misplaced-where-clause.fixed b/tests/ui/generic-consts/misplaced-where-clause.fixed new file mode 100644 index 0000000000000..cad0789a122f2 --- /dev/null +++ b/tests/ui/generic-consts/misplaced-where-clause.fixed @@ -0,0 +1,18 @@ +// run-rustfix + +#![feature(generic_consts)] +#![allow(incomplete_features, dead_code)] + +const K: u64 += T::K where + T: Tr<()>; +//~^^^ ERROR where clauses are not allowed before const item bodies + +trait Tr

{ + const K: u64 + = 0 where + P: Copy; + //~^^^ ERROR where clauses are not allowed before const item bodies +} + +fn main() {} diff --git a/tests/ui/generic-consts/misplaced-where-clause.rs b/tests/ui/generic-consts/misplaced-where-clause.rs new file mode 100644 index 0000000000000..648fa6839f6c7 --- /dev/null +++ b/tests/ui/generic-consts/misplaced-where-clause.rs @@ -0,0 +1,20 @@ +// run-rustfix + +#![feature(generic_consts)] +#![allow(incomplete_features, dead_code)] + +const K: u64 +where + T: Tr<()> += T::K; +//~^^^ ERROR where clauses are not allowed before const item bodies + +trait Tr

{ + const K: u64 + where + P: Copy + = 0; + //~^^^ ERROR where clauses are not allowed before const item bodies +} + +fn main() {} diff --git a/tests/ui/generic-consts/misplaced-where-clause.stderr b/tests/ui/generic-consts/misplaced-where-clause.stderr new file mode 100644 index 0000000000000..431741d8724b0 --- /dev/null +++ b/tests/ui/generic-consts/misplaced-where-clause.stderr @@ -0,0 +1,36 @@ +error: where clauses are not allowed before const item bodies + --> $DIR/misplaced-where-clause.rs:7:1 + | +LL | const K: u64 + | - while parsing this const item +LL | / where +LL | | T: Tr<()> + | |_____________^ unexpected where clause +LL | = T::K; + | ---- the item body + | +help: move the body before the where clause + | +LL ~ = T::K where +LL ~ T: Tr<()>; + | + +error: where clauses are not allowed before const item bodies + --> $DIR/misplaced-where-clause.rs:14:5 + | +LL | const K: u64 + | - while parsing this const item +LL | / where +LL | | P: Copy + | |_______________^ unexpected where clause +LL | = 0; + | - the item body + | +help: move the body before the where clause + | +LL ~ = 0 where +LL ~ P: Copy; + | + +error: aborting due to 2 previous errors + diff --git a/tests/ui/generic-consts/parameter-defaults.rs b/tests/ui/generic-consts/parameter-defaults.rs new file mode 100644 index 0000000000000..1eb822270ca38 --- /dev/null +++ b/tests/ui/generic-consts/parameter-defaults.rs @@ -0,0 +1,12 @@ +#![feature(generic_consts)] +#![allow(incomplete_features)] + +// Check that we emit a *hard* error for generic parameter defaults on free const items since we are +// not limited by backward compatibility. +// FIXME(default_type_parameter_fallback): Consider reallowing them once they work properly. + +const NONE: Option = None::; //~ ERROR defaults for type parameters are only allowed + +fn main() { + let _ = NONE; +} diff --git a/tests/ui/generic-consts/parameter-defaults.stderr b/tests/ui/generic-consts/parameter-defaults.stderr new file mode 100644 index 0000000000000..fccd92ec946a8 --- /dev/null +++ b/tests/ui/generic-consts/parameter-defaults.stderr @@ -0,0 +1,8 @@ +error: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions + --> $DIR/parameter-defaults.rs:8:12 + | +LL | const NONE: Option = None::; + | ^^^^^^ + +error: aborting due to previous error + diff --git a/tests/ui/generic-consts/recursive.rs b/tests/ui/generic-consts/recursive.rs new file mode 100644 index 0000000000000..939c6119a9880 --- /dev/null +++ b/tests/ui/generic-consts/recursive.rs @@ -0,0 +1,13 @@ +// FIXME(fmease): #prMergeBlocker This leads to a stack overflow in the compiler! +// Detect this during normalization / const evaluation and report a cycle error instead. + +// ignore-test + +#![feature(generic_consts)] +#![allow(incomplete_features)] + +const RECUR: () = RECUR::<(T,)>; + +fn main() { + let _ = RECUR::<()>; +} diff --git a/tests/ui/generic-consts/trivially-unsatisfied-bounds-0.rs b/tests/ui/generic-consts/trivially-unsatisfied-bounds-0.rs new file mode 100644 index 0000000000000..275f9222e14b3 --- /dev/null +++ b/tests/ui/generic-consts/trivially-unsatisfied-bounds-0.rs @@ -0,0 +1,12 @@ +#![feature(generic_consts, trivial_bounds)] +#![allow(incomplete_features)] + +// Ensure that we check if trivial bounds on consts hold or not. + +const UNUSABLE: () = () +where + String: Copy; + +fn main() { + let _ = UNUSABLE; //~ ERROR the trait bound `String: Copy` is not satisfied +} diff --git a/tests/ui/generic-consts/trivially-unsatisfied-bounds-0.stderr b/tests/ui/generic-consts/trivially-unsatisfied-bounds-0.stderr new file mode 100644 index 0000000000000..c3ef94529a49b --- /dev/null +++ b/tests/ui/generic-consts/trivially-unsatisfied-bounds-0.stderr @@ -0,0 +1,18 @@ +error[E0277]: the trait bound `String: Copy` is not satisfied + --> $DIR/trivially-unsatisfied-bounds-0.rs:11:13 + | +LL | let _ = UNUSABLE; + | ^^^^^^^^ the trait `Copy` is not implemented for `String` + | +note: required by a bound in `UNUSABLE` + --> $DIR/trivially-unsatisfied-bounds-0.rs:8:13 + | +LL | const UNUSABLE: () = () + | -------- required by a bound in this constant +LL | where +LL | String: Copy; + | ^^^^ required by this bound in `UNUSABLE` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/generic-consts/trivially-unsatisfied-bounds-1.rs b/tests/ui/generic-consts/trivially-unsatisfied-bounds-1.rs new file mode 100644 index 0000000000000..31a4a686fbc94 --- /dev/null +++ b/tests/ui/generic-consts/trivially-unsatisfied-bounds-1.rs @@ -0,0 +1,13 @@ +#![feature(generic_consts, trivial_bounds)] +#![allow(incomplete_features, dead_code, trivial_bounds)] + +// FIXME(generic_consts): This looks like a compiler bug to me, is it one though? +// I expected that we wouldn't emit any errors. +// I thought we'd skip the evaluation of consts whose bounds don't hold. + +const UNUSED: () = () +where + String: Copy; +//~^^^ ERROR evaluation of constant value failed + +fn main() {} diff --git a/tests/ui/generic-consts/trivially-unsatisfied-bounds-1.stderr b/tests/ui/generic-consts/trivially-unsatisfied-bounds-1.stderr new file mode 100644 index 0000000000000..11c7e3c7b11b4 --- /dev/null +++ b/tests/ui/generic-consts/trivially-unsatisfied-bounds-1.stderr @@ -0,0 +1,11 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/trivially-unsatisfied-bounds-1.rs:8:1 + | +LL | / const UNUSED: () = () +LL | | where +LL | | String: Copy; + | |_________________^ entering unreachable code + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/generic-consts/unsatisfied-bounds.rs b/tests/ui/generic-consts/unsatisfied-bounds.rs new file mode 100644 index 0000000000000..67b966581deb4 --- /dev/null +++ b/tests/ui/generic-consts/unsatisfied-bounds.rs @@ -0,0 +1,36 @@ +#![feature(generic_consts)] +#![allow(incomplete_features)] + +// Ensure that we check if bounds on consts hold or not. + +use std::convert::Infallible; + +const C: () = (); + +const K: () = () +where + Infallible: From; + +const Q<'a, T: 'a>: () = (); + +trait Trait

{ + const A: u32 + where + P: Copy; + + const B: u32 + where + Infallible: From; +} + +impl

Trait

for () { + const A: u32 = 0; + const B: u32 = 1; +} + +fn main() { + let () = C::; //~ ERROR the trait bound `String: Copy` is not satisfied + let () = K::<()>; //~ ERROR the trait bound `Infallible: From<()>` is not satisfied + let _ = <() as Trait>>::A; //~ ERROR the trait bound `Vec: Copy` is not satisfied + let _ = <() as Trait<&'static str>>::B::<()>; //~ ERROR the trait bound `Infallible: From<()>` is not satisfied +} diff --git a/tests/ui/generic-consts/unsatisfied-bounds.stderr b/tests/ui/generic-consts/unsatisfied-bounds.stderr new file mode 100644 index 0000000000000..eac8465825ec5 --- /dev/null +++ b/tests/ui/generic-consts/unsatisfied-bounds.stderr @@ -0,0 +1,62 @@ +error[E0277]: the trait bound `String: Copy` is not satisfied + --> $DIR/unsatisfied-bounds.rs:32:18 + | +LL | let () = C::; + | ^^^^^^ the trait `Copy` is not implemented for `String` + | +note: required by a bound in `C` + --> $DIR/unsatisfied-bounds.rs:8:12 + | +LL | const C: () = (); + | ^^^^ required by this bound in `C` + +error[E0277]: the trait bound `Infallible: From<()>` is not satisfied + --> $DIR/unsatisfied-bounds.rs:33:18 + | +LL | let () = K::<()>; + | ^^ the trait `From<()>` is not implemented for `Infallible` + | + = help: the trait `From` is implemented for `Infallible` +note: required by a bound in `K` + --> $DIR/unsatisfied-bounds.rs:12:17 + | +LL | const K: () = () + | - required by a bound in this constant +LL | where +LL | Infallible: From; + | ^^^^^^^ required by this bound in `K` + +error[E0277]: the trait bound `Vec: Copy` is not satisfied + --> $DIR/unsatisfied-bounds.rs:34:13 + | +LL | let _ = <() as Trait>>::A; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Vec` + | +note: required by a bound in `Trait::A` + --> $DIR/unsatisfied-bounds.rs:19:12 + | +LL | const A: u32 + | - required by a bound in this associated constant +LL | where +LL | P: Copy; + | ^^^^ required by this bound in `Trait::A` + +error[E0277]: the trait bound `Infallible: From<()>` is not satisfied + --> $DIR/unsatisfied-bounds.rs:35:46 + | +LL | let _ = <() as Trait<&'static str>>::B::<()>; + | ^^ the trait `From<()>` is not implemented for `Infallible` + | + = help: the trait `From` is implemented for `Infallible` +note: required by a bound in `Trait::B` + --> $DIR/unsatisfied-bounds.rs:23:21 + | +LL | const B: u32 + | - required by a bound in this associated constant +LL | where +LL | Infallible: From; + | ^^^^^^^ required by this bound in `Trait::B` + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/generic-consts/unsatisfied-evaluatable-bounds.rs b/tests/ui/generic-consts/unsatisfied-evaluatable-bounds.rs new file mode 100644 index 0000000000000..b9c6e2aa4dc03 --- /dev/null +++ b/tests/ui/generic-consts/unsatisfied-evaluatable-bounds.rs @@ -0,0 +1,12 @@ +#![feature(generic_consts, generic_const_exprs)] +#![allow(incomplete_features)] + +// Ensure that we check if (makeshift) "evaluatable"-bounds on consts hold or not. + +const POSITIVE: usize = N +where + [(); N - 1]:; //~ ERROR evaluation of `POSITIVE::<0>::{constant#0}` failed + +fn main() { + let _ = POSITIVE::<0>; +} diff --git a/tests/ui/generic-consts/unsatisfied-evaluatable-bounds.stderr b/tests/ui/generic-consts/unsatisfied-evaluatable-bounds.stderr new file mode 100644 index 0000000000000..bed213b0caa7a --- /dev/null +++ b/tests/ui/generic-consts/unsatisfied-evaluatable-bounds.stderr @@ -0,0 +1,9 @@ +error[E0080]: evaluation of `POSITIVE::<0>::{constant#0}` failed + --> $DIR/unsatisfied-evaluatable-bounds.rs:8:10 + | +LL | [(); 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/tests/ui/generic-consts/unsatisfied-outlives-bounds.rs b/tests/ui/generic-consts/unsatisfied-outlives-bounds.rs new file mode 100644 index 0000000000000..660a87d178890 --- /dev/null +++ b/tests/ui/generic-consts/unsatisfied-outlives-bounds.rs @@ -0,0 +1,17 @@ +#![feature(generic_consts)] +#![allow(incomplete_features)] + +// Ensure that we check if outlives-bounds on consts hold or not. + +const C<'a, T: 'a>: () = (); +const K<'a, 'b: 'a>: () = (); + +fn parametrized0<'any>() { + let () = C::<'static, &'any ()>; //~ ERROR lifetime may not live long enough +} + +fn parametrized1<'any>() { + let () = K::<'static, 'any>; //~ ERROR lifetime may not live long enough +} + +fn main() {} diff --git a/tests/ui/generic-consts/unsatisfied-outlives-bounds.stderr b/tests/ui/generic-consts/unsatisfied-outlives-bounds.stderr new file mode 100644 index 0000000000000..72e4265b3d7ff --- /dev/null +++ b/tests/ui/generic-consts/unsatisfied-outlives-bounds.stderr @@ -0,0 +1,18 @@ +error: lifetime may not live long enough + --> $DIR/unsatisfied-outlives-bounds.rs:10:14 + | +LL | fn parametrized0<'any>() { + | ---- lifetime `'any` defined here +LL | let () = C::<'static, &'any ()>; + | ^^^^^^^^^^^^^^^^^^^^^^ requires that `'any` must outlive `'static` + +error: lifetime may not live long enough + --> $DIR/unsatisfied-outlives-bounds.rs:14:14 + | +LL | fn parametrized1<'any>() { + | ---- lifetime `'any` defined here +LL | let () = K::<'static, 'any>; + | ^^^^^^^^^^^^^^^^^^ requires that `'any` must outlive `'static` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/impl-trait/deduce-signature-from-supertrait.rs b/tests/ui/impl-trait/deduce-signature-from-supertrait.rs index d2c3479203573..7a51aac44e2e8 100644 --- a/tests/ui/impl-trait/deduce-signature-from-supertrait.rs +++ b/tests/ui/impl-trait/deduce-signature-from-supertrait.rs @@ -8,8 +8,10 @@ impl SuperExpectation for T {} type Foo = impl SuperExpectation; -fn main() { +fn bop(_: Foo) { let _: Foo = |x| { let _ = x.to_string(); }; } + +fn main() {} diff --git a/tests/ui/impl-trait/equality.stderr b/tests/ui/impl-trait/equality.stderr index 69f4cbbbf4294..9b8bff215e027 100644 --- a/tests/ui/impl-trait/equality.stderr +++ b/tests/ui/impl-trait/equality.stderr @@ -30,10 +30,10 @@ LL | n + sum_to(n - 1) | = help: the trait `Add` is not implemented for `u32` = help: the following other types implement trait `Add`: + + > <&'a u32 as Add> <&u32 as Add<&u32>> - > - error: aborting due to 2 previous errors; 1 warning emitted diff --git a/tests/ui/impl-trait/in-assoc-type.rs b/tests/ui/impl-trait/in-assoc-type.rs index 36c54bdd6de34..38ad2fa6f02ee 100644 --- a/tests/ui/impl-trait/in-assoc-type.rs +++ b/tests/ui/impl-trait/in-assoc-type.rs @@ -1,3 +1,6 @@ +//! This test checks that we don't allow registering hidden types for +//! opaque types from other impls. + #![feature(impl_trait_in_assoc_type)] trait Foo { diff --git a/tests/ui/impl-trait/in-assoc-type.stderr b/tests/ui/impl-trait/in-assoc-type.stderr index ab3f3a14410d0..af60da07cac31 100644 --- a/tests/ui/impl-trait/in-assoc-type.stderr +++ b/tests/ui/impl-trait/in-assoc-type.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/in-assoc-type.rs:17:22 + --> $DIR/in-assoc-type.rs:20:22 | LL | type Bar = impl std::fmt::Debug; | -------------------- the expected opaque type @@ -12,7 +12,7 @@ LL | fn foo(&self) -> >::Bar {} = note: expected opaque type `<() as Foo<()>>::Bar` found unit type `()` note: this item must have the opaque type in its signature in order to be able to register hidden types - --> $DIR/in-assoc-type.rs:17:8 + --> $DIR/in-assoc-type.rs:20:8 | LL | fn foo(&self) -> >::Bar {} | ^^^ diff --git a/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.current.stderr b/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.current.stderr new file mode 100644 index 0000000000000..ff30103b771dd --- /dev/null +++ b/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.current.stderr @@ -0,0 +1,16 @@ +error[E0277]: the trait bound `impl Foo: Foo` is not satisfied + --> $DIR/return-dont-satisfy-bounds.rs:13:34 + | +LL | fn foo>(self) -> impl Foo { + | ^^^^^^^^^^^^ the trait `Foo` is not implemented for `impl Foo` + | + = help: the trait `Foo` is implemented for `Bar` +note: required by a bound in `Foo::foo::{opaque#0}` + --> $DIR/return-dont-satisfy-bounds.rs:7:30 + | +LL | fn foo(self) -> impl Foo; + | ^^^^^^ required by this bound in `Foo::foo::{opaque#0}` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.next.stderr b/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.next.stderr new file mode 100644 index 0000000000000..7c7f7feaa5506 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.next.stderr @@ -0,0 +1,16 @@ +error[E0277]: the trait bound `impl Foo: Foo` is not satisfied + --> $DIR/return-dont-satisfy-bounds.rs:13:34 + | +LL | fn foo>(self) -> impl Foo { + | ^^^^^^^^^^^^ the trait `Foo` is not implemented for `impl Foo` + | + = help: the trait `Foo` is implemented for `Bar` +note: required by a bound in `Foo::{opaque#0}` + --> $DIR/return-dont-satisfy-bounds.rs:7:30 + | +LL | fn foo(self) -> impl Foo; + | ^^^^^^ required by this bound in `Foo::{opaque#0}` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.rs b/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.rs new file mode 100644 index 0000000000000..65528f212e296 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.rs @@ -0,0 +1,19 @@ +// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty +// revisions: current next + +#![feature(return_position_impl_trait_in_trait)] + +trait Foo { + fn foo(self) -> impl Foo; +} + +struct Bar; + +impl Foo for Bar { + fn foo>(self) -> impl Foo { + //~^ ERROR: the trait bound `impl Foo: Foo` is not satisfied [E0277] + self + } +} + +fn main() {} diff --git a/tests/ui/impl-trait/issues/issue-70877.rs b/tests/ui/impl-trait/issues/issue-70877.rs index 8169cfafac711..df7722986744d 100644 --- a/tests/ui/impl-trait/issues/issue-70877.rs +++ b/tests/ui/impl-trait/issues/issue-70877.rs @@ -25,12 +25,12 @@ fn ham() -> Foo { Bar(1) } -fn oof() -> impl std::fmt::Debug { +fn oof(_: Foo) -> impl std::fmt::Debug { let mut bar = ham(); let func = bar.next().unwrap(); return func(&"oof"); //~ ERROR opaque type's hidden type cannot be another opaque type } fn main() { - let _ = oof(); + let _ = oof(ham()); } diff --git a/tests/ui/impl-trait/issues/issue-70877.stderr b/tests/ui/impl-trait/issues/issue-70877.stderr index 8813bff3c353e..ee140e6f6c43d 100644 --- a/tests/ui/impl-trait/issues/issue-70877.stderr +++ b/tests/ui/impl-trait/issues/issue-70877.stderr @@ -5,10 +5,10 @@ LL | return func(&"oof"); | ^^^^^^^^^^^^ one of the two opaque types used here has to be outside its defining scope | note: opaque type whose hidden type is being assigned - --> $DIR/issue-70877.rs:28:13 + --> $DIR/issue-70877.rs:28:19 | -LL | fn oof() -> impl std::fmt::Debug { - | ^^^^^^^^^^^^^^^^^^^^ +LL | fn oof(_: Foo) -> impl std::fmt::Debug { + | ^^^^^^^^^^^^^^^^^^^^ note: opaque type being used as hidden type --> $DIR/issue-70877.rs:4:15 | diff --git a/tests/ui/impl-trait/issues/issue-74282.rs b/tests/ui/impl-trait/issues/issue-74282.rs index 654de0cd0253c..51bd5f67ed574 100644 --- a/tests/ui/impl-trait/issues/issue-74282.rs +++ b/tests/ui/impl-trait/issues/issue-74282.rs @@ -3,9 +3,12 @@ type Closure = impl Fn() -> u64; struct Anonymous(Closure); -fn main() { +fn bop(_: Closure) { let y = || -> Closure { || 3 }; - Anonymous(|| { //~ ERROR mismatched types - 3 //~^ ERROR mismatched types + Anonymous(|| { + //~^ ERROR mismatched types + 3 //~^^ ERROR mismatched types }) } + +fn main() {} diff --git a/tests/ui/impl-trait/issues/issue-74282.stderr b/tests/ui/impl-trait/issues/issue-74282.stderr index 724f3c5d6747c..d43e9fee0b359 100644 --- a/tests/ui/impl-trait/issues/issue-74282.stderr +++ b/tests/ui/impl-trait/issues/issue-74282.stderr @@ -8,6 +8,7 @@ LL | Anonymous(|| { | _____---------_^ | | | | | arguments to this struct are incorrect +LL | | LL | | 3 LL | | }) | |_____^ expected opaque type, found closure @@ -25,15 +26,20 @@ LL | struct Anonymous(Closure); error[E0308]: mismatched types --> $DIR/issue-74282.rs:8:5 | -LL | fn main() { - | - expected `()` because of default return type -LL | let y = || -> Closure { || 3 }; LL | / Anonymous(|| { +LL | | LL | | 3 LL | | }) - | | ^- help: consider using a semicolon here: `;` - | |______| - | expected `()`, found `Anonymous` + | |______^ expected `()`, found `Anonymous` + | +help: consider using a semicolon here + | +LL | }); + | + +help: try adding a return type + | +LL | fn bop(_: Closure) -> Anonymous { + | ++++++++++++ error: aborting due to 2 previous errors diff --git a/tests/ui/impl-trait/issues/issue-78722-2.rs b/tests/ui/impl-trait/issues/issue-78722-2.rs new file mode 100644 index 0000000000000..cf5361e1e602c --- /dev/null +++ b/tests/ui/impl-trait/issues/issue-78722-2.rs @@ -0,0 +1,22 @@ +//! test that we cannot register hidden types for opaque types +//! declared outside an anonymous constant. +// edition:2018 + +#![feature(type_alias_impl_trait)] + +type F = impl core::future::Future; + +struct Bug { + V1: [(); { + fn concrete_use() -> F { + //~^ ERROR future that resolves to `u8`, but it resolves to `()` + async {} + } + let f: F = async { 1 }; + //~^ ERROR item constrains opaque type that is not in its signature + //~| ERROR `async` blocks are not allowed in constants + 1 + }], +} + +fn main() {} diff --git a/tests/ui/impl-trait/issues/issue-78722-2.stderr b/tests/ui/impl-trait/issues/issue-78722-2.stderr new file mode 100644 index 0000000000000..6db603e775175 --- /dev/null +++ b/tests/ui/impl-trait/issues/issue-78722-2.stderr @@ -0,0 +1,32 @@ +error[E0658]: `async` blocks are not allowed in constants + --> $DIR/issue-78722-2.rs:15:20 + | +LL | let f: F = async { 1 }; + | ^^^^^^^^^^^ + | + = note: see issue #85368 for more information + = help: add `#![feature(const_async_blocks)]` to the crate attributes to enable + +error[E0271]: expected `[async block@$DIR/issue-78722-2.rs:13:13: 13:21]` to be a future that resolves to `u8`, but it resolves to `()` + --> $DIR/issue-78722-2.rs:11:30 + | +LL | fn concrete_use() -> F { + | ^ expected `()`, found `u8` + +error: item constrains opaque type that is not in its signature + --> $DIR/issue-78722-2.rs:15:20 + | +LL | let f: F = async { 1 }; + | ^^^^^^^^^^^ + | + = note: this item must mention the opaque type in its signature in order to be able to register hidden types +note: this item must mention the opaque type in its signature in order to be able to register hidden types + --> $DIR/issue-78722-2.rs:15:20 + | +LL | let f: F = async { 1 }; + | ^^^^^^^^^^^ + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0271, E0658. +For more information about an error, try `rustc --explain E0271`. diff --git a/tests/ui/impl-trait/issues/issue-78722.rs b/tests/ui/impl-trait/issues/issue-78722.rs index 7b5ab5f229835..75ccc8d8e8a9a 100644 --- a/tests/ui/impl-trait/issues/issue-78722.rs +++ b/tests/ui/impl-trait/issues/issue-78722.rs @@ -2,10 +2,9 @@ #![feature(type_alias_impl_trait)] -type F = impl core::future::Future; - struct Bug { V1: [(); { + type F = impl core::future::Future; fn concrete_use() -> F { //~^ ERROR to be a future that resolves to `u8`, but it resolves to `()` async {} diff --git a/tests/ui/impl-trait/issues/issue-78722.stderr b/tests/ui/impl-trait/issues/issue-78722.stderr index 05a2c135cf7c7..36340a0bab41a 100644 --- a/tests/ui/impl-trait/issues/issue-78722.stderr +++ b/tests/ui/impl-trait/issues/issue-78722.stderr @@ -1,5 +1,5 @@ error[E0658]: `async` blocks are not allowed in constants - --> $DIR/issue-78722.rs:13:20 + --> $DIR/issue-78722.rs:12:20 | LL | let f: F = async { 1 }; | ^^^^^^^^^^^ @@ -7,8 +7,8 @@ LL | let f: F = async { 1 }; = note: see issue #85368 for more information = help: add `#![feature(const_async_blocks)]` to the crate attributes to enable -error[E0271]: expected `[async block@$DIR/issue-78722.rs:11:13: 11:21]` to be a future that resolves to `u8`, but it resolves to `()` - --> $DIR/issue-78722.rs:9:30 +error[E0271]: expected `[async block@$DIR/issue-78722.rs:10:13: 10:21]` to be a future that resolves to `u8`, but it resolves to `()` + --> $DIR/issue-78722.rs:8:30 | LL | fn concrete_use() -> F { | ^ expected `()`, found `u8` diff --git a/tests/ui/impl-trait/reveal-during-codegen.rs b/tests/ui/impl-trait/reveal-during-codegen.rs new file mode 100644 index 0000000000000..11463772eb38c --- /dev/null +++ b/tests/ui/impl-trait/reveal-during-codegen.rs @@ -0,0 +1,11 @@ +// build-pass +// revisions: current next +//[next] compile-flags: -Ztrait-solver=next + +fn test() -> Option { + Some("") +} + +fn main() { + test(); +} diff --git a/tests/ui/issues/issue-11771.stderr b/tests/ui/issues/issue-11771.stderr index 161fce4b0315c..b37140f60f9c1 100644 --- a/tests/ui/issues/issue-11771.stderr +++ b/tests/ui/issues/issue-11771.stderr @@ -6,14 +6,14 @@ LL | 1 + | = help: the trait `Add<()>` is not implemented for `{integer}` = help: the following other types implement trait `Add`: - <&'a f32 as Add> - <&'a f64 as Add> - <&'a i128 as Add> - <&'a i16 as Add> - <&'a i32 as Add> - <&'a i64 as Add> - <&'a i8 as Add> - <&'a isize as Add> + + > + + > + + > + + > and 48 others error[E0277]: cannot add `()` to `{integer}` @@ -24,14 +24,14 @@ LL | 1 + | = help: the trait `Add<()>` is not implemented for `{integer}` = help: the following other types implement trait `Add`: - <&'a f32 as Add> - <&'a f64 as Add> - <&'a i128 as Add> - <&'a i16 as Add> - <&'a i32 as Add> - <&'a i64 as Add> - <&'a i8 as Add> - <&'a isize as Add> + + > + + > + + > + + > and 48 others error: aborting due to 2 previous errors diff --git a/tests/ui/issues/issue-24352.stderr b/tests/ui/issues/issue-24352.stderr index 1f51b6e29050c..f1c3891b87000 100644 --- a/tests/ui/issues/issue-24352.stderr +++ b/tests/ui/issues/issue-24352.stderr @@ -6,10 +6,10 @@ LL | 1.0f64 - 1 | = help: the trait `Sub<{integer}>` is not implemented for `f64` = help: the following other types implement trait `Sub`: + + > <&'a f64 as Sub> <&f64 as Sub<&f64>> - > - help: consider using a floating-point literal by writing it with `.0` | LL | 1.0f64 - 1.0 diff --git a/tests/ui/issues/issue-32709.stderr b/tests/ui/issues/issue-32709.stderr index a4ba5da4d8724..94e8f9295fdd5 100644 --- a/tests/ui/issues/issue-32709.stderr +++ b/tests/ui/issues/issue-32709.stderr @@ -8,6 +8,7 @@ LL | Err(5)?; | = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait = help: the following other types implement trait `From`: + <(T,) as From<[T; 1]>> <(T, T) as From<[T; 2]>> <(T, T, T) as From<[T; 3]>> <(T, T, T, T) as From<[T; 4]>> @@ -15,7 +16,6 @@ LL | Err(5)?; <(T, T, T, T, T, T) as From<[T; 6]>> <(T, T, T, T, T, T, T) as From<[T; 7]>> <(T, T, T, T, T, T, T, T) as From<[T; 8]>> - <(T, T, T, T, T, T, T, T, T) as From<[T; 9]>> and 4 others = note: required for `Result` to implement `FromResidual>` diff --git a/tests/ui/issues/issue-50582.stderr b/tests/ui/issues/issue-50582.stderr index 3d527eb6b4e4a..9eafd7ab4f0fa 100644 --- a/tests/ui/issues/issue-50582.stderr +++ b/tests/ui/issues/issue-50582.stderr @@ -15,14 +15,14 @@ LL | Vec::<[(); 1 + for x in 0..1 {}]>::new(); | = help: the trait `Add<()>` is not implemented for `{integer}` = help: the following other types implement trait `Add`: - <&'a f32 as Add> - <&'a f64 as Add> - <&'a i128 as Add> - <&'a i16 as Add> - <&'a i32 as Add> - <&'a i64 as Add> - <&'a i8 as Add> - <&'a isize as Add> + + > + + > + + > + + > and 48 others error: aborting due to 2 previous errors diff --git a/tests/ui/issues/issue-67552.rs b/tests/ui/issues/issue-67552.rs index ec1997ccd5d66..7336b873dd643 100644 --- a/tests/ui/issues/issue-67552.rs +++ b/tests/ui/issues/issue-67552.rs @@ -1,6 +1,7 @@ // build-fail // compile-flags: -Copt-level=0 // normalize-stderr-test: ".nll/" -> "/" +// ignore-compare-mode-next-solver (hangs) fn main() { rec(Empty); diff --git a/tests/ui/issues/issue-67552.stderr b/tests/ui/issues/issue-67552.stderr index 4746f918bf8dd..f93ed67dab244 100644 --- a/tests/ui/issues/issue-67552.stderr +++ b/tests/ui/issues/issue-67552.stderr @@ -1,11 +1,11 @@ error: reached the recursion limit while instantiating `rec::<&mut &mut &mut &mut &mut ...>` - --> $DIR/issue-67552.rs:29:9 + --> $DIR/issue-67552.rs:30:9 | LL | rec(identity(&mut it)) | ^^^^^^^^^^^^^^^^^^^^^^ | note: `rec` defined here - --> $DIR/issue-67552.rs:22:1 + --> $DIR/issue-67552.rs:23:1 | LL | / fn rec(mut it: T) LL | | where diff --git a/tests/ui/iterators/invalid-iterator-chain-with-int-infer.stderr b/tests/ui/iterators/invalid-iterator-chain-with-int-infer.stderr index 3cb5e44c71101..7f1b9c38e6798 100644 --- a/tests/ui/iterators/invalid-iterator-chain-with-int-infer.stderr +++ b/tests/ui/iterators/invalid-iterator-chain-with-int-infer.stderr @@ -6,8 +6,8 @@ LL | let x = Some(()).iter().map(|()| 1).sum::(); | = help: the trait `Sum<{integer}>` is not implemented for `f32` = help: the following other types implement trait `Sum`: - > + > note: the method call chain might not have had the expected associated types --> $DIR/invalid-iterator-chain-with-int-infer.rs:2:29 | diff --git a/tests/ui/iterators/invalid-iterator-chain.stderr b/tests/ui/iterators/invalid-iterator-chain.stderr index f3dceca7e4139..a2688107d10db 100644 --- a/tests/ui/iterators/invalid-iterator-chain.stderr +++ b/tests/ui/iterators/invalid-iterator-chain.stderr @@ -24,8 +24,8 @@ LL | println!("{}", scores.sum::()); | = help: the trait `Sum<()>` is not implemented for `i32` = help: the following other types implement trait `Sum`: - > + > note: the method call chain might not have had the expected associated types --> $DIR/invalid-iterator-chain.rs:12:10 | @@ -49,8 +49,8 @@ LL | .sum::(), | = help: the trait `Sum<()>` is not implemented for `i32` = help: the following other types implement trait `Sum`: - > + > note: the method call chain might not have had the expected associated types --> $DIR/invalid-iterator-chain.rs:25:14 | @@ -81,8 +81,8 @@ LL | .sum::(), | = help: the trait `Sum` is not implemented for `i32` = help: the following other types implement trait `Sum`: - > + > note: the method call chain might not have had the expected associated types --> $DIR/invalid-iterator-chain.rs:33:14 | @@ -109,8 +109,8 @@ LL | println!("{}", vec![0, 1].iter().map(|x| { x; }).sum::()); | = help: the trait `Sum<()>` is not implemented for `i32` = help: the following other types implement trait `Sum`: - > + > note: the method call chain might not have had the expected associated types --> $DIR/invalid-iterator-chain.rs:38:38 | @@ -130,8 +130,8 @@ LL | println!("{}", vec![(), ()].iter().sum::()); | = help: the trait `Sum<&()>` is not implemented for `i32` = help: the following other types implement trait `Sum`: - > + > note: the method call chain might not have had the expected associated types --> $DIR/invalid-iterator-chain.rs:39:33 | diff --git a/tests/ui/lint/issue-99387.rs b/tests/ui/lint/issue-99387.rs index 616eb935e93d4..ba5031167e33d 100644 --- a/tests/ui/lint/issue-99387.rs +++ b/tests/ui/lint/issue-99387.rs @@ -1,4 +1,5 @@ -// check-pass +//! Test that we don't follow through projections to find +//! opaque types. #![feature(type_alias_impl_trait)] #![allow(private_in_public)] @@ -18,6 +19,7 @@ impl<'a> Tr for &'a () { } pub fn ohno<'a>() -> <&'a () as Tr>::Item { + //~^ ERROR item constrains opaque type that is not in its signature None.into_iter() } diff --git a/tests/ui/lint/issue-99387.stderr b/tests/ui/lint/issue-99387.stderr new file mode 100644 index 0000000000000..3a46ce7e1952d --- /dev/null +++ b/tests/ui/lint/issue-99387.stderr @@ -0,0 +1,15 @@ +error: item constrains opaque type that is not in its signature + --> $DIR/issue-99387.rs:21:22 + | +LL | pub fn ohno<'a>() -> <&'a () as Tr>::Item { + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: this item must mention the opaque type in its signature in order to be able to register hidden types +note: this item must mention the opaque type in its signature in order to be able to register hidden types + --> $DIR/issue-99387.rs:21:8 + | +LL | pub fn ohno<'a>() -> <&'a () as Tr>::Item { + | ^^^^ + +error: aborting due to previous error + diff --git a/tests/ui/mismatched_types/binops.stderr b/tests/ui/mismatched_types/binops.stderr index 3585587ed4c02..b18ab7f7608d5 100644 --- a/tests/ui/mismatched_types/binops.stderr +++ b/tests/ui/mismatched_types/binops.stderr @@ -6,14 +6,14 @@ LL | 1 + Some(1); | = help: the trait `Add>` is not implemented for `{integer}` = help: the following other types implement trait `Add`: - <&'a f32 as Add> - <&'a f64 as Add> - <&'a i128 as Add> - <&'a i16 as Add> - <&'a i32 as Add> - <&'a i64 as Add> - <&'a i8 as Add> - <&'a isize as Add> + + > + + > + + > + + > and 48 others error[E0277]: cannot subtract `Option<{integer}>` from `usize` @@ -24,10 +24,10 @@ LL | 2 as usize - Some(1); | = help: the trait `Sub>` is not implemented for `usize` = help: the following other types implement trait `Sub`: + + > <&'a usize as Sub> <&usize as Sub<&usize>> - > - error[E0277]: cannot multiply `{integer}` by `()` --> $DIR/binops.rs:4:7 @@ -37,14 +37,14 @@ LL | 3 * (); | = help: the trait `Mul<()>` is not implemented for `{integer}` = help: the following other types implement trait `Mul`: - <&'a f32 as Mul> - <&'a f64 as Mul> - <&'a i128 as Mul> - <&'a i16 as Mul> - <&'a i32 as Mul> - <&'a i64 as Mul> - <&'a i8 as Mul> - <&'a isize as Mul> + + > + + > + + > + + > and 49 others error[E0277]: cannot divide `{integer}` by `&str` @@ -55,14 +55,14 @@ LL | 4 / ""; | = help: the trait `Div<&str>` is not implemented for `{integer}` = help: the following other types implement trait `Div`: - <&'a f32 as Div> - <&'a f64 as Div> - <&'a i128 as Div> - <&'a i16 as Div> - <&'a i32 as Div> - <&'a i64 as Div> - <&'a i8 as Div> - <&'a isize as Div> + + > + + > + + > + + > and 54 others error[E0277]: can't compare `{integer}` with `String` @@ -73,14 +73,14 @@ LL | 5 < String::new(); | = help: the trait `PartialOrd` is not implemented for `{integer}` = help: the following other types implement trait `PartialOrd`: - f32 - f64 - i128 + isize + i8 i16 i32 i64 - i8 - isize + i128 + usize + u8 and 6 others error[E0277]: can't compare `{integer}` with `Result<{integer}, _>` @@ -91,14 +91,14 @@ LL | 6 == Ok(1); | = help: the trait `PartialEq>` is not implemented for `{integer}` = help: the following other types implement trait `PartialEq`: - f32 - f64 - i128 + isize + i8 i16 i32 i64 - i8 - isize + i128 + usize + u8 and 6 others error: aborting due to 6 previous errors diff --git a/tests/ui/never_type/diverging-fallback-no-leak.fallback.stderr b/tests/ui/never_type/diverging-fallback-no-leak.fallback.stderr index 3215c4669d5e3..df29fe227135d 100644 --- a/tests/ui/never_type/diverging-fallback-no-leak.fallback.stderr +++ b/tests/ui/never_type/diverging-fallback-no-leak.fallback.stderr @@ -7,8 +7,8 @@ LL | unconstrained_arg(return); | required by a bound introduced by this call | = help: the following other types implement trait `Test`: - () i32 + () = note: this error might have been caused by changes to Rust's type-inference algorithm (see issue #48950 for more information) = help: did you intend to use the type `()` here instead? note: required by a bound in `unconstrained_arg` diff --git a/tests/ui/never_type/issue-13352.stderr b/tests/ui/never_type/issue-13352.stderr index 2d22da0b420e0..406785bfea0e2 100644 --- a/tests/ui/never_type/issue-13352.stderr +++ b/tests/ui/never_type/issue-13352.stderr @@ -6,10 +6,10 @@ LL | 2_usize + (loop {}); | = help: the trait `Add<()>` is not implemented for `usize` = help: the following other types implement trait `Add`: + + > <&'a usize as Add> <&usize as Add<&usize>> - > - error: aborting due to previous error diff --git a/tests/ui/nll/user-annotations/normalization-2.stderr b/tests/ui/nll/user-annotations/normalization-2.stderr index 5299282ea151e..6b0dcb414aea5 100644 --- a/tests/ui/nll/user-annotations/normalization-2.stderr +++ b/tests/ui/nll/user-annotations/normalization-2.stderr @@ -147,7 +147,7 @@ LL | fn test_variants<'a, 'b, 'c>() { | -- lifetime `'b` defined here ... LL | >::Tuple(); - | ^^^^^^^^^^^^^^^ requires that `'b` must outlive `'static` + | ^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'static` error: lifetime may not live long enough --> $DIR/normalization-2.rs:93:5 diff --git a/tests/ui/numbers-arithmetic/not-suggest-float-literal.stderr b/tests/ui/numbers-arithmetic/not-suggest-float-literal.stderr index 8f0eef237cfe2..e1825eb5b541d 100644 --- a/tests/ui/numbers-arithmetic/not-suggest-float-literal.stderr +++ b/tests/ui/numbers-arithmetic/not-suggest-float-literal.stderr @@ -6,10 +6,10 @@ LL | x + 100.0 | = help: the trait `Add<{float}>` is not implemented for `u8` = help: the following other types implement trait `Add`: + + > <&'a u8 as Add> <&u8 as Add<&u8>> - > - error[E0277]: cannot add `&str` to `f64` --> $DIR/not-suggest-float-literal.rs:6:7 @@ -19,10 +19,10 @@ LL | x + "foo" | = help: the trait `Add<&str>` is not implemented for `f64` = help: the following other types implement trait `Add`: + + > <&'a f64 as Add> <&f64 as Add<&f64>> - > - error[E0277]: cannot add `{integer}` to `f64` --> $DIR/not-suggest-float-literal.rs:11:7 @@ -32,10 +32,10 @@ LL | x + y | = help: the trait `Add<{integer}>` is not implemented for `f64` = help: the following other types implement trait `Add`: + + > <&'a f64 as Add> <&f64 as Add<&f64>> - > - error[E0277]: cannot subtract `{float}` from `u8` --> $DIR/not-suggest-float-literal.rs:15:7 @@ -45,10 +45,10 @@ LL | x - 100.0 | = help: the trait `Sub<{float}>` is not implemented for `u8` = help: the following other types implement trait `Sub`: + + > <&'a u8 as Sub> <&u8 as Sub<&u8>> - > - error[E0277]: cannot subtract `&str` from `f64` --> $DIR/not-suggest-float-literal.rs:19:7 @@ -58,10 +58,10 @@ LL | x - "foo" | = help: the trait `Sub<&str>` is not implemented for `f64` = help: the following other types implement trait `Sub`: + + > <&'a f64 as Sub> <&f64 as Sub<&f64>> - > - error[E0277]: cannot subtract `{integer}` from `f64` --> $DIR/not-suggest-float-literal.rs:24:7 @@ -71,10 +71,10 @@ LL | x - y | = help: the trait `Sub<{integer}>` is not implemented for `f64` = help: the following other types implement trait `Sub`: + + > <&'a f64 as Sub> <&f64 as Sub<&f64>> - > - error[E0277]: cannot multiply `u8` by `{float}` --> $DIR/not-suggest-float-literal.rs:28:7 @@ -84,10 +84,10 @@ LL | x * 100.0 | = help: the trait `Mul<{float}>` is not implemented for `u8` = help: the following other types implement trait `Mul`: + + > <&'a u8 as Mul> <&u8 as Mul<&u8>> - > - error[E0277]: cannot multiply `f64` by `&str` --> $DIR/not-suggest-float-literal.rs:32:7 @@ -97,10 +97,10 @@ LL | x * "foo" | = help: the trait `Mul<&str>` is not implemented for `f64` = help: the following other types implement trait `Mul`: + + > <&'a f64 as Mul> <&f64 as Mul<&f64>> - > - error[E0277]: cannot multiply `f64` by `{integer}` --> $DIR/not-suggest-float-literal.rs:37:7 @@ -110,10 +110,10 @@ LL | x * y | = help: the trait `Mul<{integer}>` is not implemented for `f64` = help: the following other types implement trait `Mul`: + + > <&'a f64 as Mul> <&f64 as Mul<&f64>> - > - error[E0277]: cannot divide `u8` by `{float}` --> $DIR/not-suggest-float-literal.rs:41:7 @@ -123,11 +123,11 @@ LL | x / 100.0 | = help: the trait `Div<{float}>` is not implemented for `u8` = help: the following other types implement trait `Div`: + + > + > <&'a u8 as Div> <&u8 as Div<&u8>> - > - > - error[E0277]: cannot divide `f64` by `&str` --> $DIR/not-suggest-float-literal.rs:45:7 @@ -137,10 +137,10 @@ LL | x / "foo" | = help: the trait `Div<&str>` is not implemented for `f64` = help: the following other types implement trait `Div`: + + > <&'a f64 as Div> <&f64 as Div<&f64>> - > - error[E0277]: cannot divide `f64` by `{integer}` --> $DIR/not-suggest-float-literal.rs:50:7 @@ -150,10 +150,10 @@ LL | x / y | = help: the trait `Div<{integer}>` is not implemented for `f64` = help: the following other types implement trait `Div`: + + > <&'a f64 as Div> <&f64 as Div<&f64>> - > - error: aborting due to 12 previous errors diff --git a/tests/ui/numbers-arithmetic/suggest-float-literal.stderr b/tests/ui/numbers-arithmetic/suggest-float-literal.stderr index 03779d356371a..929a9e3b5954d 100644 --- a/tests/ui/numbers-arithmetic/suggest-float-literal.stderr +++ b/tests/ui/numbers-arithmetic/suggest-float-literal.stderr @@ -6,10 +6,10 @@ LL | x + 100 | = help: the trait `Add<{integer}>` is not implemented for `f32` = help: the following other types implement trait `Add`: + + > <&'a f32 as Add> <&f32 as Add<&f32>> - > - help: consider using a floating-point literal by writing it with `.0` | LL | x + 100.0 @@ -23,10 +23,10 @@ LL | x + 100 | = help: the trait `Add<{integer}>` is not implemented for `f64` = help: the following other types implement trait `Add`: + + > <&'a f64 as Add> <&f64 as Add<&f64>> - > - help: consider using a floating-point literal by writing it with `.0` | LL | x + 100.0 @@ -40,10 +40,10 @@ LL | x - 100 | = help: the trait `Sub<{integer}>` is not implemented for `f32` = help: the following other types implement trait `Sub`: + + > <&'a f32 as Sub> <&f32 as Sub<&f32>> - > - help: consider using a floating-point literal by writing it with `.0` | LL | x - 100.0 @@ -57,10 +57,10 @@ LL | x - 100 | = help: the trait `Sub<{integer}>` is not implemented for `f64` = help: the following other types implement trait `Sub`: + + > <&'a f64 as Sub> <&f64 as Sub<&f64>> - > - help: consider using a floating-point literal by writing it with `.0` | LL | x - 100.0 @@ -74,10 +74,10 @@ LL | x * 100 | = help: the trait `Mul<{integer}>` is not implemented for `f32` = help: the following other types implement trait `Mul`: + + > <&'a f32 as Mul> <&f32 as Mul<&f32>> - > - help: consider using a floating-point literal by writing it with `.0` | LL | x * 100.0 @@ -91,10 +91,10 @@ LL | x * 100 | = help: the trait `Mul<{integer}>` is not implemented for `f64` = help: the following other types implement trait `Mul`: + + > <&'a f64 as Mul> <&f64 as Mul<&f64>> - > - help: consider using a floating-point literal by writing it with `.0` | LL | x * 100.0 @@ -108,10 +108,10 @@ LL | x / 100 | = help: the trait `Div<{integer}>` is not implemented for `f32` = help: the following other types implement trait `Div`: + + > <&'a f32 as Div> <&f32 as Div<&f32>> - > - help: consider using a floating-point literal by writing it with `.0` | LL | x / 100.0 @@ -125,10 +125,10 @@ LL | x / 100 | = help: the trait `Div<{integer}>` is not implemented for `f64` = help: the following other types implement trait `Div`: + + > <&'a f64 as Div> <&f64 as Div<&f64>> - > - help: consider using a floating-point literal by writing it with `.0` | LL | x / 100.0 diff --git a/tests/ui/object-safety/assoc_const_bounds.rs b/tests/ui/object-safety/assoc_const_bounds.rs index 94b1f63165ba2..1844a6f287430 100644 --- a/tests/ui/object-safety/assoc_const_bounds.rs +++ b/tests/ui/object-safety/assoc_const_bounds.rs @@ -1,7 +1,13 @@ +#![feature(generic_consts)] +#![allow(incomplete_features, dead_code)] + +// FIXME(generic_consts): Is this the expected behavior? CC #110590 +// check-pass + trait Foo { const BAR: bool - where //~ ERROR: expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `=`, found keyword `where` - Self: Sized; + where + Self: Sized; } trait Cake {} diff --git a/tests/ui/object-safety/assoc_const_bounds.stderr b/tests/ui/object-safety/assoc_const_bounds.stderr deleted file mode 100644 index 09bc11e178a45..0000000000000 --- a/tests/ui/object-safety/assoc_const_bounds.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error: expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `=`, found keyword `where` - --> $DIR/assoc_const_bounds.rs:3:9 - | -LL | trait Foo { - | - while parsing this item list starting here -LL | const BAR: bool - | - expected one of 7 possible tokens -LL | where - | ^^^^^ unexpected token -LL | Self: Sized; -LL | } - | - the item list ends here - -error: aborting due to previous error - diff --git a/tests/ui/object-safety/assoc_const_bounds_sized.rs b/tests/ui/object-safety/assoc_const_bounds_sized.rs index 2a76e5dce2b49..09c50ba92da09 100644 --- a/tests/ui/object-safety/assoc_const_bounds_sized.rs +++ b/tests/ui/object-safety/assoc_const_bounds_sized.rs @@ -1,7 +1,13 @@ +#![feature(generic_consts)] +#![allow(incomplete_features, dead_code)] + +// FIXME(generic_consts): Is this the expected behavior? CC #110590 +// check-pass + trait Foo { const BAR: bool - where //~ ERROR: expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `=`, found keyword `where` - Self: Sized; + where + Self: Sized; } fn foo(_: &dyn Foo) {} diff --git a/tests/ui/object-safety/assoc_const_bounds_sized.stderr b/tests/ui/object-safety/assoc_const_bounds_sized.stderr deleted file mode 100644 index e1f57f677956b..0000000000000 --- a/tests/ui/object-safety/assoc_const_bounds_sized.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error: expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `=`, found keyword `where` - --> $DIR/assoc_const_bounds_sized.rs:3:9 - | -LL | trait Foo { - | - while parsing this item list starting here -LL | const BAR: bool - | - expected one of 7 possible tokens -LL | where - | ^^^^^ unexpected token -LL | Self: Sized; -LL | } - | - the item list ends here - -error: aborting due to previous error - diff --git a/tests/ui/on-unimplemented/multiple-impls.stderr b/tests/ui/on-unimplemented/multiple-impls.stderr index d628b159a66d2..3d0e36db75215 100644 --- a/tests/ui/on-unimplemented/multiple-impls.stderr +++ b/tests/ui/on-unimplemented/multiple-impls.stderr @@ -8,8 +8,8 @@ LL | Index::index(&[] as &[i32], 2u32); | = help: the trait `Index` is not implemented for `[i32]` = help: the following other types implement trait `Index`: - <[i32] as Index>> <[i32] as Index>> + <[i32] as Index>> error[E0277]: the trait bound `[i32]: Index` is not satisfied --> $DIR/multiple-impls.rs:33:5 @@ -19,8 +19,8 @@ LL | Index::index(&[] as &[i32], 2u32); | = help: the trait `Index` is not implemented for `[i32]` = help: the following other types implement trait `Index`: - <[i32] as Index>> <[i32] as Index>> + <[i32] as Index>> error[E0277]: the trait bound `[i32]: Index>` is not satisfied --> $DIR/multiple-impls.rs:37:33 @@ -32,8 +32,8 @@ LL | Index::index(&[] as &[i32], Foo(2u32)); | = help: the trait `Index>` is not implemented for `[i32]` = help: the following other types implement trait `Index`: - <[i32] as Index>> <[i32] as Index>> + <[i32] as Index>> error[E0277]: the trait bound `[i32]: Index>` is not satisfied --> $DIR/multiple-impls.rs:37:5 @@ -43,8 +43,8 @@ LL | Index::index(&[] as &[i32], Foo(2u32)); | = help: the trait `Index>` is not implemented for `[i32]` = help: the following other types implement trait `Index`: - <[i32] as Index>> <[i32] as Index>> + <[i32] as Index>> error[E0277]: the trait bound `[i32]: Index>` is not satisfied --> $DIR/multiple-impls.rs:41:33 @@ -56,8 +56,8 @@ LL | Index::index(&[] as &[i32], Bar(2u32)); | = help: the trait `Index>` is not implemented for `[i32]` = help: the following other types implement trait `Index`: - <[i32] as Index>> <[i32] as Index>> + <[i32] as Index>> error[E0277]: the trait bound `[i32]: Index>` is not satisfied --> $DIR/multiple-impls.rs:41:5 @@ -67,8 +67,8 @@ LL | Index::index(&[] as &[i32], Bar(2u32)); | = help: the trait `Index>` is not implemented for `[i32]` = help: the following other types implement trait `Index`: - <[i32] as Index>> <[i32] as Index>> + <[i32] as Index>> error[E0277]: the trait bound `[i32]: Index` is not satisfied --> $DIR/multiple-impls.rs:33:5 @@ -78,8 +78,8 @@ LL | Index::index(&[] as &[i32], 2u32); | = help: the trait `Index` is not implemented for `[i32]` = help: the following other types implement trait `Index`: - <[i32] as Index>> <[i32] as Index>> + <[i32] as Index>> error[E0277]: the trait bound `[i32]: Index>` is not satisfied --> $DIR/multiple-impls.rs:37:5 @@ -89,8 +89,8 @@ LL | Index::index(&[] as &[i32], Foo(2u32)); | = help: the trait `Index>` is not implemented for `[i32]` = help: the following other types implement trait `Index`: - <[i32] as Index>> <[i32] as Index>> + <[i32] as Index>> error[E0277]: the trait bound `[i32]: Index>` is not satisfied --> $DIR/multiple-impls.rs:41:5 @@ -100,8 +100,8 @@ LL | Index::index(&[] as &[i32], Bar(2u32)); | = help: the trait `Index>` is not implemented for `[i32]` = help: the following other types implement trait `Index`: - <[i32] as Index>> <[i32] as Index>> + <[i32] as Index>> error: aborting due to 9 previous errors diff --git a/tests/ui/on-unimplemented/slice-index.stderr b/tests/ui/on-unimplemented/slice-index.stderr index a7ec3bda85eca..b9bca211f438b 100644 --- a/tests/ui/on-unimplemented/slice-index.stderr +++ b/tests/ui/on-unimplemented/slice-index.stderr @@ -16,8 +16,8 @@ LL | x[..1i32]; | = help: the trait `SliceIndex<[i32]>` is not implemented for `RangeTo` = help: the following other types implement trait `SliceIndex`: - as SliceIndex<[T]>> as SliceIndex> + as SliceIndex<[T]>> = note: required for `[i32]` to implement `Index>` error: aborting due to 2 previous errors diff --git a/tests/ui/on-unimplemented/sum.stderr b/tests/ui/on-unimplemented/sum.stderr index 2a316dba778fe..a2357e49b07e8 100644 --- a/tests/ui/on-unimplemented/sum.stderr +++ b/tests/ui/on-unimplemented/sum.stderr @@ -6,8 +6,8 @@ LL | vec![(), ()].iter().sum::(); | = help: the trait `Sum<&()>` is not implemented for `i32` = help: the following other types implement trait `Sum`: - > + > note: the method call chain might not have had the expected associated types --> $DIR/sum.rs:4:18 | @@ -26,8 +26,8 @@ LL | vec![(), ()].iter().product::(); | = help: the trait `Product<&()>` is not implemented for `i32` = help: the following other types implement trait `Product`: - > + > note: the method call chain might not have had the expected associated types --> $DIR/sum.rs:7:18 | diff --git a/tests/ui/parser/generic-statics.rs b/tests/ui/parser/generic-statics.rs new file mode 100644 index 0000000000000..75974571033ff --- /dev/null +++ b/tests/ui/parser/generic-statics.rs @@ -0,0 +1,15 @@ +static S: i32 = 0; +//~^ ERROR static items may not have generic parameters + +static T: () = () +where + Vec<()>: Clone; +//~^^ ERROR static items may not have a where clause + +static U: bool +where + (): Copy, += true; +//~^^^ ERROR static items may not have a where clause + +fn main() {} diff --git a/tests/ui/parser/generic-statics.stderr b/tests/ui/parser/generic-statics.stderr new file mode 100644 index 0000000000000..c44fceb6bd8fc --- /dev/null +++ b/tests/ui/parser/generic-statics.stderr @@ -0,0 +1,22 @@ +error: static items may not have generic parameters + --> $DIR/generic-statics.rs:1:9 + | +LL | static S: i32 = 0; + | ^^^ + +error: static items may not have a where clause + --> $DIR/generic-statics.rs:5:1 + | +LL | / where +LL | | Vec<()>: Clone; + | |__________________^ + +error: static items may not have a where clause + --> $DIR/generic-statics.rs:10:1 + | +LL | / where +LL | | (): Copy, + | |_____________^ + +error: aborting due to 3 previous errors + diff --git a/tests/ui/parser/removed-syntax-static-fn.rs b/tests/ui/parser/removed-syntax-static-fn.rs index cd643b874dbda..ddd2c032e4d54 100644 --- a/tests/ui/parser/removed-syntax-static-fn.rs +++ b/tests/ui/parser/removed-syntax-static-fn.rs @@ -3,8 +3,9 @@ struct S; impl S { static fn f() {} //~^ ERROR expected identifier, found keyword `fn` - //~| ERROR expected one of `:`, `;`, or `=` + //~| ERROR expected one of `:`, `;`, `<`, `=`, or `where` //~| ERROR missing type for `static` item + // FIXME(generic_consts): `<` and `where` now being in the list of expected tokens isn't great. } fn main() {} diff --git a/tests/ui/parser/removed-syntax-static-fn.stderr b/tests/ui/parser/removed-syntax-static-fn.stderr index 52e0658949d3d..2a97fc647cd9b 100644 --- a/tests/ui/parser/removed-syntax-static-fn.stderr +++ b/tests/ui/parser/removed-syntax-static-fn.stderr @@ -4,13 +4,13 @@ error: expected identifier, found keyword `fn` LL | static fn f() {} | ^^ expected identifier, found keyword -error: expected one of `:`, `;`, or `=`, found `f` +error: expected one of `:`, `;`, `<`, `=`, or `where`, found `f` --> $DIR/removed-syntax-static-fn.rs:4:15 | LL | impl S { | - while parsing this item list starting here LL | static fn f() {} - | ^ expected one of `:`, `;`, or `=` + | ^ expected one of `:`, `;`, `<`, `=`, or `where` ... LL | } | - the item list ends here diff --git a/tests/ui/pattern/issue-110508.rs b/tests/ui/pattern/issue-110508.rs new file mode 100644 index 0000000000000..1024ff05578ef --- /dev/null +++ b/tests/ui/pattern/issue-110508.rs @@ -0,0 +1,38 @@ +// run-pass + +#[derive(PartialEq, Eq)] +pub enum Foo { + FooA(()), + FooB(Vec<()>), +} + +impl Foo { + const A1: Foo = Foo::FooA(()); + const A2: Foo = Self::FooA(()); + const A3: Self = Foo::FooA(()); + const A4: Self = Self::FooA(()); +} + +fn main() { + let foo = Foo::FooA(()); + + match foo { + Foo::A1 => {}, + _ => {}, + } + + match foo { + Foo::A2 => {}, + _ => {}, + } + + match foo { + Foo::A3 => {}, + _ => {}, + } + + match foo { + Foo::A4 => {}, + _ => {}, + } +} diff --git a/tests/ui/range/range-1.stderr b/tests/ui/range/range-1.stderr index 3956390368f7f..277d9b2682d8b 100644 --- a/tests/ui/range/range-1.stderr +++ b/tests/ui/range/range-1.stderr @@ -12,13 +12,13 @@ LL | for i in false..true {} | = help: the following other types implement trait `Step`: char - i128 + isize + i8 i16 i32 i64 - i8 - isize - u128 + i128 + usize and 5 others = note: required for `std::ops::Range` to implement `Iterator` = note: required for `std::ops::Range` to implement `IntoIterator` diff --git a/tests/ui/recursion/issue-95134.rs b/tests/ui/recursion/issue-95134.rs index 2f1cffa2fa907..7ee31d85c2b12 100644 --- a/tests/ui/recursion/issue-95134.rs +++ b/tests/ui/recursion/issue-95134.rs @@ -3,6 +3,7 @@ // compile-flags: -Copt-level=0 // dont-check-failure-status // dont-check-compiler-stderr +// ignore-compare-mode-next-solver (hangs) pub fn encode_num(n: u32, mut writer: Writer) -> Result<(), Writer::Error> { if n > 15 { diff --git a/tests/ui/resolve/issue-2356.stderr b/tests/ui/resolve/issue-2356.stderr index 313b3e30dd956..30f5f05952664 100644 --- a/tests/ui/resolve/issue-2356.stderr +++ b/tests/ui/resolve/issue-2356.stderr @@ -1,18 +1,3 @@ -error[E0425]: cannot find function `default` in this scope - --> $DIR/issue-2356.rs:31:5 - | -LL | default(); - | ^^^^^^^ - | -help: you might have meant to call the associated function - | -LL | Self::default(); - | ~~~~~~~~~~~~~ -help: consider importing this function - | -LL + use std::default::default; - | - error[E0425]: cannot find value `whiskers` in this scope --> $DIR/issue-2356.rs:39:5 | @@ -64,6 +49,12 @@ error[E0425]: cannot find function `clone` in this scope LL | clone(); | ^^^^^ help: you might have meant to call the method: `self.clone` +error[E0425]: cannot find function `default` in this scope + --> $DIR/issue-2356.rs:31:5 + | +LL | default(); + | ^^^^^^^ help: you might have meant to call the associated function: `Self::default` + error[E0425]: cannot find function `shave` in this scope --> $DIR/issue-2356.rs:41:5 | diff --git a/tests/ui/span/multiline-span-simple.stderr b/tests/ui/span/multiline-span-simple.stderr index b44df962a9ba7..b6052a209bf50 100644 --- a/tests/ui/span/multiline-span-simple.stderr +++ b/tests/ui/span/multiline-span-simple.stderr @@ -6,10 +6,10 @@ LL | foo(1 as u32 + | = help: the trait `Add<()>` is not implemented for `u32` = help: the following other types implement trait `Add`: + + > <&'a u32 as Add> <&u32 as Add<&u32>> - > - error: aborting due to previous error diff --git a/tests/ui/suggestions/impl-trait-return-trailing-semicolon.stderr b/tests/ui/suggestions/impl-trait-return-trailing-semicolon.stderr index e74c2c4214fe2..6465eeb8bc62d 100644 --- a/tests/ui/suggestions/impl-trait-return-trailing-semicolon.stderr +++ b/tests/ui/suggestions/impl-trait-return-trailing-semicolon.stderr @@ -16,8 +16,8 @@ LL | fn bar() -> impl Bar { | ^^^^^^^^ the trait `Bar` is not implemented for `()` | = help: the following other types implement trait `Bar`: - Qux i32 + Qux error: aborting due to 2 previous errors diff --git a/tests/ui/suggestions/into-str.stderr b/tests/ui/suggestions/into-str.stderr index a56a2a188cb3f..7e24150e7f447 100644 --- a/tests/ui/suggestions/into-str.stderr +++ b/tests/ui/suggestions/into-str.stderr @@ -8,12 +8,12 @@ LL | foo(String::new()); | = note: to coerce a `String` into a `&str`, use `&*` as a prefix = help: the following other types implement trait `From`: - > - > - > + > >> >> - > + > + > + > = note: required for `String` to implement `Into<&str>` note: required by a bound in `foo` --> $DIR/into-str.rs:1:31 diff --git a/tests/ui/suggestions/issue-71394-no-from-impl.stderr b/tests/ui/suggestions/issue-71394-no-from-impl.stderr index ea57992b48326..004f1c1622b6f 100644 --- a/tests/ui/suggestions/issue-71394-no-from-impl.stderr +++ b/tests/ui/suggestions/issue-71394-no-from-impl.stderr @@ -5,14 +5,14 @@ LL | let _: &[i8] = data.into(); | ^^^^ the trait `From<&[u8]>` is not implemented for `&[i8]` | = help: the following other types implement trait `From`: - <&'input [u8] as From>> - <[T; 10] as From<(T, T, T, T, T, T, T, T, T, T)>> - <[T; 11] as From<(T, T, T, T, T, T, T, T, T, T, T)>> - <[T; 12] as From<(T, T, T, T, T, T, T, T, T, T, T, T)>> + <[bool; LANES] as From>> + <[T; N] as From>> <[T; 1] as From<(T,)>> <[T; 2] as From<(T, T)>> <[T; 3] as From<(T, T, T)>> <[T; 4] as From<(T, T, T, T)>> + <[T; 5] as From<(T, T, T, T, T)>> + <[T; 6] as From<(T, T, T, T, T, T)>> and 7 others = note: required for `&[u8]` to implement `Into<&[i8]>` diff --git a/tests/ui/suggestions/missing-lifetime-in-assoc-const-type.rs b/tests/ui/suggestions/missing-lifetime-in-assoc-const-type.rs index 38332627f4c87..10da5d5322aae 100644 --- a/tests/ui/suggestions/missing-lifetime-in-assoc-const-type.rs +++ b/tests/ui/suggestions/missing-lifetime-in-assoc-const-type.rs @@ -3,6 +3,8 @@ trait ZstAssert: Sized { const B: S = S { s: &() }; //~ ERROR missing lifetime specifier const C: &'_ str = ""; //~ ERROR missing lifetime specifier const D: T = T { a: &(), b: &() }; //~ ERROR missing lifetime specifier + // FIXME(generic_consts): We should only suggest adding lifetime parameters to assoc consts if + // the feature `generic_consts` is enabled. If it isn't, suggest adding it to the trait. } struct S<'a> { diff --git a/tests/ui/suggestions/missing-lifetime-in-assoc-const-type.stderr b/tests/ui/suggestions/missing-lifetime-in-assoc-const-type.stderr index 233f1bc5a86ee..7ddabbf6b4612 100644 --- a/tests/ui/suggestions/missing-lifetime-in-assoc-const-type.stderr +++ b/tests/ui/suggestions/missing-lifetime-in-assoc-const-type.stderr @@ -6,9 +6,8 @@ LL | const A: &str = ""; | help: consider introducing a named lifetime parameter | -LL ~ trait ZstAssert<'a>: Sized { -LL ~ const A: &'a str = ""; - | +LL | const A<'a>: &'a str = ""; + | ++++ ++ error[E0106]: missing lifetime specifier --> $DIR/missing-lifetime-in-assoc-const-type.rs:3:14 @@ -18,10 +17,8 @@ LL | const B: S = S { s: &() }; | help: consider introducing a named lifetime parameter | -LL ~ trait ZstAssert<'a>: Sized { -LL | const A: &str = ""; -LL ~ const B: S<'a> = S { s: &() }; - | +LL | const B<'a>: S<'a> = S { s: &() }; + | ++++ ++++ error[E0106]: missing lifetime specifier --> $DIR/missing-lifetime-in-assoc-const-type.rs:4:15 @@ -31,11 +28,8 @@ LL | const C: &'_ str = ""; | help: consider introducing a named lifetime parameter | -LL ~ trait ZstAssert<'a>: Sized { -LL | const A: &str = ""; -LL | const B: S = S { s: &() }; -LL ~ const C: &'a str = ""; - | +LL | const C<'a>: &'a str = ""; + | ++++ ~~ error[E0106]: missing lifetime specifiers --> $DIR/missing-lifetime-in-assoc-const-type.rs:5:14 @@ -45,12 +39,8 @@ LL | const D: T = T { a: &(), b: &() }; | help: consider introducing a named lifetime parameter | -LL ~ trait ZstAssert<'a>: Sized { -LL | const A: &str = ""; -LL | const B: S = S { s: &() }; -LL | const C: &'_ str = ""; -LL ~ const D: T<'a, 'a> = T { a: &(), b: &() }; - | +LL | const D<'a>: T<'a, 'a> = T { a: &(), b: &() }; + | ++++ ++++++++ error: aborting due to 4 previous errors diff --git a/tests/ui/thir-print/thir-flat-const-variant.rs b/tests/ui/thir-print/thir-flat-const-variant.rs new file mode 100644 index 0000000000000..2cd87a5cbb2af --- /dev/null +++ b/tests/ui/thir-print/thir-flat-const-variant.rs @@ -0,0 +1,18 @@ +// compile-flags: -Z unpretty=thir-flat +// check-pass + +// Previously, the constants with `Self::Bar(())` would be `Call`s instead of +// `Adt`s in THIR. + +pub enum Foo { + Bar(()), +} + +impl Foo { + const BAR1: Foo = Foo::Bar(()); + const BAR2: Foo = Self::Bar(()); + const BAR3: Self = Foo::Bar(()); + const BAR4: Self = Self::Bar(()); +} + +fn main() {} diff --git a/tests/ui/thir-print/thir-flat-const-variant.stdout b/tests/ui/thir-print/thir-flat-const-variant.stdout new file mode 100644 index 0000000000000..1b76f07c31889 --- /dev/null +++ b/tests/ui/thir-print/thir-flat-const-variant.stdout @@ -0,0 +1,399 @@ +DefId(0:8 ~ thir_flat_const_variant[1f54]::{impl#0}::BAR1): +Thir { + body_type: Const( + Foo, + ), + arms: [], + blocks: [], + exprs: [ + Expr { + kind: Tuple { + fields: [], + }, + ty: (), + temp_lifetime: Some( + Node(3), + ), + span: $DIR/thir-flat-const-variant.rs:12:32: 12:34 (#0), + }, + Expr { + kind: Scope { + region_scope: Node(7), + lint_level: Explicit( + HirId(DefId(0:8 ~ thir_flat_const_variant[1f54]::{impl#0}::BAR1).7), + ), + value: e0, + }, + ty: (), + temp_lifetime: Some( + Node(3), + ), + span: $DIR/thir-flat-const-variant.rs:12:32: 12:34 (#0), + }, + Expr { + kind: Adt( + AdtExpr { + adt_def: Foo, + variant_index: 0, + substs: [], + user_ty: None, + fields: [ + FieldExpr { + name: 0, + expr: e1, + }, + ], + base: None, + }, + ), + ty: Foo, + temp_lifetime: Some( + Node(3), + ), + span: $DIR/thir-flat-const-variant.rs:12:23: 12:35 (#0), + }, + Expr { + kind: Scope { + region_scope: Node(3), + lint_level: Explicit( + HirId(DefId(0:8 ~ thir_flat_const_variant[1f54]::{impl#0}::BAR1).3), + ), + value: e2, + }, + ty: Foo, + temp_lifetime: Some( + Node(3), + ), + span: $DIR/thir-flat-const-variant.rs:12:23: 12:35 (#0), + }, + Expr { + kind: Scope { + region_scope: Destruction(3), + lint_level: Inherited, + value: e3, + }, + ty: Foo, + temp_lifetime: Some( + Node(3), + ), + span: $DIR/thir-flat-const-variant.rs:12:23: 12:35 (#0), + }, + ], + stmts: [], + params: [], +} + +DefId(0:9 ~ thir_flat_const_variant[1f54]::{impl#0}::BAR2): +Thir { + body_type: Const( + Foo, + ), + arms: [], + blocks: [], + exprs: [ + Expr { + kind: Tuple { + fields: [], + }, + ty: (), + temp_lifetime: Some( + Node(3), + ), + span: $DIR/thir-flat-const-variant.rs:13:33: 13:35 (#0), + }, + Expr { + kind: Scope { + region_scope: Node(8), + lint_level: Explicit( + HirId(DefId(0:9 ~ thir_flat_const_variant[1f54]::{impl#0}::BAR2).8), + ), + value: e0, + }, + ty: (), + temp_lifetime: Some( + Node(3), + ), + span: $DIR/thir-flat-const-variant.rs:13:33: 13:35 (#0), + }, + Expr { + kind: Adt( + AdtExpr { + adt_def: Foo, + variant_index: 0, + substs: [], + user_ty: None, + fields: [ + FieldExpr { + name: 0, + expr: e1, + }, + ], + base: None, + }, + ), + ty: Foo, + temp_lifetime: Some( + Node(3), + ), + span: $DIR/thir-flat-const-variant.rs:13:23: 13:36 (#0), + }, + Expr { + kind: Scope { + region_scope: Node(3), + lint_level: Explicit( + HirId(DefId(0:9 ~ thir_flat_const_variant[1f54]::{impl#0}::BAR2).3), + ), + value: e2, + }, + ty: Foo, + temp_lifetime: Some( + Node(3), + ), + span: $DIR/thir-flat-const-variant.rs:13:23: 13:36 (#0), + }, + Expr { + kind: Scope { + region_scope: Destruction(3), + lint_level: Inherited, + value: e3, + }, + ty: Foo, + temp_lifetime: Some( + Node(3), + ), + span: $DIR/thir-flat-const-variant.rs:13:23: 13:36 (#0), + }, + ], + stmts: [], + params: [], +} + +DefId(0:10 ~ thir_flat_const_variant[1f54]::{impl#0}::BAR3): +Thir { + body_type: Const( + Foo, + ), + arms: [], + blocks: [], + exprs: [ + Expr { + kind: Tuple { + fields: [], + }, + ty: (), + temp_lifetime: Some( + Node(3), + ), + span: $DIR/thir-flat-const-variant.rs:14:33: 14:35 (#0), + }, + Expr { + kind: Scope { + region_scope: Node(7), + lint_level: Explicit( + HirId(DefId(0:10 ~ thir_flat_const_variant[1f54]::{impl#0}::BAR3).7), + ), + value: e0, + }, + ty: (), + temp_lifetime: Some( + Node(3), + ), + span: $DIR/thir-flat-const-variant.rs:14:33: 14:35 (#0), + }, + Expr { + kind: Adt( + AdtExpr { + adt_def: Foo, + variant_index: 0, + substs: [], + user_ty: None, + fields: [ + FieldExpr { + name: 0, + expr: e1, + }, + ], + base: None, + }, + ), + ty: Foo, + temp_lifetime: Some( + Node(3), + ), + span: $DIR/thir-flat-const-variant.rs:14:24: 14:36 (#0), + }, + Expr { + kind: Scope { + region_scope: Node(3), + lint_level: Explicit( + HirId(DefId(0:10 ~ thir_flat_const_variant[1f54]::{impl#0}::BAR3).3), + ), + value: e2, + }, + ty: Foo, + temp_lifetime: Some( + Node(3), + ), + span: $DIR/thir-flat-const-variant.rs:14:24: 14:36 (#0), + }, + Expr { + kind: Scope { + region_scope: Destruction(3), + lint_level: Inherited, + value: e3, + }, + ty: Foo, + temp_lifetime: Some( + Node(3), + ), + span: $DIR/thir-flat-const-variant.rs:14:24: 14:36 (#0), + }, + ], + stmts: [], + params: [], +} + +DefId(0:11 ~ thir_flat_const_variant[1f54]::{impl#0}::BAR4): +Thir { + body_type: Const( + Foo, + ), + arms: [], + blocks: [], + exprs: [ + Expr { + kind: Tuple { + fields: [], + }, + ty: (), + temp_lifetime: Some( + Node(3), + ), + span: $DIR/thir-flat-const-variant.rs:15:34: 15:36 (#0), + }, + Expr { + kind: Scope { + region_scope: Node(8), + lint_level: Explicit( + HirId(DefId(0:11 ~ thir_flat_const_variant[1f54]::{impl#0}::BAR4).8), + ), + value: e0, + }, + ty: (), + temp_lifetime: Some( + Node(3), + ), + span: $DIR/thir-flat-const-variant.rs:15:34: 15:36 (#0), + }, + Expr { + kind: Adt( + AdtExpr { + adt_def: Foo, + variant_index: 0, + substs: [], + user_ty: None, + fields: [ + FieldExpr { + name: 0, + expr: e1, + }, + ], + base: None, + }, + ), + ty: Foo, + temp_lifetime: Some( + Node(3), + ), + span: $DIR/thir-flat-const-variant.rs:15:24: 15:37 (#0), + }, + Expr { + kind: Scope { + region_scope: Node(3), + lint_level: Explicit( + HirId(DefId(0:11 ~ thir_flat_const_variant[1f54]::{impl#0}::BAR4).3), + ), + value: e2, + }, + ty: Foo, + temp_lifetime: Some( + Node(3), + ), + span: $DIR/thir-flat-const-variant.rs:15:24: 15:37 (#0), + }, + Expr { + kind: Scope { + region_scope: Destruction(3), + lint_level: Inherited, + value: e3, + }, + ty: Foo, + temp_lifetime: Some( + Node(3), + ), + span: $DIR/thir-flat-const-variant.rs:15:24: 15:37 (#0), + }, + ], + stmts: [], + params: [], +} + +DefId(0:12 ~ thir_flat_const_variant[1f54]::main): +Thir { + body_type: Fn( + fn(), + ), + arms: [], + blocks: [ + Block { + targeted_by_break: false, + region_scope: Node(1), + opt_destruction_scope: None, + span: $DIR/thir-flat-const-variant.rs:18:11: 18:13 (#0), + stmts: [], + expr: None, + safety_mode: Safe, + }, + ], + exprs: [ + Expr { + kind: Block { + block: b0, + }, + ty: (), + temp_lifetime: Some( + Node(2), + ), + span: $DIR/thir-flat-const-variant.rs:18:11: 18:13 (#0), + }, + Expr { + kind: Scope { + region_scope: Node(2), + lint_level: Explicit( + HirId(DefId(0:12 ~ thir_flat_const_variant[1f54]::main).2), + ), + value: e0, + }, + ty: (), + temp_lifetime: Some( + Node(2), + ), + span: $DIR/thir-flat-const-variant.rs:18:11: 18:13 (#0), + }, + Expr { + kind: Scope { + region_scope: Destruction(2), + lint_level: Inherited, + value: e1, + }, + ty: (), + temp_lifetime: Some( + Node(2), + ), + span: $DIR/thir-flat-const-variant.rs:18:11: 18:13 (#0), + }, + ], + stmts: [], + params: [], +} + diff --git a/tests/ui/traits/bound/assoc-fn-bound-root-obligation.stderr b/tests/ui/traits/bound/assoc-fn-bound-root-obligation.stderr index ce9ab2d811ae1..b1c683e4729ea 100644 --- a/tests/ui/traits/bound/assoc-fn-bound-root-obligation.stderr +++ b/tests/ui/traits/bound/assoc-fn-bound-root-obligation.stderr @@ -6,13 +6,13 @@ LL | s.strip_suffix(b'\n').unwrap_or(s) | = help: the trait `FnMut<(char,)>` is not implemented for `u8` = help: the following other types implement trait `Pattern<'a>`: + char + [char; N] &'b String &'b [char; N] &'b [char] - &'b str &'c &'b str - [char; N] - char + &'b str = note: required for `u8` to implement `Pattern<'_>` error: aborting due to previous error diff --git a/tests/ui/traits/new-solver/dont-remap-tait-substs.rs b/tests/ui/traits/new-solver/dont-remap-tait-substs.rs index 028222f4e6dba..309bee8aa8c2c 100644 --- a/tests/ui/traits/new-solver/dont-remap-tait-substs.rs +++ b/tests/ui/traits/new-solver/dont-remap-tait-substs.rs @@ -12,7 +12,7 @@ type Foo = impl NeedsSend; trait NeedsSend {} impl NeedsSend for T {} -fn define(a: A, b: B) { +fn define(a: A, b: B, _: Foo) { let y: Option> = Some(b); } diff --git a/tests/ui/traits/new-solver/dont-type_of-tait-in-defining-scope.rs b/tests/ui/traits/new-solver/dont-type_of-tait-in-defining-scope.rs index 5a0dcd0e8ccea..08f14d7494d79 100644 --- a/tests/ui/traits/new-solver/dont-type_of-tait-in-defining-scope.rs +++ b/tests/ui/traits/new-solver/dont-type_of-tait-in-defining-scope.rs @@ -12,11 +12,13 @@ type Foo = impl Sized; fn needs_send() {} -fn test() { +fn test(_: Foo) { needs_send::(); //[not_send]~^ ERROR type annotations needed: cannot satisfy `Foo: Send` } -fn main() { +fn defines(_: Foo) { let _: Foo = (); } + +fn main() {} diff --git a/tests/ui/traits/new-solver/slice-match-byte-lit.rs b/tests/ui/traits/new-solver/slice-match-byte-lit.rs index 5f9c0df645036..4f848062595da 100644 --- a/tests/ui/traits/new-solver/slice-match-byte-lit.rs +++ b/tests/ui/traits/new-solver/slice-match-byte-lit.rs @@ -1,5 +1,5 @@ // compile-flags: -Ztrait-solver=next -// known-bug: rust-lang/trait-system-refactor-initiative#38 +// check-pass fn test(s: &[u8]) { match &s[0..3] { diff --git a/tests/ui/traits/new-solver/slice-match-byte-lit.stderr b/tests/ui/traits/new-solver/slice-match-byte-lit.stderr deleted file mode 100644 index cd48a6d184339..0000000000000 --- a/tests/ui/traits/new-solver/slice-match-byte-lit.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0271]: type mismatch resolving `[u8; 3] <: <[u8] as Index>>::Output` - --> $DIR/slice-match-byte-lit.rs:6:9 - | -LL | match &s[0..3] { - | -------- this expression has type `&<[u8] as Index>>::Output` -LL | b"uwu" => {} - | ^^^^^^ types differ - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0271`. diff --git a/tests/ui/traits/new-solver/tait-eq-proj-2.rs b/tests/ui/traits/new-solver/tait-eq-proj-2.rs index 99a3d02bd1aea..77ea8bc246e64 100644 --- a/tests/ui/traits/new-solver/tait-eq-proj-2.rs +++ b/tests/ui/traits/new-solver/tait-eq-proj-2.rs @@ -8,9 +8,11 @@ type Tait = impl Iterator; -fn mk() -> T { todo!() } +fn mk() -> T { + todo!() +} -fn a() { +fn a(_: Tait) { let x: Tait = mk(); let mut array = mk(); let mut z = IntoIterator::into_iter(array); diff --git a/tests/ui/traits/new-solver/tait-eq-proj.rs b/tests/ui/traits/new-solver/tait-eq-proj.rs index 01141b2819a8d..01ef2ec953aeb 100644 --- a/tests/ui/traits/new-solver/tait-eq-proj.rs +++ b/tests/ui/traits/new-solver/tait-eq-proj.rs @@ -28,7 +28,7 @@ goals together. Essentially: */ -fn a() { +fn a(_: Tait) { let _: Tait = IntoIterator::into_iter([0i32; 32]); } diff --git a/tests/ui/traits/new-solver/tait-eq-tait.rs b/tests/ui/traits/new-solver/tait-eq-tait.rs index 532c4c39bd499..70d9dc0eaa8ae 100644 --- a/tests/ui/traits/new-solver/tait-eq-tait.rs +++ b/tests/ui/traits/new-solver/tait-eq-tait.rs @@ -6,12 +6,13 @@ #![feature(type_alias_impl_trait)] -type Tait = impl Sized; -type Tait2 = impl Sized; - -fn mk() -> T { todo!() } +fn mk() -> T { + todo!() +} fn main() { + type Tait = impl Sized; + type Tait2 = impl Sized; let x: Tait = 1u32; let y: Tait2 = x; } diff --git a/tests/ui/try-trait/bad-interconversion.stderr b/tests/ui/try-trait/bad-interconversion.stderr index a49630adb9538..7eb392faa66b3 100644 --- a/tests/ui/try-trait/bad-interconversion.stderr +++ b/tests/ui/try-trait/bad-interconversion.stderr @@ -8,8 +8,8 @@ LL | Ok(Err(123_i32)?) | = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait = help: the following other types implement trait `From`: - > > + > = note: required for `Result` to implement `FromResidual>` error[E0277]: the `?` operator can only be used on `Result`s, not `Option`s, in a function that returns `Result` @@ -22,8 +22,8 @@ LL | Some(3)?; | = help: the trait `FromResidual>` is not implemented for `Result` = help: the following other types implement trait `FromResidual`: - as FromResidual>> as FromResidual>> + as FromResidual>> error[E0277]: the `?` operator can only be used on `Result`s in a function that returns `Result` --> $DIR/bad-interconversion.rs:17:31 @@ -35,8 +35,8 @@ LL | Ok(ControlFlow::Break(123)?) | = help: the trait `FromResidual>` is not implemented for `Result` = help: the following other types implement trait `FromResidual`: - as FromResidual>> as FromResidual>> + as FromResidual>> error[E0277]: the `?` operator can only be used on `Option`s, not `Result`s, in a function that returns `Option` --> $DIR/bad-interconversion.rs:22:22 diff --git a/tests/ui/try-trait/option-to-result.stderr b/tests/ui/try-trait/option-to-result.stderr index fabc1ff2c762e..1c4d718f1eeb4 100644 --- a/tests/ui/try-trait/option-to-result.stderr +++ b/tests/ui/try-trait/option-to-result.stderr @@ -9,8 +9,8 @@ LL | a?; | = help: the trait `FromResidual>` is not implemented for `Result<(), ()>` = help: the following other types implement trait `FromResidual`: - as FromResidual>> as FromResidual>> + as FromResidual>> error[E0277]: the `?` operator can only be used on `Option`s, not `Result`s, in a function that returns `Option` --> $DIR/option-to-result.rs:11:6 diff --git a/tests/ui/try-trait/try-on-option.stderr b/tests/ui/try-trait/try-on-option.stderr index fad6a1fe8237b..eeb0439df298c 100644 --- a/tests/ui/try-trait/try-on-option.stderr +++ b/tests/ui/try-trait/try-on-option.stderr @@ -9,8 +9,8 @@ LL | x?; | = help: the trait `FromResidual>` is not implemented for `Result` = help: the following other types implement trait `FromResidual`: - as FromResidual>> as FromResidual>> + as FromResidual>> error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`) --> $DIR/try-on-option.rs:11:6 diff --git a/tests/ui/type-alias-impl-trait/bound_reduction2.rs b/tests/ui/type-alias-impl-trait/bound_reduction2.rs index 0bcc9e002ca04..4e9f65d88a129 100644 --- a/tests/ui/type-alias-impl-trait/bound_reduction2.rs +++ b/tests/ui/type-alias-impl-trait/bound_reduction2.rs @@ -13,6 +13,7 @@ trait Trait {} impl Trait for () {} fn foo_desugared(_: T) -> Foo { + //~^ ERROR non-defining opaque type use () //~^ ERROR expected generic type parameter, found `::Assoc` } diff --git a/tests/ui/type-alias-impl-trait/bound_reduction2.stderr b/tests/ui/type-alias-impl-trait/bound_reduction2.stderr index 3c259bd9e97cc..14f9dbbdb4e93 100644 --- a/tests/ui/type-alias-impl-trait/bound_reduction2.stderr +++ b/tests/ui/type-alias-impl-trait/bound_reduction2.stderr @@ -1,5 +1,17 @@ +error[E0792]: non-defining opaque type use in defining scope + --> $DIR/bound_reduction2.rs:15:46 + | +LL | fn foo_desugared(_: T) -> Foo { + | ^^^^^^^^^^^^^ argument `::Assoc` is not a generic parameter + | +note: for this opaque type + --> $DIR/bound_reduction2.rs:9:15 + | +LL | type Foo = impl Trait; + | ^^^^^^^^^^^^^ + error[E0792]: expected generic type parameter, found `::Assoc` - --> $DIR/bound_reduction2.rs:16:5 + --> $DIR/bound_reduction2.rs:17:5 | LL | type Foo = impl Trait; | - this generic parameter must be used with a generic type parameter @@ -7,6 +19,6 @@ LL | type Foo = impl Trait; LL | () | ^^ -error: aborting due to previous error +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0792`. diff --git a/tests/ui/type-alias-impl-trait/closure_args.rs b/tests/ui/type-alias-impl-trait/closure_args.rs index c5e7af81d3dd0..243f9cd6d4f4c 100644 --- a/tests/ui/type-alias-impl-trait/closure_args.rs +++ b/tests/ui/type-alias-impl-trait/closure_args.rs @@ -11,6 +11,13 @@ fn run ()>(f: F, i: Input) { f(i); } -fn main() { - run(|x: u32| {println!("{x}");}, 0); +fn bop(_: Input) { + run( + |x: u32| { + println!("{x}"); + }, + 0, + ); } + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/closure_args2.rs b/tests/ui/type-alias-impl-trait/closure_args2.rs index 82386c280a8e3..1dd5c3e40cda6 100644 --- a/tests/ui/type-alias-impl-trait/closure_args2.rs +++ b/tests/ui/type-alias-impl-trait/closure_args2.rs @@ -1,10 +1,12 @@ -// run-pass +// check-pass #![feature(type_alias_impl_trait)] trait Foo { // This was reachable in https://github.com/rust-lang/rust/issues/100800 - fn foo(&self) { unreachable!() } + fn foo(&self) { + unreachable!() + } } impl Foo for T {} @@ -14,10 +16,17 @@ impl B { } type Input = impl Foo; -fn run1(f: F, i: Input) {f(i)} -fn run2(f: F, i: B) {f(i)} +fn run1(f: F, i: Input) { + f(i) +} +fn run2(f: F, i: B) { + f(i) +} -fn main() { - run1(|x: B| {x.foo()}, B); - run2(|x: B| {x.foo()}, B); +fn bop() -> Input { + run1(|x: B| x.foo(), B); + run2(|x: B| x.foo(), B); + panic!() } + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/declared_but_not_defined_in_scope.stderr b/tests/ui/type-alias-impl-trait/declared_but_not_defined_in_scope.stderr index fbfa0ccf1e8d9..d60f1ffbccc2d 100644 --- a/tests/ui/type-alias-impl-trait/declared_but_not_defined_in_scope.stderr +++ b/tests/ui/type-alias-impl-trait/declared_but_not_defined_in_scope.stderr @@ -19,6 +19,11 @@ LL | "" | = note: expected opaque type `Boo` found reference `&'static str` +note: this item must have the opaque type in its signature in order to be able to register hidden types + --> $DIR/declared_but_not_defined_in_scope.rs:10:4 + | +LL | fn bomp() -> boo::Boo { + | ^^^^ error: aborting due to 2 previous errors diff --git a/tests/ui/type-alias-impl-trait/different_defining_uses_never_type-2.rs b/tests/ui/type-alias-impl-trait/different_defining_uses_never_type-2.rs index e5bfbfdae91fd..b2842df150a3f 100644 --- a/tests/ui/type-alias-impl-trait/different_defining_uses_never_type-2.rs +++ b/tests/ui/type-alias-impl-trait/different_defining_uses_never_type-2.rs @@ -2,7 +2,7 @@ type Tait<'a> = impl Sized + 'a; -fn foo<'a, 'b>() { +fn foo<'a, 'b>() -> Tait<'a> { if false { if { return } { let y: Tait<'b> = 1i32; @@ -10,6 +10,7 @@ fn foo<'a, 'b>() { } } let x: Tait<'a> = (); + x } fn main() {} diff --git a/tests/ui/type-alias-impl-trait/different_defining_uses_never_type-2.stderr b/tests/ui/type-alias-impl-trait/different_defining_uses_never_type-2.stderr index f2eb7bc4dc79b..b138f9d5c45ab 100644 --- a/tests/ui/type-alias-impl-trait/different_defining_uses_never_type-2.stderr +++ b/tests/ui/type-alias-impl-trait/different_defining_uses_never_type-2.stderr @@ -5,10 +5,10 @@ LL | let y: Tait<'b> = 1i32; | ^^^^ expected `()`, got `i32` | note: previous use here - --> $DIR/different_defining_uses_never_type-2.rs:12:23 + --> $DIR/different_defining_uses_never_type-2.rs:7:14 | -LL | let x: Tait<'a> = (); - | ^^ +LL | if { return } { + | ^^^^^^ error: aborting due to previous error diff --git a/tests/ui/type-alias-impl-trait/different_defining_uses_never_type-3.rs b/tests/ui/type-alias-impl-trait/different_defining_uses_never_type-3.rs index 2b30a9cd57cf6..a4ac27378e1d8 100644 --- a/tests/ui/type-alias-impl-trait/different_defining_uses_never_type-3.rs +++ b/tests/ui/type-alias-impl-trait/different_defining_uses_never_type-3.rs @@ -2,7 +2,7 @@ type Tait = impl Sized; -fn foo() { +fn foo() -> Tait { if false { if { return } { let y: Tait = 1i32; @@ -10,6 +10,7 @@ fn foo() { } } let x: Tait = (); + x } fn main() {} diff --git a/tests/ui/type-alias-impl-trait/generic_duplicate_lifetime_param.rs b/tests/ui/type-alias-impl-trait/generic_duplicate_lifetime_param.rs index 9d938a61600f5..14ced3418542a 100644 --- a/tests/ui/type-alias-impl-trait/generic_duplicate_lifetime_param.rs +++ b/tests/ui/type-alias-impl-trait/generic_duplicate_lifetime_param.rs @@ -9,6 +9,7 @@ impl<'a, T: ?Sized> Captures<'a> for T {} type Two<'a, 'b> = impl std::fmt::Debug + Captures<'a> + Captures<'b>; fn one<'a>(t: &'a ()) -> Two<'a, 'a> { + //~^ ERROR non-defining opaque type use t //~^ ERROR non-defining opaque type use } diff --git a/tests/ui/type-alias-impl-trait/generic_duplicate_lifetime_param.stderr b/tests/ui/type-alias-impl-trait/generic_duplicate_lifetime_param.stderr index 72e1ef4b4923b..4da69a705c07c 100644 --- a/tests/ui/type-alias-impl-trait/generic_duplicate_lifetime_param.stderr +++ b/tests/ui/type-alias-impl-trait/generic_duplicate_lifetime_param.stderr @@ -1,5 +1,17 @@ error: non-defining opaque type use in defining scope - --> $DIR/generic_duplicate_lifetime_param.rs:12:5 + --> $DIR/generic_duplicate_lifetime_param.rs:11:26 + | +LL | fn one<'a>(t: &'a ()) -> Two<'a, 'a> { + | ^^^^^^^^^^^ generic argument `'a` used twice + | +note: for this opaque type + --> $DIR/generic_duplicate_lifetime_param.rs:9:20 + | +LL | type Two<'a, 'b> = impl std::fmt::Debug + Captures<'a> + Captures<'b>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: non-defining opaque type use in defining scope + --> $DIR/generic_duplicate_lifetime_param.rs:13:5 | LL | t | ^ @@ -10,5 +22,5 @@ note: lifetime used multiple times LL | type Two<'a, 'b> = impl std::fmt::Debug + Captures<'a> + Captures<'b>; | ^^ ^^ -error: aborting due to previous error +error: aborting due to 2 previous errors diff --git a/tests/ui/type-alias-impl-trait/generic_duplicate_param_use.rs b/tests/ui/type-alias-impl-trait/generic_duplicate_param_use.rs index 80462f8ac046c..1e391b55a4fac 100644 --- a/tests/ui/type-alias-impl-trait/generic_duplicate_param_use.rs +++ b/tests/ui/type-alias-impl-trait/generic_duplicate_param_use.rs @@ -1,5 +1,12 @@ #![feature(type_alias_impl_trait)] +//! This test checks various cases where we are using the same +//! generic parameter twice in the parameter list of a TAIT. +//! Within defining scopes that is not legal, because the hidden type +//! is not fully defined then. This could cause us to have a TAIT +//! that doesn't have a hidden type for all possible combinations of generic +//! parameters passed to it. + use std::fmt::Debug; fn main() {} @@ -7,7 +14,6 @@ fn main() {} // test that unused generic parameters are ok type TwoTys = impl Debug; - pub trait Captures<'a> {} impl<'a, T: ?Sized> Captures<'a> for T {} @@ -16,18 +22,20 @@ type TwoLifetimes<'a, 'b> = impl Debug + Captures<'a> + Captures<'b>; type TwoConsts = impl Debug; - fn one_ty(t: T) -> TwoTys { + //~^ ERROR non-defining opaque type use in defining scope t //~^ ERROR non-defining opaque type use in defining scope } fn one_lifetime<'a>(t: &'a u32) -> TwoLifetimes<'a, 'a> { + //~^ ERROR non-defining opaque type use in defining scope t //~^ ERROR non-defining opaque type use in defining scope } fn one_const(t: *mut [u8; N]) -> TwoConsts { + //~^ ERROR non-defining opaque type use in defining scope t //~^ ERROR non-defining opaque type use in defining scope } diff --git a/tests/ui/type-alias-impl-trait/generic_duplicate_param_use.stderr b/tests/ui/type-alias-impl-trait/generic_duplicate_param_use.stderr index 98e4bfea10d63..d8330771d301d 100644 --- a/tests/ui/type-alias-impl-trait/generic_duplicate_param_use.stderr +++ b/tests/ui/type-alias-impl-trait/generic_duplicate_param_use.stderr @@ -1,38 +1,74 @@ error: non-defining opaque type use in defining scope - --> $DIR/generic_duplicate_param_use.rs:21:5 + --> $DIR/generic_duplicate_param_use.rs:25:30 + | +LL | fn one_ty(t: T) -> TwoTys { + | ^^^^^^^^^^^^ generic argument `T` used twice + | +note: for this opaque type + --> $DIR/generic_duplicate_param_use.rs:15:21 + | +LL | type TwoTys = impl Debug; + | ^^^^^^^^^^ + +error: non-defining opaque type use in defining scope + --> $DIR/generic_duplicate_param_use.rs:27:5 | LL | t | ^ | note: type used multiple times - --> $DIR/generic_duplicate_param_use.rs:8:13 + --> $DIR/generic_duplicate_param_use.rs:15:13 | LL | type TwoTys = impl Debug; | ^ ^ error: non-defining opaque type use in defining scope - --> $DIR/generic_duplicate_param_use.rs:26:5 + --> $DIR/generic_duplicate_param_use.rs:31:36 + | +LL | fn one_lifetime<'a>(t: &'a u32) -> TwoLifetimes<'a, 'a> { + | ^^^^^^^^^^^^^^^^^^^^ generic argument `'a` used twice + | +note: for this opaque type + --> $DIR/generic_duplicate_param_use.rs:21:29 + | +LL | type TwoLifetimes<'a, 'b> = impl Debug + Captures<'a> + Captures<'b>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: non-defining opaque type use in defining scope + --> $DIR/generic_duplicate_param_use.rs:33:5 | LL | t | ^ | note: lifetime used multiple times - --> $DIR/generic_duplicate_param_use.rs:15:19 + --> $DIR/generic_duplicate_param_use.rs:21:19 | LL | type TwoLifetimes<'a, 'b> = impl Debug + Captures<'a> + Captures<'b>; | ^^ ^^ error: non-defining opaque type use in defining scope - --> $DIR/generic_duplicate_param_use.rs:31:5 + --> $DIR/generic_duplicate_param_use.rs:37:50 + | +LL | fn one_const(t: *mut [u8; N]) -> TwoConsts { + | ^^^^^^^^^^^^^^^ generic argument `N` used twice + | +note: for this opaque type + --> $DIR/generic_duplicate_param_use.rs:23:50 + | +LL | type TwoConsts = impl Debug; + | ^^^^^^^^^^ + +error: non-defining opaque type use in defining scope + --> $DIR/generic_duplicate_param_use.rs:39:5 | LL | t | ^ | note: constant used multiple times - --> $DIR/generic_duplicate_param_use.rs:17:16 + --> $DIR/generic_duplicate_param_use.rs:23:16 | LL | type TwoConsts = impl Debug; | ^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^ -error: aborting due to 3 previous errors +error: aborting due to 6 previous errors diff --git a/tests/ui/type-alias-impl-trait/generic_nondefining_use.rs b/tests/ui/type-alias-impl-trait/generic_nondefining_use.rs index e7b8567b9a217..68f4c6923ae18 100644 --- a/tests/ui/type-alias-impl-trait/generic_nondefining_use.rs +++ b/tests/ui/type-alias-impl-trait/generic_nondefining_use.rs @@ -13,16 +13,19 @@ type OneConst = impl Debug; // Not defining uses, because they doesn't define *all* possible generics. fn concrete_ty() -> OneTy { + //~^ ERROR: non-defining opaque type use in defining scope 5u32 - //~^ ERROR expected generic type parameter, found `u32` + //~^ ERROR: expected generic type parameter, found `u32` } fn concrete_lifetime() -> OneLifetime<'static> { + //~^ ERROR: non-defining opaque type use in defining scope 6u32 - //~^ ERROR expected generic lifetime parameter, found `'static` + //~^ ERROR: expected generic lifetime parameter, found `'static` } fn concrete_const() -> OneConst<{ 123 }> { + //~^ ERROR: non-defining opaque type use in defining scope 7u32 - //~^ ERROR expected generic constant parameter, found `123` + //~^ ERROR: expected generic constant parameter, found `123` } diff --git a/tests/ui/type-alias-impl-trait/generic_nondefining_use.stderr b/tests/ui/type-alias-impl-trait/generic_nondefining_use.stderr index 966fe823f024d..e3b7b1a76b09d 100644 --- a/tests/ui/type-alias-impl-trait/generic_nondefining_use.stderr +++ b/tests/ui/type-alias-impl-trait/generic_nondefining_use.stderr @@ -1,5 +1,17 @@ +error[E0792]: non-defining opaque type use in defining scope + --> $DIR/generic_nondefining_use.rs:15:21 + | +LL | fn concrete_ty() -> OneTy { + | ^^^^^^^^^^ argument `u32` is not a generic parameter + | +note: for this opaque type + --> $DIR/generic_nondefining_use.rs:7:17 + | +LL | type OneTy = impl Debug; + | ^^^^^^^^^^ + error[E0792]: expected generic type parameter, found `u32` - --> $DIR/generic_nondefining_use.rs:16:5 + --> $DIR/generic_nondefining_use.rs:17:5 | LL | type OneTy = impl Debug; | - this generic parameter must be used with a generic type parameter @@ -7,8 +19,20 @@ LL | type OneTy = impl Debug; LL | 5u32 | ^^^^ +error[E0792]: non-defining opaque type use in defining scope + --> $DIR/generic_nondefining_use.rs:21:27 + | +LL | fn concrete_lifetime() -> OneLifetime<'static> { + | ^^^^^^^^^^^^^^^^^^^^ argument `'static` is not a generic parameter + | +note: for this opaque type + --> $DIR/generic_nondefining_use.rs:9:24 + | +LL | type OneLifetime<'a> = impl Debug; + | ^^^^^^^^^^ + error[E0792]: expected generic lifetime parameter, found `'static` - --> $DIR/generic_nondefining_use.rs:21:5 + --> $DIR/generic_nondefining_use.rs:23:5 | LL | type OneLifetime<'a> = impl Debug; | -- cannot use static lifetime; use a bound lifetime instead or remove the lifetime parameter from the opaque type @@ -16,8 +40,20 @@ LL | type OneLifetime<'a> = impl Debug; LL | 6u32 | ^^^^ +error[E0792]: non-defining opaque type use in defining scope + --> $DIR/generic_nondefining_use.rs:27:24 + | +LL | fn concrete_const() -> OneConst<{ 123 }> { + | ^^^^^^^^^^^^^^^^^ argument `123` is not a generic parameter + | +note: for this opaque type + --> $DIR/generic_nondefining_use.rs:11:33 + | +LL | type OneConst = impl Debug; + | ^^^^^^^^^^ + error[E0792]: expected generic constant parameter, found `123` - --> $DIR/generic_nondefining_use.rs:26:5 + --> $DIR/generic_nondefining_use.rs:29:5 | LL | type OneConst = impl Debug; | -------------- this generic parameter must be used with a generic constant parameter @@ -25,6 +61,6 @@ LL | type OneConst = impl Debug; LL | 7u32 | ^^^^ -error: aborting due to 3 previous errors +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0792`. diff --git a/tests/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.rs b/tests/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.rs index cdd8f6f1976a5..c60f5c11cd18c 100644 --- a/tests/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.rs +++ b/tests/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.rs @@ -5,12 +5,12 @@ fn main() { let x = wrong_generic(&y); let z: i32 = x; //~^ ERROR expected generic type parameter, found `&i32` -} -type WrongGeneric = impl 'static; -//~^ ERROR: at least one trait must be specified + type WrongGeneric = impl 'static; + //~^ ERROR: at least one trait must be specified -fn wrong_generic(t: T) -> WrongGeneric { - t - //~^ ERROR the parameter type `T` may not live long enough + fn wrong_generic(t: T) -> WrongGeneric { + t + //~^ ERROR the parameter type `T` may not live long enough + } } diff --git a/tests/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.stderr b/tests/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.stderr index fa79e51e9f79f..8c3a25dbfe7de 100644 --- a/tests/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.stderr +++ b/tests/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.stderr @@ -1,8 +1,8 @@ error: at least one trait must be specified - --> $DIR/generic_type_does_not_live_long_enough.rs:10:24 + --> $DIR/generic_type_does_not_live_long_enough.rs:9:28 | -LL | type WrongGeneric = impl 'static; - | ^^^^^^^^^^^^ +LL | type WrongGeneric = impl 'static; + | ^^^^^^^^^^^^ error[E0792]: expected generic type parameter, found `&i32` --> $DIR/generic_type_does_not_live_long_enough.rs:6:18 @@ -10,19 +10,19 @@ error[E0792]: expected generic type parameter, found `&i32` LL | let z: i32 = x; | ^ ... -LL | type WrongGeneric = impl 'static; - | - this generic parameter must be used with a generic type parameter +LL | type WrongGeneric = impl 'static; + | - this generic parameter must be used with a generic type parameter error[E0310]: the parameter type `T` may not live long enough - --> $DIR/generic_type_does_not_live_long_enough.rs:14:5 + --> $DIR/generic_type_does_not_live_long_enough.rs:13:9 | -LL | t - | ^ ...so that the type `T` will meet its required lifetime bounds +LL | t + | ^ ...so that the type `T` will meet its required lifetime bounds | help: consider adding an explicit lifetime bound... | -LL | fn wrong_generic(t: T) -> WrongGeneric { - | +++++++++ +LL | fn wrong_generic(t: T) -> WrongGeneric { + | +++++++++ error: aborting due to 3 previous errors diff --git a/tests/ui/type-alias-impl-trait/higher_kinded_params.rs b/tests/ui/type-alias-impl-trait/higher_kinded_params.rs new file mode 100644 index 0000000000000..db1a3a1c7a9d0 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/higher_kinded_params.rs @@ -0,0 +1,28 @@ +//! This test checks that walking into binders +//! during opaque type collection does not ICE or raise errors. + +// edition: 2021 + +// check-pass + +#![feature(type_alias_impl_trait)] + +trait B { + type C; +} + +struct A; + +impl<'a> B for &'a A { + type C = (); +} + +struct Terminator; + +type Successors<'a> = impl std::fmt::Debug + 'a; + +impl Terminator { + fn successors(&self, _: for<'x> fn(&'x ()) -> <&'x A as B>::C) -> Successors<'_> {} +} + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/higher_kinded_params2.rs b/tests/ui/type-alias-impl-trait/higher_kinded_params2.rs new file mode 100644 index 0000000000000..f011e5b214813 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/higher_kinded_params2.rs @@ -0,0 +1,35 @@ +//! This test checks the behaviour of walking into binders +//! and normalizing something behind them actually works. + +// edition: 2021 + +#![feature(type_alias_impl_trait)] + +trait B { + type C; +} + +struct A; + +impl<'a> B for &'a A { + type C = Tait; +} + +type Tait = impl std::fmt::Debug; + +struct Terminator; + +type Successors<'a> = impl std::fmt::Debug + 'a; + +impl Terminator { + fn successors(&self, mut f: for<'x> fn(&'x ()) -> <&'x A as B>::C) -> Successors<'_> { + f = g; + //~^ ERROR item constrains opaque type that is not in its signature + } +} + +fn g(_: &()) -> String { + String::new() +} + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/higher_kinded_params2.stderr b/tests/ui/type-alias-impl-trait/higher_kinded_params2.stderr new file mode 100644 index 0000000000000..39f584dd49ca3 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/higher_kinded_params2.stderr @@ -0,0 +1,15 @@ +error: item constrains opaque type that is not in its signature + --> $DIR/higher_kinded_params2.rs:26:13 + | +LL | f = g; + | ^ + | + = note: this item must mention the opaque type in its signature in order to be able to register hidden types +note: this item must mention the opaque type in its signature in order to be able to register hidden types + --> $DIR/higher_kinded_params2.rs:25:8 + | +LL | fn successors(&self, mut f: for<'x> fn(&'x ()) -> <&'x A as B>::C) -> Successors<'_> { + | ^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/tests/ui/type-alias-impl-trait/higher_kinded_params3.rs b/tests/ui/type-alias-impl-trait/higher_kinded_params3.rs index 839a611cb71a9..6edfccaf7d179 100644 --- a/tests/ui/type-alias-impl-trait/higher_kinded_params3.rs +++ b/tests/ui/type-alias-impl-trait/higher_kinded_params3.rs @@ -24,7 +24,8 @@ type Successors<'a> = impl std::fmt::Debug + 'a; impl Terminator { fn successors(&self, mut f: for<'x> fn(&'x ()) -> <&'x A as B>::C) -> Successors<'_> { f = g; - //~^ ERROR: mismatched types + //~^ ERROR mismatched types + //~| ERROR item constrains opaque type that is not in its signature } } diff --git a/tests/ui/type-alias-impl-trait/higher_kinded_params3.stderr b/tests/ui/type-alias-impl-trait/higher_kinded_params3.stderr index aaba9ad5ca704..14372d8f3e64d 100644 --- a/tests/ui/type-alias-impl-trait/higher_kinded_params3.stderr +++ b/tests/ui/type-alias-impl-trait/higher_kinded_params3.stderr @@ -1,3 +1,16 @@ +error: item constrains opaque type that is not in its signature + --> $DIR/higher_kinded_params3.rs:26:13 + | +LL | f = g; + | ^ + | + = note: this item must mention the opaque type in its signature in order to be able to register hidden types +note: this item must mention the opaque type in its signature in order to be able to register hidden types + --> $DIR/higher_kinded_params3.rs:25:8 + | +LL | fn successors(&self, mut f: for<'x> fn(&'x ()) -> <&'x A as B>::C) -> Successors<'_> { + | ^^^^^^^^^^ + error[E0308]: mismatched types --> $DIR/higher_kinded_params3.rs:26:9 | @@ -10,6 +23,6 @@ LL | f = g; = note: expected fn pointer `for<'x> fn(&'x ()) -> Tait<'x>` found fn pointer `for<'a> fn(&'a ()) -> &'a ()` -error: aborting due to previous error +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/type-alias-impl-trait/inference-cycle.rs b/tests/ui/type-alias-impl-trait/inference-cycle.rs index 093afc25249a7..20175a4feca00 100644 --- a/tests/ui/type-alias-impl-trait/inference-cycle.rs +++ b/tests/ui/type-alias-impl-trait/inference-cycle.rs @@ -17,8 +17,8 @@ mod m { //~^ ERROR: cannot check whether the hidden type of `inference_cycle[4ecc]::m::Foo::{opaque#0}` satisfies auto traits } - fn baz() { - let f: Foo = (); + fn baz() -> Foo { + () } fn is_send(_: T) {} diff --git a/tests/ui/type-alias-impl-trait/issue-53678-generator-and-const-fn.rs b/tests/ui/type-alias-impl-trait/issue-53678-generator-and-const-fn.rs index a3f126d56cf20..a213dbba4ea01 100644 --- a/tests/ui/type-alias-impl-trait/issue-53678-generator-and-const-fn.rs +++ b/tests/ui/type-alias-impl-trait/issue-53678-generator-and-const-fn.rs @@ -1,19 +1,22 @@ #![feature(generators, generator_trait, rustc_attrs)] #![feature(type_alias_impl_trait)] -use std::ops::Generator; +// check-pass -type GenOnce = impl Generator; +mod gen { + use std::ops::Generator; -const fn const_generator(yielding: Y, returning: R) -> GenOnce { - move || { - yield yielding; + pub type GenOnce = impl Generator; - return returning; + pub const fn const_generator(yielding: Y, returning: R) -> GenOnce { + move || { + yield yielding; + + return returning; + } } } -const FOO: GenOnce = const_generator(10, 100); +const FOO: gen::GenOnce = gen::const_generator(10, 100); -#[rustc_error] -fn main() {} //~ ERROR +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/issue-53678-generator-and-const-fn.stderr b/tests/ui/type-alias-impl-trait/issue-53678-generator-and-const-fn.stderr deleted file mode 100644 index eb1c9603a60d6..0000000000000 --- a/tests/ui/type-alias-impl-trait/issue-53678-generator-and-const-fn.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: fatal error triggered by #[rustc_error] - --> $DIR/issue-53678-generator-and-const-fn.rs:19:1 - | -LL | fn main() {} - | ^^^^^^^^^ - -error: aborting due to previous error - diff --git a/tests/ui/type-alias-impl-trait/issue-57961.rs b/tests/ui/type-alias-impl-trait/issue-57961.rs index 4aa5966ff25d4..61af7a0f62500 100644 --- a/tests/ui/type-alias-impl-trait/issue-57961.rs +++ b/tests/ui/type-alias-impl-trait/issue-57961.rs @@ -11,8 +11,8 @@ impl Foo for () { //~^ ERROR expected `IntoIter` to be an iterator that yields `X`, but it yields `u32` } -fn incoherent() { - let f: X = 22_i32; +fn incoherent() -> X { + 22_i32 } fn main() {} diff --git a/tests/ui/type-alias-impl-trait/issue-60564.rs b/tests/ui/type-alias-impl-trait/issue-60564.rs index c2f4c37080746..48bd70bcca950 100644 --- a/tests/ui/type-alias-impl-trait/issue-60564.rs +++ b/tests/ui/type-alias-impl-trait/issue-60564.rs @@ -17,6 +17,7 @@ where { type BitsIter = IterBitsIter; fn iter_bits(self, n: u8) -> Self::BitsIter { + //~^ ERROR non-defining opaque type use (0u8..n).rev().map(move |shift| ((self >> T::from(shift)) & T::from(1)).try_into().unwrap()) //~^ ERROR expected generic type parameter, found `u8` } diff --git a/tests/ui/type-alias-impl-trait/issue-60564.stderr b/tests/ui/type-alias-impl-trait/issue-60564.stderr index f8fdb004d0989..d42495e934d33 100644 --- a/tests/ui/type-alias-impl-trait/issue-60564.stderr +++ b/tests/ui/type-alias-impl-trait/issue-60564.stderr @@ -1,5 +1,17 @@ +error[E0792]: non-defining opaque type use in defining scope + --> $DIR/issue-60564.rs:19:34 + | +LL | fn iter_bits(self, n: u8) -> Self::BitsIter { + | ^^^^^^^^^^^^^^ argument `u8` is not a generic parameter + | +note: for this opaque type + --> $DIR/issue-60564.rs:8:30 + | +LL | type IterBitsIter = impl std::iter::Iterator; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + error[E0792]: expected generic type parameter, found `u8` - --> $DIR/issue-60564.rs:20:9 + --> $DIR/issue-60564.rs:21:9 | LL | type IterBitsIter = impl std::iter::Iterator; | - this generic parameter must be used with a generic type parameter @@ -7,6 +19,6 @@ LL | type IterBitsIter = impl std::iter::Iterator; LL | (0u8..n).rev().map(move |shift| ((self >> T::from(shift)) & T::from(1)).try_into().unwrap()) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to previous error +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0792`. diff --git a/tests/ui/type-alias-impl-trait/issue-63263-closure-return.rs b/tests/ui/type-alias-impl-trait/issue-63263-closure-return.rs index 7414611a74893..ddea7aeb6cda7 100644 --- a/tests/ui/type-alias-impl-trait/issue-63263-closure-return.rs +++ b/tests/ui/type-alias-impl-trait/issue-63263-closure-return.rs @@ -8,6 +8,9 @@ pub type Closure = impl FnOnce(); -fn main() { +fn bop() -> Closure { || -> Closure { || () }; + panic!() } + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/issue-65679-inst-opaque-ty-from-val-twice.rs b/tests/ui/type-alias-impl-trait/issue-65679-inst-opaque-ty-from-val-twice.rs index b91cbce3727f6..7b3e9e12405c7 100644 --- a/tests/ui/type-alias-impl-trait/issue-65679-inst-opaque-ty-from-val-twice.rs +++ b/tests/ui/type-alias-impl-trait/issue-65679-inst-opaque-ty-from-val-twice.rs @@ -11,7 +11,9 @@ type T = impl Sized; fn take(_: fn() -> T) {} -fn main() { +fn bop(_: T) { take(|| {}); take(|| {}); } + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/issue-68368-non-defining-use-2.rs b/tests/ui/type-alias-impl-trait/issue-68368-non-defining-use-2.rs index 5e0a82a72868a..9dcdb578568aa 100644 --- a/tests/ui/type-alias-impl-trait/issue-68368-non-defining-use-2.rs +++ b/tests/ui/type-alias-impl-trait/issue-68368-non-defining-use-2.rs @@ -7,7 +7,8 @@ trait Trait {} type Alias<'a, U> = impl Trait; fn f<'a>() -> Alias<'a, ()> {} -//~^ ERROR expected generic type parameter, found `()` +//~^ ERROR non-defining opaque type use +//~| ERROR expected generic type parameter, found `()` fn main() {} diff --git a/tests/ui/type-alias-impl-trait/issue-68368-non-defining-use-2.stderr b/tests/ui/type-alias-impl-trait/issue-68368-non-defining-use-2.stderr index 271743a4010c8..085bffe907b4b 100644 --- a/tests/ui/type-alias-impl-trait/issue-68368-non-defining-use-2.stderr +++ b/tests/ui/type-alias-impl-trait/issue-68368-non-defining-use-2.stderr @@ -1,3 +1,15 @@ +error[E0792]: non-defining opaque type use in defining scope + --> $DIR/issue-68368-non-defining-use-2.rs:9:15 + | +LL | fn f<'a>() -> Alias<'a, ()> {} + | ^^^^^^^^^^^^^ argument `()` is not a generic parameter + | +note: for this opaque type + --> $DIR/issue-68368-non-defining-use-2.rs:7:21 + | +LL | type Alias<'a, U> = impl Trait; + | ^^^^^^^^^^^^^ + error[E0792]: expected generic type parameter, found `()` --> $DIR/issue-68368-non-defining-use-2.rs:9:29 | @@ -7,6 +19,6 @@ LL | LL | fn f<'a>() -> Alias<'a, ()> {} | ^^ -error: aborting due to previous error +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0792`. diff --git a/tests/ui/type-alias-impl-trait/issue-68368-non-defining-use.rs b/tests/ui/type-alias-impl-trait/issue-68368-non-defining-use.rs index 3b32260c96fe1..dfe2ee8204c75 100644 --- a/tests/ui/type-alias-impl-trait/issue-68368-non-defining-use.rs +++ b/tests/ui/type-alias-impl-trait/issue-68368-non-defining-use.rs @@ -8,6 +8,7 @@ type Alias<'a, U> = impl Trait; fn f<'a>() -> Alias<'a, ()> {} //~^ ERROR expected generic type parameter, found `()` +//~| ERROR non-defining opaque type use fn main() {} diff --git a/tests/ui/type-alias-impl-trait/issue-68368-non-defining-use.stderr b/tests/ui/type-alias-impl-trait/issue-68368-non-defining-use.stderr index 4d9a8d6eef915..ea704ffff97ab 100644 --- a/tests/ui/type-alias-impl-trait/issue-68368-non-defining-use.stderr +++ b/tests/ui/type-alias-impl-trait/issue-68368-non-defining-use.stderr @@ -1,3 +1,15 @@ +error[E0792]: non-defining opaque type use in defining scope + --> $DIR/issue-68368-non-defining-use.rs:9:15 + | +LL | fn f<'a>() -> Alias<'a, ()> {} + | ^^^^^^^^^^^^^ argument `()` is not a generic parameter + | +note: for this opaque type + --> $DIR/issue-68368-non-defining-use.rs:7:21 + | +LL | type Alias<'a, U> = impl Trait; + | ^^^^^^^^^^^^^ + error[E0792]: expected generic type parameter, found `()` --> $DIR/issue-68368-non-defining-use.rs:9:29 | @@ -7,6 +19,6 @@ LL | LL | fn f<'a>() -> Alias<'a, ()> {} | ^^ -error: aborting due to previous error +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0792`. diff --git a/tests/ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-error.rs b/tests/ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-error.rs index 7657fe2fb1aee..a0f8e48e268c9 100644 --- a/tests/ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-error.rs +++ b/tests/ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-error.rs @@ -1,4 +1,6 @@ -// Regression test for #69136 +//! Regression test for #69136 +//! This test checks that the unknown lifetime `'a` doesn't cause +//! ICEs after emitting the error. #![feature(type_alias_impl_trait)] @@ -17,7 +19,6 @@ impl WithAssoc for () { type Return = impl WithAssoc; //~^ ERROR use of undeclared lifetime name `'a` -fn my_fun() -> Return<()> {} -//~^ ERROR expected generic type parameter, found `()` +fn my_fun() -> Return {} fn main() {} diff --git a/tests/ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-error.stderr b/tests/ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-error.stderr index d1250786d938c..b7af3f06d0d9a 100644 --- a/tests/ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-error.stderr +++ b/tests/ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-error.stderr @@ -1,5 +1,5 @@ error[E0261]: use of undeclared lifetime name `'a` - --> $DIR/issue-69136-inner-lifetime-resolve-error.rs:17:65 + --> $DIR/issue-69136-inner-lifetime-resolve-error.rs:19:65 | LL | type Return = impl WithAssoc; | ^^ undeclared lifetime @@ -14,16 +14,6 @@ help: consider introducing lifetime `'a` here LL | type Return<'a, A> = impl WithAssoc; | +++ -error[E0792]: expected generic type parameter, found `()` - --> $DIR/issue-69136-inner-lifetime-resolve-error.rs:20:27 - | -LL | type Return = impl WithAssoc; - | - this generic parameter must be used with a generic type parameter -... -LL | fn my_fun() -> Return<()> {} - | ^^ - -error: aborting due to 2 previous errors +error: aborting due to previous error -Some errors have detailed explanations: E0261, E0792. -For more information about an error, try `rustc --explain E0261`. +For more information about this error, try `rustc --explain E0261`. diff --git a/tests/ui/type-alias-impl-trait/issue-70121.rs b/tests/ui/type-alias-impl-trait/issue-70121.rs index dff0d89d465dd..bfd8d8872e37f 100644 --- a/tests/ui/type-alias-impl-trait/issue-70121.rs +++ b/tests/ui/type-alias-impl-trait/issue-70121.rs @@ -1,5 +1,3 @@ -// check-pass - #![feature(type_alias_impl_trait)] pub type Successors<'a> = impl Iterator; @@ -17,6 +15,7 @@ impl<'a> Tr for &'a () { } pub fn kazusa<'a>() -> <&'a () as Tr>::Item { + //~^ ERROR item constrains opaque type that is not in its signature None.into_iter() } diff --git a/tests/ui/type-alias-impl-trait/issue-70121.stderr b/tests/ui/type-alias-impl-trait/issue-70121.stderr new file mode 100644 index 0000000000000..30c3ddd8659d1 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/issue-70121.stderr @@ -0,0 +1,15 @@ +error: item constrains opaque type that is not in its signature + --> $DIR/issue-70121.rs:17:24 + | +LL | pub fn kazusa<'a>() -> <&'a () as Tr>::Item { + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: this item must mention the opaque type in its signature in order to be able to register hidden types +note: this item must mention the opaque type in its signature in order to be able to register hidden types + --> $DIR/issue-70121.rs:17:8 + | +LL | pub fn kazusa<'a>() -> <&'a () as Tr>::Item { + | ^^^^^^ + +error: aborting due to previous error + diff --git a/tests/ui/type-alias-impl-trait/issue-77179.rs b/tests/ui/type-alias-impl-trait/issue-77179.rs index 8d818d4a387a6..e7b04a4897559 100644 --- a/tests/ui/type-alias-impl-trait/issue-77179.rs +++ b/tests/ui/type-alias-impl-trait/issue-77179.rs @@ -2,7 +2,7 @@ #![feature(type_alias_impl_trait)] -type Pointer = impl std::ops::Deref; +type Pointer = impl std::ops::Deref; fn test() -> Pointer<_> { //~^ ERROR: the placeholder `_` is not allowed within types diff --git a/tests/ui/type-alias-impl-trait/nested-tait-inference2.stderr b/tests/ui/type-alias-impl-trait/nested-tait-inference2.stderr index f4d96038d9109..dccf84362f0f8 100644 --- a/tests/ui/type-alias-impl-trait/nested-tait-inference2.stderr +++ b/tests/ui/type-alias-impl-trait/nested-tait-inference2.stderr @@ -8,8 +8,8 @@ LL | () | -- return type was inferred to be `()` here | = help: the following other types implement trait `Foo`: - <() as Foo<()>> <() as Foo> + <() as Foo<()>> error: aborting due to previous error diff --git a/tests/ui/type-alias-impl-trait/nested_in_closure.rs b/tests/ui/type-alias-impl-trait/nested_in_closure.rs new file mode 100644 index 0000000000000..362f3d53e88bf --- /dev/null +++ b/tests/ui/type-alias-impl-trait/nested_in_closure.rs @@ -0,0 +1,17 @@ +#![feature(type_alias_impl_trait)] +// check-pass + +fn main() { + let x = || { + type Tait = impl Sized; + let y: Tait = (); + }; + + let y = || { + type Tait = impl std::fmt::Debug; + let y: Tait = (); + y + }; + let mut z = y(); + z = (); +} diff --git a/tests/ui/type-alias-impl-trait/nested_type_alias_impl_trait.rs b/tests/ui/type-alias-impl-trait/nested_type_alias_impl_trait.rs index 60b6e1aac6281..07607516cc4bc 100644 --- a/tests/ui/type-alias-impl-trait/nested_type_alias_impl_trait.rs +++ b/tests/ui/type-alias-impl-trait/nested_type_alias_impl_trait.rs @@ -10,11 +10,11 @@ mod my_mod { 5i32 } - pub fn get_foot() -> Foot { + pub fn get_foot(_: Foo) -> Foot { get_foo() //~ ERROR opaque type's hidden type cannot be another opaque type } } fn main() { - let _: my_mod::Foot = my_mod::get_foot(); + let _: my_mod::Foot = my_mod::get_foot(my_mod::get_foo()); } diff --git a/tests/ui/type-alias-impl-trait/no_revealing_outside_defining_module.stderr b/tests/ui/type-alias-impl-trait/no_revealing_outside_defining_module.stderr index ae03a5b3e37bf..863282a0ff94d 100644 --- a/tests/ui/type-alias-impl-trait/no_revealing_outside_defining_module.stderr +++ b/tests/ui/type-alias-impl-trait/no_revealing_outside_defining_module.stderr @@ -11,6 +11,11 @@ LL | let _: &str = bomp(); | = note: expected reference `&str` found opaque type `Boo` +note: this item must have the opaque type in its signature in order to be able to register hidden types + --> $DIR/no_revealing_outside_defining_module.rs:14:4 + | +LL | fn bomp2() { + | ^^^^^ error[E0308]: mismatched types --> $DIR/no_revealing_outside_defining_module.rs:19:5 @@ -25,6 +30,11 @@ LL | "" | = note: expected opaque type `Boo` found reference `&'static str` +note: this item must have the opaque type in its signature in order to be able to register hidden types + --> $DIR/no_revealing_outside_defining_module.rs:18:4 + | +LL | fn bomp() -> boo::Boo { + | ^^^^ error: aborting due to 2 previous errors diff --git a/tests/ui/type-alias-impl-trait/reveal_local.rs b/tests/ui/type-alias-impl-trait/reveal_local.rs index 75015e41c3da7..7943bb240f15b 100644 --- a/tests/ui/type-alias-impl-trait/reveal_local.rs +++ b/tests/ui/type-alias-impl-trait/reveal_local.rs @@ -16,7 +16,7 @@ fn not_good() { //~^ ERROR: cannot check whether the hidden type of `reveal_local[9507]::Foo::{opaque#0}` satisfies auto traits } -fn not_gooder() { +fn not_gooder() -> Foo { // Constrain `Foo = u32` let x: Foo = 22_u32; @@ -24,6 +24,8 @@ fn not_gooder() { // need extra roundabout logic to support it. is_send::(); //~^ ERROR: cannot check whether the hidden type of `reveal_local[9507]::Foo::{opaque#0}` satisfies auto traits + + x } fn main() {} diff --git a/tests/ui/type-alias-impl-trait/reveal_local.stderr b/tests/ui/type-alias-impl-trait/reveal_local.stderr index 202a87ecbb773..0c5ef4a6fb418 100644 --- a/tests/ui/type-alias-impl-trait/reveal_local.stderr +++ b/tests/ui/type-alias-impl-trait/reveal_local.stderr @@ -78,8 +78,8 @@ LL | type Foo = impl Debug; note: ...which requires type-checking `not_gooder`... --> $DIR/reveal_local.rs:19:1 | -LL | fn not_gooder() { - | ^^^^^^^^^^^^^^^ +LL | fn not_gooder() -> Foo { + | ^^^^^^^^^^^^^^^^^^^^^^ = note: ...which again requires computing type of `Foo::{opaque#0}`, completing the cycle note: cycle used when checking item types in top-level module --> $DIR/reveal_local.rs:1:1 @@ -107,7 +107,7 @@ LL | type Foo = impl Debug; note: this item depends on auto traits of the hidden type, but may also be registering the hidden type. This is not supported right now. You can try moving the opaque type and the item that actually registers a hidden type into a new submodule --> $DIR/reveal_local.rs:19:4 | -LL | fn not_gooder() { +LL | fn not_gooder() -> Foo { | ^^^^^^^^^^ note: required by a bound in `is_send` --> $DIR/reveal_local.rs:10:15 diff --git a/tests/ui/type-alias-impl-trait/type_of_a_let.rs b/tests/ui/type-alias-impl-trait/type_of_a_let.rs index 4e9d1788b94d8..36161171555ca 100644 --- a/tests/ui/type-alias-impl-trait/type_of_a_let.rs +++ b/tests/ui/type-alias-impl-trait/type_of_a_let.rs @@ -5,16 +5,16 @@ use std::fmt::Debug; type Foo = impl Debug; -fn foo1() -> u32 { +fn foo1() -> (u32, Foo) { let x: Foo = 22_u32; - x + (x, todo!()) } -fn foo2() -> u32 { +fn foo2() -> (u32, Foo) { let x: Foo = 22_u32; let y: Foo = x; same_type((x, y)); //~ ERROR use of moved value - y //~ ERROR use of moved value + (y, todo!()) //~ ERROR use of moved value } fn same_type(x: (T, T)) {} diff --git a/tests/ui/type-alias-impl-trait/type_of_a_let.stderr b/tests/ui/type-alias-impl-trait/type_of_a_let.stderr index 1dabe4586c5b9..7d7cad874faec 100644 --- a/tests/ui/type-alias-impl-trait/type_of_a_let.stderr +++ b/tests/ui/type-alias-impl-trait/type_of_a_let.stderr @@ -9,14 +9,14 @@ LL | same_type((x, y)); | ^ value used here after move error[E0382]: use of moved value: `y` - --> $DIR/type_of_a_let.rs:17:5 + --> $DIR/type_of_a_let.rs:17:6 | LL | let y: Foo = x; | - move occurs because `y` has type `Foo`, which does not implement the `Copy` trait LL | same_type((x, y)); | - value moved here -LL | y - | ^ value used here after move +LL | (y, todo!()) + | ^ value used here after move error: aborting due to 2 previous errors diff --git a/tests/ui/type/type-check-defaults.stderr b/tests/ui/type/type-check-defaults.stderr index 9ba63ffe9c93f..10d600cbfccce 100644 --- a/tests/ui/type/type-check-defaults.stderr +++ b/tests/ui/type/type-check-defaults.stderr @@ -66,10 +66,10 @@ LL | trait ProjectionPred> where T::Item : Add {} | = help: the trait `Add` is not implemented for `i32` = help: the following other types implement trait `Add`: + + > <&'a i32 as Add> <&i32 as Add<&i32>> - > - error: aborting due to 7 previous errors diff --git a/tests/ui/typeck/issue-81293.stderr b/tests/ui/typeck/issue-81293.stderr index 6976be71135c2..292c63070ae44 100644 --- a/tests/ui/typeck/issue-81293.stderr +++ b/tests/ui/typeck/issue-81293.stderr @@ -21,10 +21,10 @@ LL | a = c + b * 5; | = help: the trait `Add` is not implemented for `usize` = help: the following other types implement trait `Add`: + + > <&'a usize as Add> <&usize as Add<&usize>> - > - error: aborting due to 3 previous errors diff --git a/tests/ui/typeck/issue-90101.stderr b/tests/ui/typeck/issue-90101.stderr index d2729d853547b..484089f9e87e3 100644 --- a/tests/ui/typeck/issue-90101.stderr +++ b/tests/ui/typeck/issue-90101.stderr @@ -7,11 +7,11 @@ LL | func(Path::new("hello").to_path_buf().to_string_lossy(), "world") | required by a bound introduced by this call | = help: the following other types implement trait `From`: - > >> >> > > + > = note: required for `Cow<'_, str>` to implement `Into` note: required by a bound in `func` --> $DIR/issue-90101.rs:3:20 diff --git a/tests/ui/ufcs/ufcs-qpath-self-mismatch.stderr b/tests/ui/ufcs/ufcs-qpath-self-mismatch.stderr index 96ac4321689f3..85adf7751392f 100644 --- a/tests/ui/ufcs/ufcs-qpath-self-mismatch.stderr +++ b/tests/ui/ufcs/ufcs-qpath-self-mismatch.stderr @@ -8,10 +8,10 @@ LL | >::add(1, 2); | = help: the trait `Add` is not implemented for `i32` = help: the following other types implement trait `Add`: + + > <&'a i32 as Add> <&i32 as Add<&i32>> - > - error[E0308]: mismatched types --> $DIR/ufcs-qpath-self-mismatch.rs:7:28 @@ -65,10 +65,10 @@ LL | >::add(1, 2); | = help: the trait `Add` is not implemented for `i32` = help: the following other types implement trait `Add`: + + > <&'a i32 as Add> <&i32 as Add<&i32>> - > - error: aborting due to 4 previous errors diff --git a/triagebot.toml b/triagebot.toml index 4bab8facc85b0..e6c593204cad0 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -20,6 +20,7 @@ allow-unauthenticated = [ "regression-*", "perf-*", "AsyncAwait-OnDeck", + "needs-triage", ] [glacier] @@ -254,6 +255,9 @@ trigger_files = [ [autolabel."S-waiting-on-review"] new_pr = true +[autolabel."needs-triage"] +new_issue = true + [autolabel."WG-trait-system-refactor"] trigger_files = [ "compiler/rustc_trait_selection/src/solve",