diff --git a/.mailmap b/.mailmap index 30c3212810cf9..564a68955d301 100644 --- a/.mailmap +++ b/.mailmap @@ -105,10 +105,13 @@ Chris Vittal Christopher Vittal Christiaan Dirkx CDirkx Christiaan Dirkx CDirkx -Christian Poveda -Christian Poveda -Christian Poveda -Christian Poveda +Christian Poveda +Christian Poveda +Christian Poveda +Christian Poveda +Christian Poveda +Christian Poveda <31802960+christianpoveda@users.noreply.github.com> +Christian Poveda Christian Vallentin Christoffer Buchholz Christopher Durham diff --git a/Cargo.lock b/Cargo.lock index afe1814de6720..7ed327e9f4ccb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -220,7 +220,7 @@ dependencies = [ "libc", "once_cell", "opener", - "pretty_assertions", + "pretty_assertions 0.7.2", "serde", "serde_json", "tar", @@ -311,7 +311,7 @@ dependencies = [ [[package]] name = "cargo" -version = "0.63.0" +version = "0.64.0" dependencies = [ "anyhow", "atty", @@ -364,7 +364,7 @@ dependencies = [ "tar", "tempfile", "termcolor", - "toml_edit 0.14.3", + "toml_edit", "unicode-width", "unicode-xid", "url 2.2.2", @@ -451,7 +451,7 @@ dependencies = [ "snapbox", "tar", "termcolor", - "toml_edit 0.14.3", + "toml_edit", "url 2.2.2", ] @@ -627,7 +627,7 @@ dependencies = [ [[package]] name = "clippy" -version = "0.1.62" +version = "0.1.63" dependencies = [ "clippy_lints", "clippy_utils", @@ -647,6 +647,7 @@ dependencies = [ "serde", "syn", "tempfile", + "termize", "tester", "tokio", ] @@ -667,7 +668,7 @@ dependencies = [ [[package]] name = "clippy_lints" -version = "0.1.62" +version = "0.1.63" dependencies = [ "cargo_metadata", "clippy_utils", @@ -688,7 +689,7 @@ dependencies = [ [[package]] name = "clippy_utils" -version = "0.1.62" +version = "0.1.63" dependencies = [ "arrayvec", "if_chain", @@ -745,9 +746,9 @@ dependencies = [ [[package]] name = "compiler_builtins" -version = "0.1.71" +version = "0.1.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "163437f05ca8f29d7e9128ea728dedf5eb620e445fbca273641d3a3050305f23" +checksum = "71b72fde1d7792ca3bd654f7c3ea4508f9e4d0c826e24179eabb7fcc97a90bc3" dependencies = [ "cc", "rustc-std-workspace-core", @@ -882,6 +883,20 @@ dependencies = [ "cfg-if 0.1.10", ] +[[package]] +name = "crossbeam" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ae5588f6b3c3cb05239e90bd110f257254aecd01e4635400391aeae07497845" +dependencies = [ + "cfg-if 1.0.0", + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-epoch", + "crossbeam-queue", + "crossbeam-utils", +] + [[package]] name = "crossbeam-channel" version = "0.5.4" @@ -916,6 +931,16 @@ dependencies = [ "scopeguard", ] +[[package]] +name = "crossbeam-queue" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f25d8400f4a7a5778f0e4e52384a48cbd9b5c495d110786187fc750075277a2" +dependencies = [ + "cfg-if 1.0.0", + "crossbeam-utils", +] + [[package]] name = "crossbeam-utils" version = "0.8.8" @@ -969,9 +994,9 @@ dependencies = [ [[package]] name = "curl" -version = "0.4.41" +version = "0.4.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bc6d233563261f8db6ffb83bbaad5a73837a6e6b28868e926337ebbdece0be3" +checksum = "37d855aeef205b43f65a5001e0997d81f8efca7badad4fad7d897aa7f0d0651f" dependencies = [ "curl-sys", "libc", @@ -984,9 +1009,9 @@ dependencies = [ [[package]] name = "curl-sys" -version = "0.4.51+curl-7.80.0" +version = "0.4.55+curl-7.83.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d130987e6a6a34fe0889e1083022fa48cd90e6709a84be3fb8dd95801de5af20" +checksum = "23734ec77368ec583c2e61dd3f0b0e5c98b93abe6d2a004ca06b91dd7e3e2762" dependencies = [ "cc", "libc", @@ -1816,9 +1841,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.8.0" +version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282a6247722caba404c065016bbfa522806e51714c34f5dfc3e4a3a46fcb4223" +checksum = "e6012d540c5baa3589337a98ce73408de9b5a25ec9fc2c6fd6be8f0d39e0ca5a" dependencies = [ "autocfg", "hashbrown 0.11.2", @@ -1896,6 +1921,17 @@ version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6" +[[package]] +name = "jemalloc-sys" +version = "0.5.0+5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f655c3ecfa6b0d03634595b4b54551d4bd5ac208b9e0124873949a7ab168f70b" +dependencies = [ + "cc", + "fs_extra", + "libc", +] + [[package]] name = "jobserver" version = "0.1.24" @@ -2041,15 +2077,6 @@ dependencies = [ "unicase", ] -[[package]] -name = "kstring" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b310ccceade8121d7d77fee406160e457c2f4e7c7982d589da3499bc7ea4526" -dependencies = [ - "serde", -] - [[package]] name = "kstring" version = "2.0.0" @@ -2073,9 +2100,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.125" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5916d2ae698f6de9bfb891ad7a8d65c09d232dc58cc4ac433c7da3b2fd84bc2b" +checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" dependencies = [ "rustc-std-workspace-core", ] @@ -2232,12 +2259,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" -[[package]] -name = "macro-utils" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e72f7deb758fea9ea7d290aebfa788763d0bffae12caa6406a25baaf8fa68a8" - [[package]] name = "maplit" version = "1.0.2" @@ -2369,12 +2390,9 @@ dependencies = [ [[package]] name = "minifier" -version = "0.0.43" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d81352bda6f4d04af1720afaa762054f66e16caffd93c1f86461a1c0ac4e695e" -dependencies = [ - "macro-utils", -] +checksum = "7071d17e2898e134cabf624f43cdefa0cedf57c739e964df3d0df9d028701a72" [[package]] name = "minimal-lexical" @@ -2421,17 +2439,18 @@ name = "miri" version = "0.1.0" dependencies = [ "colored", - "compiletest_rs", "env_logger 0.9.0", "getrandom 0.2.0", + "lazy_static", "libc", "log", "measureme 9.1.2", "rand 0.8.5", + "regex", "rustc-workspace-hack", - "rustc_version", "shell-escape", "smallvec", + "ui_test", ] [[package]] @@ -2872,6 +2891,18 @@ dependencies = [ "output_vt100", ] +[[package]] +name = "pretty_assertions" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c89f989ac94207d048d92db058e4f6ec7342b0971fc58d1271ca148b799b3563" +dependencies = [ + "ansi_term", + "ctor", + "diff", + "output_vt100", +] + [[package]] name = "pretty_env_logger" version = "0.4.0" @@ -3003,8 +3034,6 @@ dependencies = [ [[package]] name = "racer" version = "2.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64954e44fc0d1dcc64e0b9f2b155249ad62849eba25354b76ae1598d1e8f0fa0" dependencies = [ "bitflags", "clap 2.34.0", @@ -3012,10 +3041,28 @@ dependencies = [ "env_logger 0.7.1", "humantime 2.0.1", "lazy_static", + "lazycell", "log", + "racer-cargo-metadata", "rls-span", ] +[[package]] +name = "racer-cargo-metadata" +version = "0.1.2" +dependencies = [ + "racer-interner", + "serde", + "serde_json", +] + +[[package]] +name = "racer-interner" +version = "0.1.0" +dependencies = [ + "serde", +] + [[package]] name = "rand" version = "0.7.3" @@ -3116,9 +3163,9 @@ dependencies = [ [[package]] name = "rayon" -version = "1.5.1" +version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06aca804d41dbc8ba42dfd964f0d01334eceb64314b9ecf7c5fad5188a06d90" +checksum = "bd99e5772ead8baa5215278c9b15bf92087709e9c1b2d1f97cdb5a183c933a7d" dependencies = [ "autocfg", "crossbeam-deque", @@ -3128,14 +3175,13 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.9.1" +version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d78120e2c850279833f1dd3582f730c4ab53ed95aeaaaa862a2a5c71b1656d8e" +checksum = "258bcdb5ac6dad48491bb2992db6b7cf74878b0384908af124823d118c99683f" dependencies = [ "crossbeam-channel", "crossbeam-deque", "crossbeam-utils", - "lazy_static", "num_cpus", ] @@ -3246,7 +3292,7 @@ dependencies = [ "tokio-stream", "tokio-util", "toml", - "toml_edit 0.13.4", + "toml_edit", "url 2.2.2", "walkdir", ] @@ -3361,17 +3407,18 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" name = "rustc-main" version = "0.0.0" dependencies = [ + "jemalloc-sys", "rustc_codegen_ssa", "rustc_driver", - "tikv-jemalloc-sys", ] [[package]] name = "rustc-rayon" -version = "0.3.2" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9974ab223660e61c1b4e7b43b827379df286736ca988308ce7e16f59f2d89246" +checksum = "1a79f0b0b2609e2eacf9758013f50e7176cb4b29fd6436a747b14a5362c8727a" dependencies = [ + "autocfg", "crossbeam-deque", "either", "rustc-rayon-core", @@ -3379,13 +3426,13 @@ dependencies = [ [[package]] name = "rustc-rayon-core" -version = "0.3.2" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "564bfd27be8db888d0fa76aa4335e7851aaed0c2c11ad1e93aeb9349f6b88500" +checksum = "02269144a0db9bb55cf5d4a41a5a0e95b334b0b78b08269018ca9b0250718c30" dependencies = [ + "crossbeam-channel", "crossbeam-deque", "crossbeam-utils", - "lazy_static", "num_cpus", ] @@ -3666,6 +3713,7 @@ dependencies = [ "rustc_span", "rustc_target", "rustc_trait_selection", + "rustc_type_ir", "tracing", ] @@ -3959,6 +4007,7 @@ dependencies = [ "rustc_span", "rustc_target", "rustc_trait_selection", + "rustc_type_ir", "tracing", "unicode-security", ] @@ -4000,10 +4049,14 @@ dependencies = [ name = "rustc_macros" version = "0.1.0" dependencies = [ + "annotate-snippets", + "fluent-bundle", + "fluent-syntax", "proc-macro2", "quote", "syn", "synstructure", + "unic-langid", ] [[package]] @@ -4027,6 +4080,7 @@ dependencies = [ "rustc_session", "rustc_span", "rustc_target", + "rustc_type_ir", "smallvec", "snap", "tracing", @@ -4248,6 +4302,7 @@ dependencies = [ "rustc_serialize", "rustc_session", "rustc_span", + "rustc_type_ir", "tracing", ] @@ -4269,6 +4324,7 @@ dependencies = [ "rustc_session", "rustc_span", "rustc_target", + "rustc_type_ir", "smallvec", "tracing", ] @@ -4458,6 +4514,7 @@ dependencies = [ "rustc_span", "rustc_target", "rustc_trait_selection", + "rustc_type_ir", "tracing", ] @@ -4470,6 +4527,7 @@ dependencies = [ "rustc_index", "rustc_macros", "rustc_serialize", + "smallvec", ] [[package]] @@ -4495,6 +4553,7 @@ dependencies = [ "rustc_target", "rustc_trait_selection", "rustc_ty_utils", + "rustc_type_ir", "smallvec", "tracing", ] @@ -5235,17 +5294,6 @@ dependencies = [ name = "tier-check" version = "0.1.0" -[[package]] -name = "tikv-jemalloc-sys" -version = "0.4.1+5.2.1-patched" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a26331b05179d4cb505c8d6814a7e18d298972f0a551b0e3cefccff927f86d3" -dependencies = [ - "cc", - "fs_extra", - "libc", -] - [[package]] name = "time" version = "0.1.43" @@ -5320,19 +5368,6 @@ dependencies = [ "serde", ] -[[package]] -name = "toml_edit" -version = "0.13.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "744e9ed5b352340aa47ce033716991b5589e23781acb97cad37d4ea70560f55b" -dependencies = [ - "combine", - "indexmap", - "itertools", - "kstring 1.0.6", - "serde", -] - [[package]] name = "toml_edit" version = "0.14.3" @@ -5342,7 +5377,7 @@ dependencies = [ "combine", "indexmap", "itertools", - "kstring 2.0.0", + "kstring", "serde", ] @@ -5464,6 +5499,20 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" +[[package]] +name = "ui_test" +version = "0.1.0" +dependencies = [ + "colored", + "crossbeam", + "lazy_static", + "pretty_assertions 1.2.1", + "regex", + "rustc_version", + "serde", + "serde_json", +] + [[package]] name = "unic-char-property" version = "0.9.0" diff --git a/RELEASES.md b/RELEASES.md index 0965e37574d07..0e118fb939ff0 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,3 +1,129 @@ +Version 1.61.0 (2022-05-19) +========================== + +Language +-------- + +- [`const fn` signatures can now include generic trait bounds][93827] +- [`const fn` signatures can now use `impl Trait` in argument and return position][93827] +- [Function pointers can now be created, cast, and passed around in a `const fn`][93827] +- [Recursive calls can now set the value of a function's opaque `impl Trait` return type][94081] + +Compiler +-------- + +- [Linking modifier syntax in `#[link]` attributes and on the command line, as well as the `whole-archive` modifier specifically, are now supported][93901] +- [The `char` type is now described as UTF-32 in debuginfo][89887] +- The [`#[target_feature]`][target_feature] attribute [can now be used with aarch64 features][90621] +- X86 [`#[target_feature = "adx"]` is now stable][93745] + +Libraries +--------- + +- [`ManuallyDrop` is now documented to have the same layout as `T`][88375] +- [`#[ignore = "…"]` messages are printed when running tests][92714] +- [Consistently show absent stdio handles on Windows as NULL handles][93263] +- [Make `std::io::stdio::lock()` return `'static` handles.][93965] Previously, the creation of locked handles to stdin/stdout/stderr would borrow the handles being locked, which prevented writing `let out = std::io::stdout().lock();` because `out` would outlive the return value of `stdout()`. Such code now works, eliminating a common pitfall that affected many Rust users. +- [`Vec::from_raw_parts` is now less restrictive about its inputs][95016] +- [`std::thread::available_parallelism` now takes cgroup quotas into account.][92697] Since `available_parallelism` is often used to create a thread pool for parallel computation, which may be CPU-bound for performance, `available_parallelism` will return a value consistent with the ability to use that many threads continuously, if possible. For instance, in a container with 8 virtual CPUs but quotas only allowing for 50% usage, `available_parallelism` will return 4. + +Stabilized APIs +--------------- + +- [`Pin::static_mut`] +- [`Pin::static_ref`] +- [`Vec::retain_mut`] +- [`VecDeque::retain_mut`] +- [`Write` for `Cursor<[u8; N]>`][cursor-write-array] +- [`std::os::unix::net::SocketAddr::from_pathname`] +- [`std::process::ExitCode`] and [`std::process::Termination`]. The stabilization of these two APIs now makes it possible for programs to return errors from `main` with custom exit codes. +- [`std::thread::JoinHandle::is_finished`] + +These APIs are now usable in const contexts: + +- [`<*const T>::offset` and `<*mut T>::offset`][ptr-offset] +- [`<*const T>::wrapping_offset` and `<*mut T>::wrapping_offset`][ptr-wrapping_offset] +- [`<*const T>::add` and `<*mut T>::add`][ptr-add] +- [`<*const T>::sub` and `<*mut T>::sub`][ptr-sub] +- [`<*const T>::wrapping_add` and `<*mut T>::wrapping_add`][ptr-wrapping_add] +- [`<*const T>::wrapping_sub` and `<*mut T>::wrapping_sub`][ptr-wrapping_sub] +- [`<[T]>::as_mut_ptr`][slice-as_mut_ptr] +- [`<[T]>::as_ptr_range`][slice-as_ptr_range] +- [`<[T]>::as_mut_ptr_range`][slice-as_mut_ptr_range] + +Cargo +----- + +No feature changes, but see compatibility notes. + +Compatibility Notes +------------------- + +- Previously native static libraries were linked as `whole-archive` in some cases, but now rustc tries not to use `whole-archive` unless explicitly requested. This [change][93901] may result in linking errors in some cases. To fix such errors, native libraries linked from the command line, build scripts, or [`#[link]` attributes][link-attr] need to + - (more common) either be reordered to respect dependencies between them (if `a` depends on `b` then `a` should go first and `b` second) + - (less common) or be updated to use the [`+whole-archive`] modifier. +- [Catching a second unwind from FFI code while cleaning up from a Rust panic now causes the process to abort][92911] +- [Proc macros no longer see `ident` matchers wrapped in groups][92472] +- [The number of `#` in `r#` raw string literals is now required to be less than 256][95251] +- [When checking that a dyn type satisfies a trait bound, supertrait bounds are now enforced][92285] +- [`cargo vendor` now only accepts one value for each `--sync` flag][cargo/10448] +- [`cfg` predicates in `all()` and `any()` are always evaluated to detect errors, instead of short-circuiting.][94295] The compatibility considerations here arise in nightly-only code that used the short-circuiting behavior of `all` to write something like `cfg(all(feature = "nightly", syntax-requiring-nightly))`, which will now fail to compile. Instead, use either `cfg_attr(feature = "nightly", ...)` or nested uses of `cfg`. +- [bootstrap: static-libstdcpp is now enabled by default, and can now be disabled when llvm-tools is enabled][94832] + +Internal Changes +---------------- + +These changes provide no direct user facing benefits, but represent significant +improvements to the internals and overall performance of rustc +and related tools. + +- [debuginfo: Refactor debuginfo generation for types][94261] +- [Remove the everybody loops pass][93913] + +[88375]: https://github.com/rust-lang/rust/pull/88375/ +[89887]: https://github.com/rust-lang/rust/pull/89887/ +[90621]: https://github.com/rust-lang/rust/pull/90621/ +[92285]: https://github.com/rust-lang/rust/pull/92285/ +[92472]: https://github.com/rust-lang/rust/pull/92472/ +[92697]: https://github.com/rust-lang/rust/pull/92697/ +[92714]: https://github.com/rust-lang/rust/pull/92714/ +[92911]: https://github.com/rust-lang/rust/pull/92911/ +[93263]: https://github.com/rust-lang/rust/pull/93263/ +[93745]: https://github.com/rust-lang/rust/pull/93745/ +[93827]: https://github.com/rust-lang/rust/pull/93827/ +[93901]: https://github.com/rust-lang/rust/pull/93901/ +[93913]: https://github.com/rust-lang/rust/pull/93913/ +[93965]: https://github.com/rust-lang/rust/pull/93965/ +[94081]: https://github.com/rust-lang/rust/pull/94081/ +[94261]: https://github.com/rust-lang/rust/pull/94261/ +[94295]: https://github.com/rust-lang/rust/pull/94295/ +[94832]: https://github.com/rust-lang/rust/pull/94832/ +[95016]: https://github.com/rust-lang/rust/pull/95016/ +[95251]: https://github.com/rust-lang/rust/pull/95251/ +[`+whole-archive`]: https://doc.rust-lang.org/stable/rustc/command-line-arguments.html#linking-modifiers-whole-archive +[`Pin::static_mut`]: https://doc.rust-lang.org/stable/std/pin/struct.Pin.html#method.static_mut +[`Pin::static_ref`]: https://doc.rust-lang.org/stable/std/pin/struct.Pin.html#method.static_ref +[`Vec::retain_mut`]: https://doc.rust-lang.org/stable/std/vec/struct.Vec.html#method.retain_mut +[`VecDeque::retain_mut`]: https://doc.rust-lang.org/stable/std/collections/struct.VecDeque.html#method.retain_mut +[`std::os::unix::net::SocketAddr::from_pathname`]: https://doc.rust-lang.org/stable/std/os/unix/net/struct.SocketAddr.html#method.from_pathname +[`std::process::ExitCode`]: https://doc.rust-lang.org/stable/std/process/struct.ExitCode.html +[`std::process::Termination`]: https://doc.rust-lang.org/stable/std/process/trait.Termination.html +[`std::thread::JoinHandle::is_finished`]: https://doc.rust-lang.org/stable/std/thread/struct.JoinHandle.html#method.is_finished +[cargo/10448]: https://github.com/rust-lang/cargo/pull/10448/ +[cursor-write-array]: https://doc.rust-lang.org/stable/std/io/struct.Cursor.html#impl-Write-4 +[link-attr]: https://doc.rust-lang.org/stable/reference/items/external-blocks.html#the-link-attribute +[ptr-add]: https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.add +[ptr-offset]: https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.offset +[ptr-sub]: https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.sub +[ptr-wrapping_add]: https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.wrapping_add +[ptr-wrapping_offset]: https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.wrapping_offset +[ptr-wrapping_sub]: https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.wrapping_sub +[slice-as_mut_ptr]: https://doc.rust-lang.org/stable/std/primitive.slice.html#method.as_mut_ptr +[slice-as_mut_ptr_range]: https://doc.rust-lang.org/stable/std/primitive.slice.html#method.as_mut_ptr_range +[slice-as_ptr_range]: https://doc.rust-lang.org/stable/std/primitive.slice.html#method.as_ptr_range +[target_feature]: https://doc.rust-lang.org/reference/attributes/codegen.html#the-target_feature-attribute + + Version 1.60.0 (2022-04-07) ========================== diff --git a/compiler/rustc/Cargo.toml b/compiler/rustc/Cargo.toml index b642e891956cb..5e0bb1a7f95d1 100644 --- a/compiler/rustc/Cargo.toml +++ b/compiler/rustc/Cargo.toml @@ -10,13 +10,13 @@ rustc_driver = { path = "../rustc_driver" } # crate is intended to be used by codegen backends, which may not be in-tree. rustc_codegen_ssa = { path = "../rustc_codegen_ssa" } -[dependencies.tikv-jemalloc-sys] -version = '0.4.0' +[dependencies.jemalloc-sys] +version = "0.5.0" optional = true features = ['unprefixed_malloc_on_supported_platforms'] [features] -jemalloc = ['tikv-jemalloc-sys'] +jemalloc = ['jemalloc-sys'] llvm = ['rustc_driver/llvm'] max_level_info = ['rustc_driver/max_level_info'] rustc_use_parallel_compiler = ['rustc_driver/rustc_use_parallel_compiler'] diff --git a/compiler/rustc/src/main.rs b/compiler/rustc/src/main.rs index 4edd095af10b5..0de1a78191353 100644 --- a/compiler/rustc/src/main.rs +++ b/compiler/rustc/src/main.rs @@ -22,12 +22,10 @@ // The two crates we link to here, `std` and `rustc_driver`, are both dynamic // libraries. So we must reference jemalloc symbols one way or another, because // this file is the only object code in the rustc executable. -#[cfg(feature = "tikv-jemalloc-sys")] -use tikv_jemalloc_sys as jemalloc_sys; fn main() { // See the comment at the top of this file for an explanation of this. - #[cfg(feature = "tikv-jemalloc-sys")] + #[cfg(feature = "jemalloc-sys")] { use std::os::raw::{c_int, c_void}; diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 5a4c997ed9bfc..b81f7a2427076 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -23,8 +23,8 @@ pub use GenericArgs::*; pub use UnsafeSource::*; use crate::ptr::P; -use crate::token::{self, CommentKind, Delimiter, Token, TokenKind}; -use crate::tokenstream::{DelimSpan, LazyTokenStream, TokenStream, TokenTree}; +use crate::token::{self, CommentKind, Delimiter}; +use crate::tokenstream::{DelimSpan, LazyTokenStream, TokenStream}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::stack::ensure_sufficient_stack; @@ -444,8 +444,7 @@ impl Default for Generics { pub struct WhereClause { /// `true` if we ate a `where` token: this can happen /// if we parsed no predicates (e.g. `struct Foo where {}`). - /// This allows us to accurately pretty-print - /// in `nt_to_tokenstream` + /// This allows us to pretty-print accurately. pub has_where_token: bool, pub predicates: Vec, pub span: Span, @@ -1571,20 +1570,7 @@ impl MacArgs { match self { MacArgs::Empty => TokenStream::default(), MacArgs::Delimited(.., tokens) => tokens.clone(), - MacArgs::Eq(_, MacArgsEq::Ast(expr)) => { - // Currently only literals are allowed here. If more complex expression kinds are - // allowed in the future, then `nt_to_tokenstream` should be used to extract the - // token stream. This will require some cleverness, perhaps with a function - // pointer, because `nt_to_tokenstream` is not directly usable from this crate. - // It will also require changing the `parse_expr` call in `parse_mac_args_common` - // to `parse_expr_force_collect`. - if let ExprKind::Lit(lit) = &expr.kind { - let token = Token::new(TokenKind::Literal(lit.token), lit.span); - TokenTree::Token(token).into() - } else { - unreachable!("couldn't extract literal when getting inner tokens: {:?}", expr) - } - } + MacArgs::Eq(_, MacArgsEq::Ast(expr)) => TokenStream::from_ast(expr), MacArgs::Eq(_, MacArgsEq::Hir(lit)) => { unreachable!("in literal form when getting inner tokens: {:?}", lit) } @@ -1976,6 +1962,8 @@ pub struct BareFnTy { pub ext: Extern, pub generic_params: Vec, pub decl: P, + /// Span of the `fn(...) -> ...` part. + pub decl_span: Span, } /// The various kinds of type recognized by the compiler. @@ -2564,15 +2552,6 @@ impl PolyTraitRef { } } -#[derive(Copy, Clone, Encodable, Decodable, Debug, HashStable_Generic)] -pub enum CrateSugar { - /// Source is `pub(crate)`. - PubCrate, - - /// Source is (just) `crate`. - JustCrate, -} - #[derive(Clone, Encodable, Decodable, Debug)] pub struct Visibility { pub kind: VisibilityKind, @@ -2583,7 +2562,6 @@ pub struct Visibility { #[derive(Clone, Encodable, Decodable, Debug)] pub enum VisibilityKind { Public, - Crate(CrateSugar), Restricted { path: P, id: NodeId }, Inherited, } diff --git a/compiler/rustc_ast/src/ast_traits.rs b/compiler/rustc_ast/src/ast_traits.rs index bd401ddbbee9f..5c30a75a140a4 100644 --- a/compiler/rustc_ast/src/ast_traits.rs +++ b/compiler/rustc_ast/src/ast_traits.rs @@ -108,7 +108,7 @@ macro_rules! impl_has_span { }; } -impl_has_span!(AssocItem, Expr, ForeignItem, Item, Stmt); +impl_has_span!(AssocItem, Block, Expr, ForeignItem, Item, Pat, Path, Stmt, Ty, Visibility); impl> HasSpan for T { fn span(&self) -> Span { @@ -116,6 +116,12 @@ impl> HasSpan for T { } } +impl HasSpan for AttrItem { + fn span(&self) -> Span { + self.span() + } +} + /// A trait for AST nodes having (or not having) collected tokens. pub trait HasTokens { fn tokens(&self) -> Option<&LazyTokenStream>; diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index 84654a9f73781..988918b0505e0 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -340,7 +340,7 @@ pub fn mk_nested_word_item(ident: Ident) -> NestedMetaItem { NestedMetaItem::MetaItem(mk_word_item(ident)) } -crate fn mk_attr_id() -> AttrId { +pub(crate) fn mk_attr_id() -> AttrId { use std::sync::atomic::AtomicU32; use std::sync::atomic::Ordering; @@ -552,7 +552,7 @@ impl MetaItemKind { ) -> Option { match tokens.next() { Some(TokenTree::Delimited(_, Delimiter::Invisible, inner_tokens)) => { - MetaItemKind::name_value_from_tokens(&mut inner_tokens.trees()) + MetaItemKind::name_value_from_tokens(&mut inner_tokens.into_trees()) } Some(TokenTree::Token(token)) => { Lit::from_token(&token).ok().map(MetaItemKind::NameValue) diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs index 124671691922a..2015d635e561b 100644 --- a/compiler/rustc_ast/src/lib.rs +++ b/compiler/rustc_ast/src/lib.rs @@ -12,7 +12,6 @@ #![feature(box_patterns)] #![feature(const_default_impls)] #![feature(const_trait_impl)] -#![feature(crate_visibility_modifier)] #![feature(if_let_guard)] #![feature(label_break_value)] #![feature(let_chains)] diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index b425b5e2cca52..85bb52964865b 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -460,10 +460,11 @@ pub fn noop_visit_ty(ty: &mut P, vis: &mut T) { vis.visit_mt(mt); } TyKind::BareFn(bft) => { - let BareFnTy { unsafety, ext: _, generic_params, decl } = bft.deref_mut(); + let BareFnTy { unsafety, ext: _, generic_params, decl, decl_span } = bft.deref_mut(); visit_unsafety(unsafety, vis); generic_params.flat_map_in_place(|param| vis.flat_map_generic_param(param)); vis.visit_fn_decl(decl); + vis.visit_span(decl_span); } TyKind::Tup(tys) => visit_vec(tys, |ty| vis.visit_ty(ty)), TyKind::Paren(ty) => vis.visit_ty(ty), @@ -1468,7 +1469,7 @@ pub fn noop_flat_map_stmt_kind( pub fn noop_visit_vis(visibility: &mut Visibility, vis: &mut T) { match &mut visibility.kind { - VisibilityKind::Public | VisibilityKind::Crate(_) | VisibilityKind::Inherited => {} + VisibilityKind::Public | VisibilityKind::Inherited => {} VisibilityKind::Restricted { path, id } => { vis.visit_path(path); vis.visit_id(id); diff --git a/compiler/rustc_ast/src/ptr.rs b/compiler/rustc_ast/src/ptr.rs index 89a0857992e49..bab85a3019d61 100644 --- a/compiler/rustc_ast/src/ptr.rs +++ b/compiler/rustc_ast/src/ptr.rs @@ -10,7 +10,7 @@ //! //! * **Immutability**: `P` disallows mutating its inner `T`, unlike `Box` //! (unless it contains an `Unsafe` interior, but that may be denied later). -//! This mainly prevents mistakes, but can also enforces a kind of "purity". +//! This mainly prevents mistakes, but also enforces a kind of "purity". //! //! * **Efficiency**: folding can reuse allocation space for `P` and `Vec`, //! the latter even when the input and output types differ (as it would be the diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index 35eca23a11625..1522d12cbf92e 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -134,7 +134,7 @@ impl LitKind { } } - crate fn may_have_suffix(self) -> bool { + pub(crate) fn may_have_suffix(self) -> bool { matches!(self, Integer | Float | Err) } } diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs index a8f29f334070e..c58fe7287bf79 100644 --- a/compiler/rustc_ast/src/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -13,7 +13,9 @@ //! and a borrowed `TokenStream` is sufficient to build an owned `TokenStream` without taking //! ownership of the original. -use crate::token::{self, Delimiter, Token, TokenKind}; +use crate::ast::StmtKind; +use crate::ast_traits::{HasAttrs, HasSpan, HasTokens}; +use crate::token::{self, Delimiter, Nonterminal, Token, TokenKind}; use crate::AttrVec; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; @@ -45,12 +47,6 @@ pub enum TokenTree { Delimited(DelimSpan, Delimiter, TokenStream), } -#[derive(Copy, Clone)] -pub enum CanSynthesizeMissingTokens { - Yes, - No, -} - // Ensure all fields of `TokenTree` is `Send` and `Sync`. #[cfg(parallel_compiler)] fn _dummy() @@ -442,8 +438,8 @@ impl TokenStream { } } - pub fn trees(&self) -> Cursor { - self.clone().into_trees() + pub fn trees(&self) -> CursorRef<'_> { + CursorRef::new(self) } pub fn into_trees(self) -> Cursor { @@ -471,6 +467,89 @@ impl TokenStream { .collect(), )) } + + fn opt_from_ast(node: &(impl HasAttrs + HasTokens)) -> Option { + let tokens = node.tokens()?; + let attrs = node.attrs(); + let attr_annotated = if attrs.is_empty() { + tokens.create_token_stream() + } else { + let attr_data = AttributesData { attrs: attrs.to_vec().into(), tokens: tokens.clone() }; + AttrAnnotatedTokenStream::new(vec![( + AttrAnnotatedTokenTree::Attributes(attr_data), + Spacing::Alone, + )]) + }; + Some(attr_annotated.to_tokenstream()) + } + + pub fn from_ast(node: &(impl HasAttrs + HasSpan + HasTokens + fmt::Debug)) -> TokenStream { + TokenStream::opt_from_ast(node) + .unwrap_or_else(|| panic!("missing tokens for node at {:?}: {:?}", node.span(), node)) + } + + pub fn from_nonterminal_ast(nt: &Nonterminal) -> TokenStream { + match nt { + Nonterminal::NtIdent(ident, is_raw) => { + TokenTree::token(token::Ident(ident.name, *is_raw), ident.span).into() + } + Nonterminal::NtLifetime(ident) => { + TokenTree::token(token::Lifetime(ident.name), ident.span).into() + } + Nonterminal::NtItem(item) => TokenStream::from_ast(item), + Nonterminal::NtBlock(block) => TokenStream::from_ast(block), + Nonterminal::NtStmt(stmt) if let StmtKind::Empty = stmt.kind => { + // FIXME: Properly collect tokens for empty statements. + TokenTree::token(token::Semi, stmt.span).into() + } + Nonterminal::NtStmt(stmt) => TokenStream::from_ast(stmt), + Nonterminal::NtPat(pat) => TokenStream::from_ast(pat), + Nonterminal::NtTy(ty) => TokenStream::from_ast(ty), + Nonterminal::NtMeta(attr) => TokenStream::from_ast(attr), + Nonterminal::NtPath(path) => TokenStream::from_ast(path), + Nonterminal::NtVis(vis) => TokenStream::from_ast(vis), + Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => TokenStream::from_ast(expr), + } + } + + fn flatten_token(token: &Token) -> TokenTree { + match &token.kind { + token::Interpolated(nt) if let token::NtIdent(ident, is_raw) = **nt => { + TokenTree::token(token::Ident(ident.name, is_raw), ident.span) + } + token::Interpolated(nt) => TokenTree::Delimited( + DelimSpan::from_single(token.span), + Delimiter::Invisible, + TokenStream::from_nonterminal_ast(&nt).flattened(), + ), + _ => TokenTree::Token(token.clone()), + } + } + + fn flatten_token_tree(tree: &TokenTree) -> TokenTree { + match tree { + TokenTree::Token(token) => TokenStream::flatten_token(token), + TokenTree::Delimited(span, delim, tts) => { + TokenTree::Delimited(*span, *delim, tts.flattened()) + } + } + } + + #[must_use] + pub fn flattened(&self) -> TokenStream { + fn can_skip(stream: &TokenStream) -> bool { + stream.trees().all(|tree| match tree { + TokenTree::Token(token) => !matches!(token.kind, token::Interpolated(_)), + TokenTree::Delimited(_, _, inner) => can_skip(inner), + }) + } + + if can_skip(self) { + return self.clone(); + } + + self.trees().map(|tree| TokenStream::flatten_token_tree(tree)).collect() + } } // 99.5%+ of the time we have 1 or 2 elements in this vector. @@ -538,12 +617,21 @@ pub struct CursorRef<'t> { } impl<'t> CursorRef<'t> { + fn new(stream: &'t TokenStream) -> Self { + CursorRef { stream, index: 0 } + } + + #[inline] fn next_with_spacing(&mut self) -> Option<&'t TreeAndSpacing> { self.stream.0.get(self.index).map(|tree| { self.index += 1; tree }) } + + pub fn look_ahead(&self, n: usize) -> Option<&TokenTree> { + self.stream.0[self.index..].get(n).map(|(tree, _)| tree) + } } impl<'t> Iterator for CursorRef<'t> { diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index cc772ac74f251..2ce8590d7718f 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -89,6 +89,16 @@ impl<'a> FnKind<'a> { } } +#[derive(Copy, Clone, Debug)] +pub enum LifetimeCtxt { + /// Appears in a reference type. + Rptr, + /// Appears as a bound on a type or another lifetime. + Bound, + /// Appears as a generic argument. + GenericArg, +} + /// Each method of the `Visitor` trait is a hook to be potentially /// overridden. Each method's default implementation recursively visits /// the substructure of the input via the corresponding `walk` method; @@ -184,7 +194,7 @@ pub trait Visitor<'ast>: Sized { fn visit_label(&mut self, label: &'ast Label) { walk_label(self, label) } - fn visit_lifetime(&mut self, lifetime: &'ast Lifetime) { + fn visit_lifetime(&mut self, lifetime: &'ast Lifetime, _: LifetimeCtxt) { walk_lifetime(self, lifetime) } fn visit_mac_call(&mut self, mac: &'ast MacCall) { @@ -326,7 +336,7 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) { ItemKind::ForeignMod(ref foreign_module) => { walk_list!(visitor, visit_foreign_item, &foreign_module.items); } - ItemKind::GlobalAsm(ref asm) => walk_inline_asm(visitor, asm), + ItemKind::GlobalAsm(ref asm) => visitor.visit_inline_asm(asm), ItemKind::TyAlias(box TyAlias { ref generics, ref bounds, ref ty, .. }) => { visitor.visit_generics(generics); walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound); @@ -414,7 +424,7 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) { TyKind::Slice(ref ty) | TyKind::Paren(ref ty) => visitor.visit_ty(ty), TyKind::Ptr(ref mutable_type) => visitor.visit_ty(&mutable_type.ty), TyKind::Rptr(ref opt_lifetime, ref mutable_type) => { - walk_list!(visitor, visit_lifetime, opt_lifetime); + walk_list!(visitor, visit_lifetime, opt_lifetime, LifetimeCtxt::Rptr); visitor.visit_ty(&mutable_type.ty) } TyKind::Tup(ref tuple_element_types) => { @@ -507,7 +517,7 @@ where V: Visitor<'a>, { match generic_arg { - GenericArg::Lifetime(lt) => visitor.visit_lifetime(lt), + GenericArg::Lifetime(lt) => visitor.visit_lifetime(lt, LifetimeCtxt::GenericArg), GenericArg::Type(ty) => visitor.visit_ty(ty), GenericArg::Const(ct) => visitor.visit_anon_const(ct), } @@ -599,7 +609,9 @@ pub fn walk_foreign_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a ForeignI pub fn walk_param_bound<'a, V: Visitor<'a>>(visitor: &mut V, bound: &'a GenericBound) { match *bound { GenericBound::Trait(ref typ, ref modifier) => visitor.visit_poly_trait_ref(typ, modifier), - GenericBound::Outlives(ref lifetime) => visitor.visit_lifetime(lifetime), + GenericBound::Outlives(ref lifetime) => { + visitor.visit_lifetime(lifetime, LifetimeCtxt::Bound) + } } } @@ -639,7 +651,7 @@ pub fn walk_where_predicate<'a, V: Visitor<'a>>(visitor: &mut V, predicate: &'a WherePredicate::RegionPredicate(WhereRegionPredicate { ref lifetime, ref bounds, .. }) => { - visitor.visit_lifetime(lifetime); + visitor.visit_lifetime(lifetime, LifetimeCtxt::Bound); walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound); } WherePredicate::EqPredicate(WhereEqPredicate { ref lhs_ty, ref rhs_ty, .. }) => { @@ -897,7 +909,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) { } ExprKind::MacCall(ref mac) => visitor.visit_mac_call(mac), ExprKind::Paren(ref subexpression) => visitor.visit_expr(subexpression), - ExprKind::InlineAsm(ref asm) => walk_inline_asm(visitor, asm), + ExprKind::InlineAsm(ref asm) => visitor.visit_inline_asm(asm), ExprKind::Yield(ref optional_expression) => { walk_list!(visitor, visit_expr, optional_expression); } diff --git a/compiler/rustc_ast_lowering/src/asm.rs b/compiler/rustc_ast_lowering/src/asm.rs index ae3e367596258..6c055645ef3e9 100644 --- a/compiler/rustc_ast_lowering/src/asm.rs +++ b/compiler/rustc_ast_lowering/src/asm.rs @@ -17,7 +17,11 @@ use std::collections::hash_map::Entry; use std::fmt::Write; impl<'a, 'hir> LoweringContext<'a, 'hir> { - crate fn lower_inline_asm(&mut self, sp: Span, asm: &InlineAsm) -> &'hir hir::InlineAsm<'hir> { + pub(crate) fn lower_inline_asm( + &mut self, + sp: Span, + asm: &InlineAsm, + ) -> &'hir hir::InlineAsm<'hir> { // Rustdoc needs to support asm! from foreign architectures: don't try // lowering the register constraints in this case. let asm_arch = if self.sess.opts.actually_rustdoc { None } else { self.sess.asm_arch }; diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 410ed3f0bdcdd..3aff04f78fb85 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -505,8 +505,14 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_arm(&mut self, arm: &Arm) -> hir::Arm<'hir> { let pat = self.lower_pat(&arm.pat); let guard = arm.guard.as_ref().map(|cond| { - if let ExprKind::Let(ref pat, ref scrutinee, _) = cond.kind { - hir::Guard::IfLet(self.lower_pat(pat), self.lower_expr(scrutinee)) + if let ExprKind::Let(ref pat, ref scrutinee, span) = cond.kind { + hir::Guard::IfLet(self.arena.alloc(hir::Let { + hir_id: self.next_id(), + span: self.lower_span(span), + pat: self.lower_pat(pat), + ty: None, + init: self.lower_expr(scrutinee), + })) } else { hir::Guard::If(self.lower_expr(cond)) } diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index cf97b270ed8f9..12d1b8404eb8b 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -13,7 +13,6 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID}; use rustc_hir::PredicateOrigin; use rustc_index::vec::{Idx, IndexVec}; -use rustc_session::utils::NtToTokenstream; use rustc_session::Session; use rustc_span::source_map::DesugaringKind; use rustc_span::symbol::{kw, sym, Ident}; @@ -27,7 +26,6 @@ use std::iter; pub(super) struct ItemLowerer<'a, 'hir> { pub(super) sess: &'a Session, pub(super) resolver: &'a mut dyn ResolverAstLowering, - pub(super) nt_to_tokenstream: NtToTokenstream, pub(super) arena: &'hir Arena<'hir>, pub(super) ast_index: &'a IndexVec>, pub(super) owners: &'a mut IndexVec>>, @@ -63,7 +61,6 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> { // Pseudo-globals. sess: &self.sess, resolver: self.resolver, - nt_to_tokenstream: self.nt_to_tokenstream, arena: self.arena, // HirId handling. @@ -848,7 +845,7 @@ impl<'hir> LoweringContext<'_, 'hir> { } /// Construct `ExprKind::Err` for the given `span`. - crate fn expr_err(&mut self, span: Span) -> hir::Expr<'hir> { + pub(crate) fn expr_err(&mut self, span: Span) -> hir::Expr<'hir> { self.expr(span, hir::ExprKind::Err, AttrVec::new()) } diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index c143266f6c1de..e59bc9aa6b399 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -30,7 +30,6 @@ //! get confused if the spans from leaf AST nodes occur in multiple places //! in the HIR, especially for multiple identifiers. -#![feature(crate_visibility_modifier)] #![feature(box_patterns)] #![feature(let_chains)] #![feature(let_else)] @@ -38,7 +37,6 @@ #![recursion_limit = "256"] #![allow(rustc::potential_query_instability)] -use rustc_ast::tokenstream::{CanSynthesizeMissingTokens, TokenStream}; use rustc_ast::visit; use rustc_ast::{self as ast, *}; use rustc_ast_pretty::pprust; @@ -57,7 +55,6 @@ use rustc_hir::{ConstArg, GenericArg, ItemLocalId, ParamName, TraitCandidate}; use rustc_index::vec::{Idx, IndexVec}; use rustc_query_system::ich::StableHashingContext; use rustc_session::parse::feature_err; -use rustc_session::utils::{FlattenNonterminals, NtToTokenstream}; use rustc_session::Session; use rustc_span::hygiene::{ExpnId, MacroKind}; use rustc_span::source_map::DesugaringKind; @@ -90,11 +87,6 @@ struct LoweringContext<'a, 'hir: 'a> { resolver: &'a mut dyn ResolverAstLowering, - /// HACK(Centril): there is a cyclic dependency between the parser and lowering - /// if we don't have this function pointer. To avoid that dependency so that - /// `rustc_middle` is independent of the parser, we use dynamic dispatch here. - nt_to_tokenstream: NtToTokenstream, - /// Used to allocate HIR nodes. arena: &'hir Arena<'hir>, @@ -437,7 +429,6 @@ pub fn lower_crate<'a, 'hir>( sess: &'a Session, krate: &'a Crate, resolver: &'a mut dyn ResolverAstLowering, - nt_to_tokenstream: NtToTokenstream, arena: &'hir Arena<'hir>, ) -> &'hir hir::Crate<'hir> { let _prof_timer = sess.prof.verbose_generic_activity("hir_lowering"); @@ -448,15 +439,8 @@ pub fn lower_crate<'a, 'hir>( IndexVec::from_fn_n(|_| hir::MaybeOwner::Phantom, resolver.definitions().def_index_count()); for def_id in ast_index.indices() { - item::ItemLowerer { - sess, - resolver, - nt_to_tokenstream, - arena, - ast_index: &ast_index, - owners: &mut owners, - } - .lower_node(def_id); + item::ItemLowerer { sess, resolver, arena, ast_index: &ast_index, owners: &mut owners } + .lower_node(def_id); } let hir_hash = compute_hir_hash(resolver, &owners); @@ -876,11 +860,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // ``` // // In both cases, we don't want to synthesize any tokens - MacArgs::Delimited( - dspan, - delim, - self.lower_token_stream(tokens.clone(), CanSynthesizeMissingTokens::No), - ) + MacArgs::Delimited(dspan, delim, tokens.flattened()) } // This is an inert key-value attribute - it will never be visible to macros // after it gets lowered to HIR. Therefore, we can extract literals to handle @@ -905,19 +885,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } } - fn lower_token_stream( - &self, - tokens: TokenStream, - synthesize_tokens: CanSynthesizeMissingTokens, - ) -> TokenStream { - FlattenNonterminals { - parse_sess: &self.sess.parse_sess, - synthesize_tokens, - nt_to_tokenstream: self.nt_to_tokenstream, - } - .process_token_stream(tokens) - } - /// Given an associated type constraint like one of these: /// /// ```ignore (illustrative) @@ -1169,15 +1136,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { TyKind::Ptr(ref mt) => hir::TyKind::Ptr(self.lower_mt(mt, itctx)), TyKind::Rptr(ref region, ref mt) => { let region = region.unwrap_or_else(|| { - let Some(LifetimeRes::ElidedAnchor { start, end }) = self.resolver.get_lifetime_res(t.id) else { - panic!() + let id = if let Some(LifetimeRes::ElidedAnchor { start, end }) = + self.resolver.get_lifetime_res(t.id) + { + debug_assert_eq!(start.plus(1), end); + start + } else { + self.resolver.next_node_id() }; - debug_assert_eq!(start.plus(1), end); let span = self.sess.source_map().next_point(t.span.shrink_to_lo()); - Lifetime { - ident: Ident::new(kw::UnderscoreLifetime, span), - id: start, - } + Lifetime { ident: Ident::new(kw::UnderscoreLifetime, span), id } }); let lifetime = self.lower_lifetime(®ion); hir::TyKind::Rptr(lifetime, self.lower_mt(mt, itctx)) @@ -1836,10 +1804,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn lower_lifetime(&mut self, l: &Lifetime) -> hir::Lifetime { let span = self.lower_span(l.ident.span); let ident = self.lower_ident(l.ident); - let res = self - .resolver - .get_lifetime_res(l.id) - .unwrap_or_else(|| panic!("Missing resolution for lifetime {:?} at {:?}", l, span)); + let res = self.resolver.get_lifetime_res(l.id).unwrap_or(LifetimeRes::Error); self.new_named_lifetime_with_res(l.id, span, ident, res) } diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index 2c331767b8958..e27bc7a0f472f 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -12,11 +12,11 @@ use rustc_span::symbol::Ident; use rustc_span::{source_map::Spanned, Span}; impl<'a, 'hir> LoweringContext<'a, 'hir> { - crate fn lower_pat(&mut self, pattern: &Pat) -> &'hir hir::Pat<'hir> { + pub(crate) fn lower_pat(&mut self, pattern: &Pat) -> &'hir hir::Pat<'hir> { self.arena.alloc(self.lower_pat_mut(pattern)) } - crate fn lower_pat_mut(&mut self, mut pattern: &Pat) -> hir::Pat<'hir> { + pub(crate) fn lower_pat_mut(&mut self, mut pattern: &Pat) -> hir::Pat<'hir> { ensure_sufficient_stack(|| { // loop here to avoid recursion let node = loop { @@ -290,7 +290,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } /// Emit a friendly error for extra `..` patterns in a tuple/tuple struct/slice pattern. - crate fn ban_extra_rest_pat(&self, sp: Span, prev_sp: Span, ctx: &str) { + pub(crate) fn ban_extra_rest_pat(&self, sp: Span, prev_sp: Span, ctx: &str) { self.diagnostic() .struct_span_err(sp, &format!("`..` can only be used once per {} pattern", ctx)) .span_label(sp, &format!("can only be used once per {} pattern", ctx)) diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs index 3c9399c1fdf80..7fc8aac5116f9 100644 --- a/compiler/rustc_ast_lowering/src/path.rs +++ b/compiler/rustc_ast_lowering/src/path.rs @@ -15,7 +15,7 @@ use smallvec::smallvec; use tracing::debug; impl<'a, 'hir> LoweringContext<'a, 'hir> { - crate fn lower_qpath( + pub(crate) fn lower_qpath( &mut self, id: NodeId, qself: &Option, @@ -142,7 +142,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ); } - crate fn lower_path_extra( + pub(crate) fn lower_path_extra( &mut self, res: Res, p: &Path, @@ -163,7 +163,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { }) } - crate fn lower_path( + pub(crate) fn lower_path( &mut self, id: NodeId, p: &Path, @@ -174,7 +174,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.lower_path_extra(res, p, param_mode) } - crate fn lower_path_segment( + pub(crate) fn lower_path_segment( &mut self, path_span: Span, segment: &PathSegment, @@ -381,7 +381,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } /// An associated type binding `Output = $ty`. - crate fn output_ty_binding( + pub(crate) fn output_ty_binding( &mut self, span: Span, ty: &'hir hir::Ty<'hir>, diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 058a0f975a7b3..0520c9ac60cf0 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -1070,7 +1070,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { visit::walk_label(self, label); } - fn visit_lifetime(&mut self, lifetime: &'a Lifetime) { + fn visit_lifetime(&mut self, lifetime: &'a Lifetime, _: visit::LifetimeCtxt) { self.check_lifetime(lifetime.ident); visit::walk_lifetime(self, lifetime); } @@ -1463,10 +1463,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> { if let GenericBound::Trait(ref poly, modify) = *bound { match (ctxt, modify) { (BoundKind::SuperTraits, TraitBoundModifier::Maybe) => { - let mut err = self.err_handler().struct_span_err( - poly.span, - &format!("`?Trait` is not permitted in supertraits"), - ); + let mut err = self + .err_handler() + .struct_span_err(poly.span, "`?Trait` is not permitted in supertraits"); let path_str = pprust::path_to_string(&poly.trait_ref.path); err.note(&format!("traits are `?{}` by default", path_str)); err.emit(); @@ -1474,7 +1473,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { (BoundKind::TraitObject, TraitBoundModifier::Maybe) => { let mut err = self.err_handler().struct_span_err( poly.span, - &format!("`?Trait` is not permitted in trait object types"), + "`?Trait` is not permitted in trait object types", ); err.emit(); } diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 2774bda24f148..f0b94047ed9da 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -697,18 +697,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { } visit::walk_assoc_item(self, i, ctxt) } - - fn visit_vis(&mut self, vis: &'a ast::Visibility) { - if let ast::VisibilityKind::Crate(ast::CrateSugar::JustCrate) = vis.kind { - gate_feature_post!( - &self, - crate_visibility_modifier, - vis.span, - "`crate` visibility modifier is experimental" - ); - } - visit::walk_vis(self, vis) - } } pub fn check_crate(krate: &ast::Crate, sess: &Session) { @@ -770,7 +758,6 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) { gate_all!(trait_alias, "trait aliases are experimental"); gate_all!(associated_type_bounds, "associated type bounds are unstable"); - gate_all!(crate_visibility_modifier, "`crate` visibility modifier is experimental"); gate_all!(decl_macro, "`macro` is experimental"); gate_all!(box_patterns, "box pattern syntax is experimental"); gate_all!(exclusive_range_pattern, "exclusive range pattern syntax is experimental"); diff --git a/compiler/rustc_ast_passes/src/node_count.rs b/compiler/rustc_ast_passes/src/node_count.rs index 48b79809c1b97..ee166f7570307 100644 --- a/compiler/rustc_ast_passes/src/node_count.rs +++ b/compiler/rustc_ast_passes/src/node_count.rs @@ -106,7 +106,7 @@ impl<'ast> Visitor<'ast> for NodeCounter { self.count += 1; walk_variant(self, v) } - fn visit_lifetime(&mut self, lifetime: &Lifetime) { + fn visit_lifetime(&mut self, lifetime: &Lifetime, _: visit::LifetimeCtxt) { self.count += 1; walk_lifetime(self, lifetime) } diff --git a/compiler/rustc_ast_pretty/src/lib.rs b/compiler/rustc_ast_pretty/src/lib.rs index 95beccbb728b7..79178830bf949 100644 --- a/compiler/rustc_ast_pretty/src/lib.rs +++ b/compiler/rustc_ast_pretty/src/lib.rs @@ -1,5 +1,4 @@ #![feature(associated_type_bounds)] -#![feature(crate_visibility_modifier)] #![feature(box_patterns)] #![feature(with_negative_coherence)] #![recursion_limit = "256"] diff --git a/compiler/rustc_ast_pretty/src/pprust/mod.rs b/compiler/rustc_ast_pretty/src/pprust/mod.rs index d2e2fd520cd41..ac9e7d06c4e40 100644 --- a/compiler/rustc_ast_pretty/src/pprust/mod.rs +++ b/compiler/rustc_ast_pretty/src/pprust/mod.rs @@ -4,42 +4,12 @@ mod tests; pub mod state; pub use state::{print_crate, AnnNode, Comments, PpAnn, PrintState, State}; +use rustc_ast as ast; use rustc_ast::token::{Nonterminal, Token, TokenKind}; use rustc_ast::tokenstream::{TokenStream, TokenTree}; -use rustc_ast::{self as ast, AstDeref}; use std::borrow::Cow; -pub trait AstPrettyPrint { - fn pretty_print(&self) -> String; -} - -impl> AstPrettyPrint for T { - fn pretty_print(&self) -> String { - self.ast_deref().pretty_print() - } -} - -macro_rules! impl_ast_pretty_print { - ($($T:ty => $method:ident),+ $(,)?) => { - $( - impl AstPrettyPrint for $T { - fn pretty_print(&self) -> String { - State::new().$method(self) - } - } - )+ - }; -} - -impl_ast_pretty_print! { - ast::Item => item_to_string, - ast::AssocItem => assoc_item_to_string, - ast::ForeignItem => foreign_item_to_string, - ast::Expr => expr_to_string, - ast::Stmt => stmt_to_string, -} - pub fn nonterminal_to_string(nt: &Nonterminal) -> String { State::new().nonterminal_to_string(nt) } diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index f520b54112464..7357ddf2134e4 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -95,7 +95,7 @@ pub struct State<'a> { ann: &'a (dyn PpAnn + 'a), } -crate const INDENT_UNIT: isize = 4; +pub(crate) const INDENT_UNIT: isize = 4; /// Requires you to pass an input filename and reader so that /// it can scan the input text for comments to copy forward. @@ -550,9 +550,9 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere fn print_tts(&mut self, tts: &TokenStream, convert_dollar_crate: bool) { let mut iter = tts.trees().peekable(); while let Some(tt) = iter.next() { - self.print_tt(&tt, convert_dollar_crate); + self.print_tt(tt, convert_dollar_crate); if let Some(next) = iter.peek() { - if tt_prepend_space(next, &tt) { + if tt_prepend_space(next, tt) { self.space(); } } @@ -955,8 +955,13 @@ impl<'a> State<'a> { State { s: pp::Printer::new(), comments: None, ann: &NoAnn } } - crate fn commasep_cmnt(&mut self, b: Breaks, elts: &[T], mut op: F, mut get_span: G) - where + pub(crate) fn commasep_cmnt( + &mut self, + b: Breaks, + elts: &[T], + mut op: F, + mut get_span: G, + ) where F: FnMut(&mut State<'_>, &T), G: FnMut(&T) -> rustc_span::Span, { @@ -976,7 +981,7 @@ impl<'a> State<'a> { self.end(); } - crate fn commasep_exprs(&mut self, b: Breaks, exprs: &[P]) { + pub(crate) fn commasep_exprs(&mut self, b: Breaks, exprs: &[P]) { self.commasep_cmnt(b, exprs, |s, e| s.print_expr(e), |e| e.span) } @@ -1109,7 +1114,7 @@ impl<'a> State<'a> { self.print_trait_ref(&t.trait_ref) } - crate fn print_stmt(&mut self, st: &ast::Stmt) { + pub(crate) fn print_stmt(&mut self, st: &ast::Stmt) { self.maybe_print_comment(st.span.lo()); match st.kind { ast::StmtKind::Local(ref loc) => { @@ -1164,19 +1169,19 @@ impl<'a> State<'a> { self.maybe_print_trailing_comment(st.span, None) } - crate fn print_block(&mut self, blk: &ast::Block) { + pub(crate) fn print_block(&mut self, blk: &ast::Block) { self.print_block_with_attrs(blk, &[]) } - crate fn print_block_unclosed_indent(&mut self, blk: &ast::Block) { + pub(crate) fn print_block_unclosed_indent(&mut self, blk: &ast::Block) { self.print_block_maybe_unclosed(blk, &[], false) } - crate fn print_block_with_attrs(&mut self, blk: &ast::Block, attrs: &[ast::Attribute]) { + pub(crate) fn print_block_with_attrs(&mut self, blk: &ast::Block, attrs: &[ast::Attribute]) { self.print_block_maybe_unclosed(blk, attrs, true) } - crate fn print_block_maybe_unclosed( + pub(crate) fn print_block_maybe_unclosed( &mut self, blk: &ast::Block, attrs: &[ast::Attribute], @@ -1210,7 +1215,7 @@ impl<'a> State<'a> { } /// Print a `let pat = expr` expression. - crate fn print_let(&mut self, pat: &ast::Pat, expr: &ast::Expr) { + pub(crate) fn print_let(&mut self, pat: &ast::Pat, expr: &ast::Expr) { self.word("let "); self.print_pat(pat); self.space(); @@ -1219,7 +1224,7 @@ impl<'a> State<'a> { self.print_expr_cond_paren(expr, Self::cond_needs_par(expr) || npals()) } - crate fn print_mac(&mut self, m: &ast::MacCall) { + pub(crate) fn print_mac(&mut self, m: &ast::MacCall) { self.print_mac_common( Some(MacHeader::Path(&m.path)), true, @@ -1360,7 +1365,7 @@ impl<'a> State<'a> { self.pclose(); } - crate fn print_local_decl(&mut self, loc: &ast::Local) { + pub(crate) fn print_local_decl(&mut self, loc: &ast::Local) { self.print_pat(&loc.pat); if let Some(ref ty) = loc.ty { self.word_space(":"); @@ -1368,7 +1373,7 @@ impl<'a> State<'a> { } } - crate fn print_name(&mut self, name: Symbol) { + pub(crate) fn print_name(&mut self, name: Symbol) { self.word(name.to_string()); self.ann.post(self, AnnNode::Name(&name)) } @@ -1392,7 +1397,7 @@ impl<'a> State<'a> { } } - crate fn print_pat(&mut self, pat: &ast::Pat) { + pub(crate) fn print_pat(&mut self, pat: &ast::Pat) { self.maybe_print_comment(pat.span.lo()); self.ann.pre(self, AnnNode::Pat(pat)); /* Pat isn't normalized, but the beauty of it @@ -1551,7 +1556,7 @@ impl<'a> State<'a> { } } - crate fn print_asyncness(&mut self, asyncness: ast::Async) { + pub(crate) fn print_asyncness(&mut self, asyncness: ast::Async) { if asyncness.is_async() { self.word_nbsp("async"); } @@ -1584,11 +1589,11 @@ impl<'a> State<'a> { } } - crate fn print_lifetime(&mut self, lifetime: ast::Lifetime) { + pub(crate) fn print_lifetime(&mut self, lifetime: ast::Lifetime) { self.print_name(lifetime.ident.name) } - crate fn print_lifetime_bounds( + pub(crate) fn print_lifetime_bounds( &mut self, lifetime: ast::Lifetime, bounds: &ast::GenericBounds, @@ -1608,7 +1613,7 @@ impl<'a> State<'a> { } } - crate fn print_generic_params(&mut self, generic_params: &[ast::GenericParam]) { + pub(crate) fn print_generic_params(&mut self, generic_params: &[ast::GenericParam]) { if generic_params.is_empty() { return; } @@ -1662,12 +1667,12 @@ impl<'a> State<'a> { } } - crate fn print_mt(&mut self, mt: &ast::MutTy, print_const: bool) { + pub(crate) fn print_mt(&mut self, mt: &ast::MutTy, print_const: bool) { self.print_mutability(mt.mutbl, print_const); self.print_type(&mt.ty) } - crate fn print_param(&mut self, input: &ast::Param, is_closure: bool) { + pub(crate) fn print_param(&mut self, input: &ast::Param, is_closure: bool) { self.ibox(INDENT_UNIT); self.print_outer_attributes_inline(&input.attrs); @@ -1695,7 +1700,7 @@ impl<'a> State<'a> { self.end(); } - crate fn print_fn_ret_ty(&mut self, fn_ret_ty: &ast::FnRetTy) { + pub(crate) fn print_fn_ret_ty(&mut self, fn_ret_ty: &ast::FnRetTy) { if let ast::FnRetTy::Ty(ty) = fn_ret_ty { self.space_if_not_bol(); self.ibox(INDENT_UNIT); @@ -1706,7 +1711,7 @@ impl<'a> State<'a> { } } - crate fn print_ty_fn( + pub(crate) fn print_ty_fn( &mut self, ext: ast::Extern, unsafety: ast::Unsafe, @@ -1730,7 +1735,7 @@ impl<'a> State<'a> { self.end(); } - crate fn print_fn_header_info(&mut self, header: ast::FnHeader) { + pub(crate) fn print_fn_header_info(&mut self, header: ast::FnHeader) { self.print_constness(header.constness); self.print_asyncness(header.asyncness); self.print_unsafety(header.unsafety); @@ -1750,21 +1755,21 @@ impl<'a> State<'a> { self.word("fn") } - crate fn print_unsafety(&mut self, s: ast::Unsafe) { + pub(crate) fn print_unsafety(&mut self, s: ast::Unsafe) { match s { ast::Unsafe::No => {} ast::Unsafe::Yes(_) => self.word_nbsp("unsafe"), } } - crate fn print_constness(&mut self, s: ast::Const) { + pub(crate) fn print_constness(&mut self, s: ast::Const) { match s { ast::Const::No => {} ast::Const::Yes(_) => self.word_nbsp("const"), } } - crate fn print_is_auto(&mut self, s: ast::IsAuto) { + pub(crate) fn print_is_auto(&mut self, s: ast::IsAuto) { match s { ast::IsAuto::Yes => self.word_nbsp("auto"), ast::IsAuto::No => {} diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs index 23c5a92e352b1..67b539a7ad41b 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs @@ -19,7 +19,7 @@ impl<'a> State<'a> { } } - crate fn print_foreign_item(&mut self, item: &ast::ForeignItem) { + pub(crate) fn print_foreign_item(&mut self, item: &ast::ForeignItem) { let ast::Item { id, span, ident, ref attrs, ref kind, ref vis, tokens: _ } = *item; self.ann.pre(self, AnnNode::SubItem(id)); self.hardbreak_if_not_bol(); @@ -128,7 +128,7 @@ impl<'a> State<'a> { } /// Pretty-prints an item. - crate fn print_item(&mut self, item: &ast::Item) { + pub(crate) fn print_item(&mut self, item: &ast::Item) { self.hardbreak_if_not_bol(); self.maybe_print_comment(item.span.lo()); self.print_outer_attributes(&item.attrs); @@ -400,16 +400,12 @@ impl<'a> State<'a> { self.bclose(span, empty) } - crate fn print_visibility(&mut self, vis: &ast::Visibility) { + pub(crate) fn print_visibility(&mut self, vis: &ast::Visibility) { match vis.kind { ast::VisibilityKind::Public => self.word_nbsp("pub"), - ast::VisibilityKind::Crate(sugar) => match sugar { - ast::CrateSugar::PubCrate => self.word_nbsp("pub(crate)"), - ast::CrateSugar::JustCrate => self.word_nbsp("crate"), - }, ast::VisibilityKind::Restricted { ref path, .. } => { let path = Self::to_string(|s| s.print_path(path, false, 0)); - if path == "self" || path == "super" { + if path == "crate" || path == "self" || path == "super" { self.word_nbsp(format!("pub({})", path)) } else { self.word_nbsp(format!("pub(in {})", path)) @@ -484,7 +480,7 @@ impl<'a> State<'a> { } } - crate fn print_variant(&mut self, v: &ast::Variant) { + pub(crate) fn print_variant(&mut self, v: &ast::Variant) { self.head(""); self.print_visibility(&v.vis); let generics = ast::Generics::default(); @@ -496,7 +492,7 @@ impl<'a> State<'a> { } } - crate fn print_assoc_item(&mut self, item: &ast::AssocItem) { + pub(crate) fn print_assoc_item(&mut self, item: &ast::AssocItem) { let ast::Item { id, span, ident, ref attrs, ref kind, ref vis, tokens: _ } = *item; self.ann.pre(self, AnnNode::SubItem(id)); self.hardbreak_if_not_bol(); @@ -562,7 +558,7 @@ impl<'a> State<'a> { } } - crate fn print_fn( + pub(crate) fn print_fn( &mut self, decl: &ast::FnDecl, header: ast::FnHeader, @@ -579,7 +575,7 @@ impl<'a> State<'a> { self.print_where_clause(&generics.where_clause) } - crate fn print_fn_params_and_ret(&mut self, decl: &ast::FnDecl, is_closure: bool) { + pub(crate) fn print_fn_params_and_ret(&mut self, decl: &ast::FnDecl, is_closure: bool) { let (open, close) = if is_closure { ("|", "|") } else { ("(", ")") }; self.word(open); self.commasep(Inconsistent, &decl.inputs, |s, param| s.print_param(param, is_closure)); @@ -591,7 +587,7 @@ impl<'a> State<'a> { self.print_where_clause_parts(where_clause.has_where_token, &where_clause.predicates); } - crate fn print_where_clause_parts( + pub(crate) fn print_where_clause_parts( &mut self, has_where_token: bool, predicates: &[ast::WherePredicate], diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index 3d4bd222715c3..c8f1e1dbb0151 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -101,6 +101,16 @@ pub struct Stability { pub feature: Symbol, } +impl Stability { + pub fn is_unstable(&self) -> bool { + self.level.is_unstable() + } + + pub fn is_stable(&self) -> bool { + self.level.is_stable() + } +} + /// Represents the `#[rustc_const_unstable]` and `#[rustc_const_stable]` attributes. #[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, Hash)] #[derive(HashStable_Generic)] @@ -111,6 +121,16 @@ pub struct ConstStability { pub promotable: bool, } +impl ConstStability { + pub fn is_const_unstable(&self) -> bool { + self.level.is_unstable() + } + + pub fn is_const_stable(&self) -> bool { + self.level.is_stable() + } +} + /// The available stability levels. #[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, Hash)] #[derive(HashStable_Generic)] @@ -434,6 +454,15 @@ pub fn find_crate_name(sess: &Session, attrs: &[Attribute]) -> Option { sess.first_attr_value_str_by_name(attrs, sym::crate_name) } +#[derive(Clone, Debug)] +pub struct Condition { + pub name: Symbol, + pub name_span: Span, + pub value: Option, + pub value_span: Option, + pub span: Span, +} + /// Tests if a cfg-pattern matches the cfg set pub fn cfg_matches( cfg: &ast::MetaItem, @@ -442,70 +471,42 @@ pub fn cfg_matches( features: Option<&Features>, ) -> bool { eval_condition(cfg, sess, features, &mut |cfg| { - try_gate_cfg(cfg, sess, features); - let error = |span, msg| { - sess.span_diagnostic.span_err(span, msg); - true - }; - if cfg.path.segments.len() != 1 { - return error(cfg.path.span, "`cfg` predicate key must be an identifier"); - } - match &cfg.kind { - MetaItemKind::List(..) => { - error(cfg.span, "unexpected parentheses after `cfg` predicate key") - } - MetaItemKind::NameValue(lit) if !lit.kind.is_str() => { - handle_errors( - sess, - lit.span, - AttrError::UnsupportedLiteral( - "literal in `cfg` predicate value must be a string", - lit.kind.is_bytestr(), - ), + try_gate_cfg(cfg.name, cfg.span, sess, features); + if let Some(names_valid) = &sess.check_config.names_valid { + if !names_valid.contains(&cfg.name) { + sess.buffer_lint_with_diagnostic( + UNEXPECTED_CFGS, + cfg.span, + lint_node_id, + "unexpected `cfg` condition name", + BuiltinLintDiagnostics::UnexpectedCfg((cfg.name, cfg.name_span), None), ); - true } - MetaItemKind::NameValue(..) | MetaItemKind::Word => { - let ident = cfg.ident().expect("multi-segment cfg predicate"); - let name = ident.name; - let value = cfg.value_str(); - if let Some(names_valid) = &sess.check_config.names_valid { - if !names_valid.contains(&name) { - sess.buffer_lint_with_diagnostic( - UNEXPECTED_CFGS, - cfg.span, - lint_node_id, - "unexpected `cfg` condition name", - BuiltinLintDiagnostics::UnexpectedCfg((name, ident.span), None), - ); - } - } - if let Some(value) = value { - if let Some(values) = &sess.check_config.values_valid.get(&name) { - if !values.contains(&value) { - sess.buffer_lint_with_diagnostic( - UNEXPECTED_CFGS, - cfg.span, - lint_node_id, - "unexpected `cfg` condition value", - BuiltinLintDiagnostics::UnexpectedCfg( - (name, ident.span), - Some((value, cfg.name_value_literal_span().unwrap())), - ), - ); - } - } + } + if let Some(value) = cfg.value { + if let Some(values) = &sess.check_config.values_valid.get(&cfg.name) { + if !values.contains(&value) { + sess.buffer_lint_with_diagnostic( + UNEXPECTED_CFGS, + cfg.span, + lint_node_id, + "unexpected `cfg` condition value", + BuiltinLintDiagnostics::UnexpectedCfg( + (cfg.name, cfg.name_span), + cfg.value_span.map(|vs| (value, vs)), + ), + ); } - sess.config.contains(&(name, value)) } } + sess.config.contains(&(cfg.name, cfg.value)) }) } -fn try_gate_cfg(cfg: &ast::MetaItem, sess: &ParseSess, features: Option<&Features>) { - let gate = find_gated_cfg(|sym| cfg.has_name(sym)); +fn try_gate_cfg(name: Symbol, span: Span, sess: &ParseSess, features: Option<&Features>) { + let gate = find_gated_cfg(|sym| sym == name); if let (Some(feats), Some(gated_cfg)) = (features, gate) { - gate_cfg(&gated_cfg, cfg.span, sess, feats); + gate_cfg(&gated_cfg, span, sess, feats); } } @@ -543,11 +544,11 @@ pub fn eval_condition( cfg: &ast::MetaItem, sess: &ParseSess, features: Option<&Features>, - eval: &mut impl FnMut(&ast::MetaItem) -> bool, + eval: &mut impl FnMut(Condition) -> bool, ) -> bool { match cfg.kind { ast::MetaItemKind::List(ref mis) if cfg.name_or_empty() == sym::version => { - try_gate_cfg(cfg, sess, features); + try_gate_cfg(sym::version, cfg.span, sess, features); let (min_version, span) = match &mis[..] { [NestedMetaItem::Literal(Lit { kind: LitKind::Str(sym, ..), span, .. })] => { (sym, span) @@ -629,6 +630,25 @@ pub fn eval_condition( !eval_condition(mis[0].meta_item().unwrap(), sess, features, eval) } + sym::target => { + if let Some(features) = features && !features.cfg_target_compact { + feature_err( + sess, + sym::cfg_target_compact, + cfg.span, + &"compact `cfg(target(..))` is experimental and subject to change" + ).emit(); + } + + mis.iter().fold(true, |res, mi| { + let mut mi = mi.meta_item().unwrap().clone(); + if let [seg, ..] = &mut mi.path.segments[..] { + seg.ident.name = Symbol::intern(&format!("target_{}", seg.ident.name)); + } + + res & eval_condition(&mi, sess, features, eval) + }) + } _ => { struct_span_err!( sess.span_diagnostic, @@ -642,7 +662,32 @@ pub fn eval_condition( } } } - ast::MetaItemKind::Word | ast::MetaItemKind::NameValue(..) => eval(cfg), + ast::MetaItemKind::Word | MetaItemKind::NameValue(..) if cfg.path.segments.len() != 1 => { + sess.span_diagnostic + .span_err(cfg.path.span, "`cfg` predicate key must be an identifier"); + true + } + MetaItemKind::NameValue(ref lit) if !lit.kind.is_str() => { + handle_errors( + sess, + lit.span, + AttrError::UnsupportedLiteral( + "literal in `cfg` predicate value must be a string", + lit.kind.is_bytestr(), + ), + ); + true + } + ast::MetaItemKind::Word | ast::MetaItemKind::NameValue(..) => { + let ident = cfg.ident().expect("multi-segment cfg predicate"); + eval(Condition { + name: ident.name, + name_span: ident.span, + value: cfg.value_str(), + value_span: cfg.name_value_literal_span(), + span: cfg.span, + }) + } } } diff --git a/compiler/rustc_attr/src/lib.rs b/compiler/rustc_attr/src/lib.rs index c95c1c40a34c2..c3f9f0cf3621f 100644 --- a/compiler/rustc_attr/src/lib.rs +++ b/compiler/rustc_attr/src/lib.rs @@ -4,6 +4,7 @@ //! The goal is to move the definition of `MetaItem` and things that don't need to be in `syntax` //! to this crate. +#![feature(let_chains)] #![feature(let_else)] #[macro_use] diff --git a/compiler/rustc_borrowck/src/borrow_set.rs b/compiler/rustc_borrowck/src/borrow_set.rs index 7c921b8505823..c7d0e3361331c 100644 --- a/compiler/rustc_borrowck/src/borrow_set.rs +++ b/compiler/rustc_borrowck/src/borrow_set.rs @@ -29,7 +29,7 @@ pub struct BorrowSet<'tcx> { /// Map from local to all the borrows on that local. pub local_map: FxHashMap>, - crate locals_state_at_exit: LocalsStateAtExit, + pub(crate) locals_state_at_exit: LocalsStateAtExit, } impl<'tcx> Index for BorrowSet<'tcx> { @@ -148,23 +148,23 @@ impl<'tcx> BorrowSet<'tcx> { } } - crate fn activations_at_location(&self, location: Location) -> &[BorrowIndex] { + pub(crate) fn activations_at_location(&self, location: Location) -> &[BorrowIndex] { self.activation_map.get(&location).map_or(&[], |activations| &activations[..]) } - crate fn len(&self) -> usize { + pub(crate) fn len(&self) -> usize { self.location_map.len() } - crate fn indices(&self) -> impl Iterator { + pub(crate) fn indices(&self) -> impl Iterator { BorrowIndex::from_usize(0)..BorrowIndex::from_usize(self.len()) } - crate fn iter_enumerated(&self) -> impl Iterator)> { + pub(crate) fn iter_enumerated(&self) -> impl Iterator)> { self.indices().zip(self.location_map.values()) } - crate fn get_index_of(&self, location: &Location) -> Option { + pub(crate) fn get_index_of(&self, location: &Location) -> Option { self.location_map.get_index_of(location).map(BorrowIndex::from) } } diff --git a/compiler/rustc_borrowck/src/borrowck_errors.rs b/compiler/rustc_borrowck/src/borrowck_errors.rs index 70f7f1e493e07..a1233d62cb02e 100644 --- a/compiler/rustc_borrowck/src/borrowck_errors.rs +++ b/compiler/rustc_borrowck/src/borrowck_errors.rs @@ -3,7 +3,7 @@ use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::Span; impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { - crate fn cannot_move_when_borrowed( + pub(crate) fn cannot_move_when_borrowed( &self, span: Span, desc: &str, @@ -11,7 +11,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { struct_span_err!(self, span, E0505, "cannot move out of {} because it is borrowed", desc,) } - crate fn cannot_use_when_mutably_borrowed( + pub(crate) fn cannot_use_when_mutably_borrowed( &self, span: Span, desc: &str, @@ -31,7 +31,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { err } - crate fn cannot_act_on_uninitialized_variable( + pub(crate) fn cannot_act_on_uninitialized_variable( &self, span: Span, verb: &str, @@ -47,7 +47,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { ) } - crate fn cannot_mutably_borrow_multiply( + pub(crate) fn cannot_mutably_borrow_multiply( &self, new_loan_span: Span, desc: &str, @@ -97,7 +97,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { err } - crate fn cannot_uniquely_borrow_by_two_closures( + pub(crate) fn cannot_uniquely_borrow_by_two_closures( &self, new_loan_span: Span, desc: &str, @@ -126,7 +126,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { err } - crate fn cannot_uniquely_borrow_by_one_closure( + pub(crate) fn cannot_uniquely_borrow_by_one_closure( &self, new_loan_span: Span, container_name: &str, @@ -157,7 +157,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { err } - crate fn cannot_reborrow_already_uniquely_borrowed( + pub(crate) fn cannot_reborrow_already_uniquely_borrowed( &self, new_loan_span: Span, container_name: &str, @@ -193,7 +193,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { err } - crate fn cannot_reborrow_already_borrowed( + pub(crate) fn cannot_reborrow_already_borrowed( &self, span: Span, desc_new: &str, @@ -242,7 +242,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { err } - crate fn cannot_assign_to_borrowed( + pub(crate) fn cannot_assign_to_borrowed( &self, span: Span, borrow_span: Span, @@ -261,7 +261,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { err } - crate fn cannot_reassign_immutable( + pub(crate) fn cannot_reassign_immutable( &self, span: Span, desc: &str, @@ -271,7 +271,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { struct_span_err!(self, span, E0384, "cannot assign {} {}", msg, desc) } - crate fn cannot_assign( + pub(crate) fn cannot_assign( &self, span: Span, desc: &str, @@ -279,7 +279,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { struct_span_err!(self, span, E0594, "cannot assign to {}", desc) } - crate fn cannot_move_out_of( + pub(crate) fn cannot_move_out_of( &self, move_from_span: Span, move_from_desc: &str, @@ -290,7 +290,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { /// Signal an error due to an attempt to move out of the interior /// of an array or slice. `is_index` is None when error origin /// didn't capture whether there was an indexing operation or not. - crate fn cannot_move_out_of_interior_noncopy( + pub(crate) fn cannot_move_out_of_interior_noncopy( &self, move_from_span: Span, ty: Ty<'_>, @@ -313,7 +313,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { err } - crate fn cannot_move_out_of_interior_of_drop( + pub(crate) fn cannot_move_out_of_interior_of_drop( &self, move_from_span: Span, container_ty: Ty<'_>, @@ -329,7 +329,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { err } - crate fn cannot_act_on_moved_value( + pub(crate) fn cannot_act_on_moved_value( &self, use_span: Span, verb: &str, @@ -349,7 +349,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { ) } - crate fn cannot_borrow_path_as_mutable_because( + pub(crate) fn cannot_borrow_path_as_mutable_because( &self, span: Span, path: &str, @@ -358,7 +358,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { struct_span_err!(self, span, E0596, "cannot borrow {} as mutable{}", path, reason,) } - crate fn cannot_mutate_in_immutable_section( + pub(crate) fn cannot_mutate_in_immutable_section( &self, mutate_span: Span, immutable_span: Span, @@ -380,7 +380,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { err } - crate fn cannot_borrow_across_generator_yield( + pub(crate) fn cannot_borrow_across_generator_yield( &self, span: Span, yield_span: Span, @@ -395,7 +395,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { err } - crate fn cannot_borrow_across_destructor( + pub(crate) fn cannot_borrow_across_destructor( &self, borrow_span: Span, ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> { @@ -407,7 +407,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { ) } - crate fn path_does_not_live_long_enough( + pub(crate) fn path_does_not_live_long_enough( &self, span: Span, path: &str, @@ -415,7 +415,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { struct_span_err!(self, span, E0597, "{} does not live long enough", path,) } - crate fn cannot_return_reference_to_local( + pub(crate) fn cannot_return_reference_to_local( &self, span: Span, return_kind: &str, @@ -440,7 +440,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { err } - crate fn cannot_capture_in_long_lived_closure( + pub(crate) fn cannot_capture_in_long_lived_closure( &self, closure_span: Span, closure_kind: &str, @@ -462,14 +462,14 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { err } - crate fn thread_local_value_does_not_live_long_enough( + pub(crate) fn thread_local_value_does_not_live_long_enough( &self, span: Span, ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> { struct_span_err!(self, span, E0712, "thread-local variable borrowed past end of function",) } - crate fn temporary_value_borrowed_for_too_long( + pub(crate) fn temporary_value_borrowed_for_too_long( &self, span: Span, ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> { @@ -486,7 +486,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { } } -crate fn borrowed_data_escapes_closure<'tcx>( +pub(crate) fn borrowed_data_escapes_closure<'tcx>( tcx: TyCtxt<'tcx>, escape_span: Span, escapes_from: &str, diff --git a/compiler/rustc_borrowck/src/constraint_generation.rs b/compiler/rustc_borrowck/src/constraint_generation.rs index 22edee33c5c1b..e4ffae38c33a5 100644 --- a/compiler/rustc_borrowck/src/constraint_generation.rs +++ b/compiler/rustc_borrowck/src/constraint_generation.rs @@ -140,9 +140,7 @@ impl<'cg, 'cx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'tcx> { // A `Call` terminator's return value can be a local which has borrows, // so we need to record those as `killed` as well. if let TerminatorKind::Call { destination, .. } = terminator.kind { - if let Some((place, _)) = destination { - self.record_killed_borrows_for_place(place, location); - } + self.record_killed_borrows_for_place(destination, location); } self.super_terminator(terminator, location); diff --git a/compiler/rustc_borrowck/src/constraints/graph.rs b/compiler/rustc_borrowck/src/constraints/graph.rs index c19a39c393f79..609fbc2bc1515 100644 --- a/compiler/rustc_borrowck/src/constraints/graph.rs +++ b/compiler/rustc_borrowck/src/constraints/graph.rs @@ -13,19 +13,19 @@ use crate::{ /// The construct graph organizes the constraints by their end-points. /// It can be used to view a `R1: R2` constraint as either an edge `R1 /// -> R2` or `R2 -> R1` depending on the direction type `D`. -crate struct ConstraintGraph { +pub(crate) struct ConstraintGraph { _direction: D, first_constraints: IndexVec>, next_constraints: IndexVec>, } -crate type NormalConstraintGraph = ConstraintGraph; +pub(crate) type NormalConstraintGraph = ConstraintGraph; -crate type ReverseConstraintGraph = ConstraintGraph; +pub(crate) type ReverseConstraintGraph = ConstraintGraph; /// Marker trait that controls whether a `R1: R2` constraint /// represents an edge `R1 -> R2` or `R2 -> R1`. -crate trait ConstraintGraphDirecton: Copy + 'static { +pub(crate) trait ConstraintGraphDirecton: Copy + 'static { fn start_region(c: &OutlivesConstraint<'_>) -> RegionVid; fn end_region(c: &OutlivesConstraint<'_>) -> RegionVid; fn is_normal() -> bool; @@ -36,7 +36,7 @@ crate trait ConstraintGraphDirecton: Copy + 'static { /// inference. This is because we compute the value of R1 by union'ing /// all the things that it relies on. #[derive(Copy, Clone, Debug)] -crate struct Normal; +pub(crate) struct Normal; impl ConstraintGraphDirecton for Normal { fn start_region(c: &OutlivesConstraint<'_>) -> RegionVid { @@ -57,7 +57,7 @@ impl ConstraintGraphDirecton for Normal { /// we wish to iterate from a region (e.g., R2) to all the regions /// that will outlive it (e.g., R1). #[derive(Copy, Clone, Debug)] -crate struct Reverse; +pub(crate) struct Reverse; impl ConstraintGraphDirecton for Reverse { fn start_region(c: &OutlivesConstraint<'_>) -> RegionVid { @@ -78,7 +78,11 @@ impl ConstraintGraph { /// R2` is treated as an edge `R1 -> R2`. We use this graph to /// construct SCCs for region inference but also for error /// reporting. - crate fn new(direction: D, set: &OutlivesConstraintSet<'_>, num_region_vars: usize) -> Self { + pub(crate) fn new( + direction: D, + set: &OutlivesConstraintSet<'_>, + num_region_vars: usize, + ) -> Self { let mut first_constraints = IndexVec::from_elem_n(None, num_region_vars); let mut next_constraints = IndexVec::from_elem(None, &set.outlives); @@ -96,7 +100,7 @@ impl ConstraintGraph { /// Given the constraint set from which this graph was built /// creates a region graph so that you can iterate over *regions* /// and not constraints. - crate fn region_graph<'rg, 'tcx>( + pub(crate) fn region_graph<'rg, 'tcx>( &'rg self, set: &'rg OutlivesConstraintSet<'tcx>, static_region: RegionVid, @@ -105,7 +109,7 @@ impl ConstraintGraph { } /// Given a region `R`, iterate over all constraints `R: R1`. - crate fn outgoing_edges<'a, 'tcx>( + pub(crate) fn outgoing_edges<'a, 'tcx>( &'a self, region_sup: RegionVid, constraints: &'a OutlivesConstraintSet<'tcx>, @@ -129,7 +133,7 @@ impl ConstraintGraph { } } -crate struct Edges<'s, 'tcx, D: ConstraintGraphDirecton> { +pub(crate) struct Edges<'s, 'tcx, D: ConstraintGraphDirecton> { graph: &'s ConstraintGraph, constraints: &'s OutlivesConstraintSet<'tcx>, pointer: Option, @@ -169,7 +173,7 @@ impl<'s, 'tcx, D: ConstraintGraphDirecton> Iterator for Edges<'s, 'tcx, D> { /// This struct brings together a constraint set and a (normal, not /// reverse) constraint graph. It implements the graph traits and is /// usd for doing the SCC computation. -crate struct RegionGraph<'s, 'tcx, D: ConstraintGraphDirecton> { +pub(crate) struct RegionGraph<'s, 'tcx, D: ConstraintGraphDirecton> { set: &'s OutlivesConstraintSet<'tcx>, constraint_graph: &'s ConstraintGraph, static_region: RegionVid, @@ -180,7 +184,7 @@ impl<'s, 'tcx, D: ConstraintGraphDirecton> RegionGraph<'s, 'tcx, D> { /// R2` is treated as an edge `R1 -> R2`. We use this graph to /// construct SCCs for region inference but also for error /// reporting. - crate fn new( + pub(crate) fn new( set: &'s OutlivesConstraintSet<'tcx>, constraint_graph: &'s ConstraintGraph, static_region: RegionVid, @@ -190,14 +194,14 @@ impl<'s, 'tcx, D: ConstraintGraphDirecton> RegionGraph<'s, 'tcx, D> { /// Given a region `R`, iterate over all regions `R1` such that /// there exists a constraint `R: R1`. - crate fn outgoing_regions(&self, region_sup: RegionVid) -> Successors<'s, 'tcx, D> { + pub(crate) fn outgoing_regions(&self, region_sup: RegionVid) -> Successors<'s, 'tcx, D> { Successors { edges: self.constraint_graph.outgoing_edges(region_sup, self.set, self.static_region), } } } -crate struct Successors<'s, 'tcx, D: ConstraintGraphDirecton> { +pub(crate) struct Successors<'s, 'tcx, D: ConstraintGraphDirecton> { edges: Edges<'s, 'tcx, D>, } diff --git a/compiler/rustc_borrowck/src/constraints/mod.rs b/compiler/rustc_borrowck/src/constraints/mod.rs index 14f0e5f620aee..a504d0c91222e 100644 --- a/compiler/rustc_borrowck/src/constraints/mod.rs +++ b/compiler/rustc_borrowck/src/constraints/mod.rs @@ -8,19 +8,19 @@ use std::ops::Index; use crate::type_check::Locations; -crate mod graph; +pub(crate) mod graph; /// A set of NLL region constraints. These include "outlives" /// constraints of the form `R1: R2`. Each constraint is identified by /// a unique `OutlivesConstraintIndex` and you can index into the set /// (`constraint_set[i]`) to access the constraint details. #[derive(Clone, Default)] -crate struct OutlivesConstraintSet<'tcx> { +pub(crate) struct OutlivesConstraintSet<'tcx> { outlives: IndexVec>, } impl<'tcx> OutlivesConstraintSet<'tcx> { - crate fn push(&mut self, constraint: OutlivesConstraint<'tcx>) { + pub(crate) fn push(&mut self, constraint: OutlivesConstraint<'tcx>) { debug!( "OutlivesConstraintSet::push({:?}: {:?} @ {:?}", constraint.sup, constraint.sub, constraint.locations @@ -38,20 +38,20 @@ impl<'tcx> OutlivesConstraintSet<'tcx> { /// N.B., this graph contains a "frozen" view of the current /// constraints. Any new constraints added to the `OutlivesConstraintSet` /// after the graph is built will not be present in the graph. - crate fn graph(&self, num_region_vars: usize) -> graph::NormalConstraintGraph { + pub(crate) fn graph(&self, num_region_vars: usize) -> graph::NormalConstraintGraph { graph::ConstraintGraph::new(graph::Normal, self, num_region_vars) } /// Like `graph`, but constraints a reverse graph where `R1: R2` /// represents an edge `R2 -> R1`. - crate fn reverse_graph(&self, num_region_vars: usize) -> graph::ReverseConstraintGraph { + pub(crate) fn reverse_graph(&self, num_region_vars: usize) -> graph::ReverseConstraintGraph { graph::ConstraintGraph::new(graph::Reverse, self, num_region_vars) } /// Computes cycles (SCCs) in the graph of regions. In particular, /// find all regions R1, R2 such that R1: R2 and R2: R1 and group /// them into an SCC, and find the relationships between SCCs. - crate fn compute_sccs( + pub(crate) fn compute_sccs( &self, constraint_graph: &graph::NormalConstraintGraph, static_region: RegionVid, @@ -60,7 +60,7 @@ impl<'tcx> OutlivesConstraintSet<'tcx> { Sccs::new(region_graph) } - crate fn outlives(&self) -> &IndexVec> { + pub(crate) fn outlives(&self) -> &IndexVec> { &self.outlives } } @@ -95,7 +95,7 @@ pub struct OutlivesConstraint<'tcx> { pub span: Span, /// What caused this constraint? - pub category: ConstraintCategory, + pub category: ConstraintCategory<'tcx>, /// Variance diagnostic information pub variance_info: VarianceDiagInfo<'tcx>, diff --git a/compiler/rustc_borrowck/src/dataflow.rs b/compiler/rustc_borrowck/src/dataflow.rs index d38e89cd79edd..97d5a8d158e1e 100644 --- a/compiler/rustc_borrowck/src/dataflow.rs +++ b/compiler/rustc_borrowck/src/dataflow.rs @@ -199,7 +199,7 @@ impl<'tcx> OutOfScopePrecomputer<'_, 'tcx> { // Add successor BBs to the work list, if necessary. let bb_data = &self.body[bb]; debug_assert!(hi == bb_data.statements.len()); - for &succ_bb in bb_data.terminator().successors() { + for succ_bb in bb_data.terminator().successors() { if !self.visited.insert(succ_bb) { if succ_bb == location.block && first_lo > 0 { // `succ_bb` has been seen before. If it wasn't @@ -233,7 +233,7 @@ impl<'tcx> OutOfScopePrecomputer<'_, 'tcx> { } impl<'a, 'tcx> Borrows<'a, 'tcx> { - crate fn new( + pub(crate) fn new( tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, nonlexical_regioncx: &'a RegionInferenceContext<'tcx>, diff --git a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs index 8601fbe27f3fa..07f182102f346 100644 --- a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs @@ -22,7 +22,7 @@ use crate::region_infer::values::RegionElement; use crate::MirBorrowckCtxt; #[derive(Clone)] -crate struct UniverseInfo<'tcx>(UniverseInfoInner<'tcx>); +pub(crate) struct UniverseInfo<'tcx>(UniverseInfoInner<'tcx>); /// What operation a universe was created for. #[derive(Clone)] @@ -36,15 +36,15 @@ enum UniverseInfoInner<'tcx> { } impl<'tcx> UniverseInfo<'tcx> { - crate fn other() -> UniverseInfo<'tcx> { + pub(crate) fn other() -> UniverseInfo<'tcx> { UniverseInfo(UniverseInfoInner::Other) } - crate fn relate(expected: Ty<'tcx>, found: Ty<'tcx>) -> UniverseInfo<'tcx> { + pub(crate) fn relate(expected: Ty<'tcx>, found: Ty<'tcx>) -> UniverseInfo<'tcx> { UniverseInfo(UniverseInfoInner::RelateTys { expected, found }) } - crate fn report_error( + pub(crate) fn report_error( &self, mbcx: &mut MirBorrowckCtxt<'_, 'tcx>, placeholder: ty::PlaceholderRegion, @@ -76,7 +76,7 @@ impl<'tcx> UniverseInfo<'tcx> { } } -crate trait ToUniverseInfo<'tcx> { +pub(crate) trait ToUniverseInfo<'tcx> { fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx>; } diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index a3c9da3021204..191574d7a8fb9 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -1,5 +1,6 @@ use either::Either; use rustc_const_eval::util::CallKind; +use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxHashSet; use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan}; use rustc_hir as hir; @@ -787,7 +788,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { err: &mut Diagnostic, location: Location, issued_borrow: &BorrowData<'tcx>, - explanation: BorrowExplanation, + explanation: BorrowExplanation<'tcx>, ) { let used_in_call = matches!( explanation, @@ -1087,7 +1088,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { BorrowExplanation::MustBeValidFor { category: category @ (ConstraintCategory::Return(_) - | ConstraintCategory::CallArgument + | ConstraintCategory::CallArgument(_) | ConstraintCategory::OpaqueType), from_closure: false, ref region_name, @@ -1146,7 +1147,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { borrow: &BorrowData<'tcx>, drop_span: Span, borrow_spans: UseSpans<'tcx>, - explanation: BorrowExplanation, + explanation: BorrowExplanation<'tcx>, ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> { debug!( "report_local_value_does_not_live_long_enough(\ @@ -1351,7 +1352,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { drop_span: Span, borrow_spans: UseSpans<'tcx>, proper_span: Span, - explanation: BorrowExplanation, + explanation: BorrowExplanation<'tcx>, ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> { debug!( "report_temporary_value_does_not_live_long_enough(\ @@ -1409,7 +1410,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { borrow: &BorrowData<'tcx>, borrow_span: Span, return_span: Span, - category: ConstraintCategory, + category: ConstraintCategory<'tcx>, opt_place_desc: Option<&String>, ) -> Option> { let return_kind = match category { @@ -1507,7 +1508,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { use_span: UseSpans<'tcx>, var_span: Span, fr_name: &RegionName, - category: ConstraintCategory, + category: ConstraintCategory<'tcx>, constraint_span: Span, captured_var: &str, ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> { @@ -1558,7 +1559,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let msg = format!("{} is returned here", kind); err.span_note(constraint_span, &msg); } - ConstraintCategory::CallArgument => { + ConstraintCategory::CallArgument(_) => { fr_name.highlight_region_name(&mut err); if matches!(use_span.generator_kind(), Some(GeneratorKind::Async(_))) { err.note( @@ -1622,10 +1623,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { location: Location, mpi: MovePathIndex, ) -> (Vec, Vec) { - fn predecessor_locations<'a>( - body: &'a mir::Body<'_>, + fn predecessor_locations<'tcx, 'a>( + body: &'a mir::Body<'tcx>, location: Location, - ) -> impl Iterator + 'a { + ) -> impl Iterator + Captures<'tcx> + 'a { if location.statement_index == 0 { let predecessors = body.predecessors()[location.block].to_vec(); Either::Left(predecessors.into_iter().map(move |bb| body.terminator_loc(bb))) @@ -2197,10 +2198,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { "annotate_argument_and_return_for_borrow: target={:?} terminator={:?}", target, terminator ); - if let TerminatorKind::Call { destination: Some((place, _)), args, .. } = + if let TerminatorKind::Call { destination, target: Some(_), args, .. } = &terminator.kind { - if let Some(assigned_to) = place.as_local() { + if let Some(assigned_to) = destination.as_local() { debug!( "annotate_argument_and_return_for_borrow: assigned_to={:?} args={:?}", assigned_to, args diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs index ffea15bdc33eb..5d9e5907dffb0 100644 --- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs +++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs @@ -24,7 +24,7 @@ use crate::{ use super::{find_use, RegionName, UseSpans}; #[derive(Debug)] -pub(crate) enum BorrowExplanation { +pub(crate) enum BorrowExplanation<'tcx> { UsedLater(LaterUseKind, Span, Option), UsedLaterInLoop(LaterUseKind, Span, Option), UsedLaterWhenDropped { @@ -33,7 +33,7 @@ pub(crate) enum BorrowExplanation { should_note_order: bool, }, MustBeValidFor { - category: ConstraintCategory, + category: ConstraintCategory<'tcx>, from_closure: bool, span: Span, region_name: RegionName, @@ -51,11 +51,11 @@ pub(crate) enum LaterUseKind { Other, } -impl BorrowExplanation { +impl<'tcx> BorrowExplanation<'tcx> { pub(crate) fn is_explained(&self) -> bool { !matches!(self, BorrowExplanation::Unexplained) } - pub(crate) fn add_explanation_to_diagnostic<'tcx>( + pub(crate) fn add_explanation_to_diagnostic( &self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>, @@ -276,7 +276,7 @@ impl BorrowExplanation { pub(crate) fn add_lifetime_bound_suggestion_to_diagnostic( &self, err: &mut Diagnostic, - category: &ConstraintCategory, + category: &ConstraintCategory<'tcx>, span: Span, region_name: &RegionName, ) { @@ -305,7 +305,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { &self, borrow_region: RegionVid, outlived_region: RegionVid, - ) -> (ConstraintCategory, bool, Span, Option) { + ) -> (ConstraintCategory<'tcx>, bool, Span, Option) { let BlameConstraint { category, from_closure, cause, variance_info: _ } = self.regioncx.best_blame_constraint( &self.body, @@ -337,7 +337,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { location: Location, borrow: &BorrowData<'tcx>, kind_place: Option<(WriteKind, Place<'tcx>)>, - ) -> BorrowExplanation { + ) -> BorrowExplanation<'tcx> { debug!( "explain_why_borrow_contains_point(location={:?}, borrow={:?}, kind_place={:?})", location, borrow, kind_place @@ -467,7 +467,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { block .terminator() .successors() - .map(|bb| Location { statement_index: 0, block: *bb }) + .map(|bb| Location { statement_index: 0, block: bb }) .filter(|s| visited_locations.insert(*s)) .map(|s| { if self.is_back_edge(location, s) { @@ -526,7 +526,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } } else { for bb in block.terminator().successors() { - let successor = Location { statement_index: 0, block: *bb }; + let successor = Location { statement_index: 0, block: bb }; if !visited_locations.contains(&successor) && self.find_loop_head_dfs(successor, loop_head, visited_locations) @@ -705,10 +705,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let terminator = block.terminator(); debug!("was_captured_by_trait_object: terminator={:?}", terminator); - if let TerminatorKind::Call { destination: Some((place, block)), args, .. } = + if let TerminatorKind::Call { destination, target: Some(block), args, .. } = &terminator.kind { - if let Some(dest) = place.as_local() { + if let Some(dest) = destination.as_local() { debug!( "was_captured_by_trait_object: target={:?} dest={:?} args={:?}", target, dest, args diff --git a/compiler/rustc_borrowck/src/diagnostics/find_use.rs b/compiler/rustc_borrowck/src/diagnostics/find_use.rs index ab4536f00fc42..06fca4db0cf1f 100644 --- a/compiler/rustc_borrowck/src/diagnostics/find_use.rs +++ b/compiler/rustc_borrowck/src/diagnostics/find_use.rs @@ -11,7 +11,7 @@ use rustc_middle::mir::visit::{MirVisitable, PlaceContext, Visitor}; use rustc_middle::mir::{Body, Local, Location}; use rustc_middle::ty::{RegionVid, TyCtxt}; -crate fn find<'tcx>( +pub(crate) fn find<'tcx>( body: &Body<'tcx>, regioncx: &Rc>, tcx: TyCtxt<'tcx>, @@ -67,8 +67,8 @@ impl<'cx, 'tcx> UseFinder<'cx, 'tcx> { block_data .terminator() .successors() - .filter(|&bb| Some(&Some(*bb)) != block_data.terminator().unwind()) - .map(|&bb| Location { statement_index: 0, block: bb }), + .filter(|&bb| Some(&Some(bb)) != block_data.terminator().unwind()) + .map(|bb| Location { statement_index: 0, block: bb }), ); } } diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index 05d29503180ef..9581bb652362f 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -35,12 +35,12 @@ mod move_errors; mod mutability_errors; mod region_errors; -crate use bound_region_errors::{ToUniverseInfo, UniverseInfo}; -crate use mutability_errors::AccessKind; -crate use outlives_suggestion::OutlivesSuggestionBuilder; -crate use region_errors::{ErrorConstraintInfo, RegionErrorKind, RegionErrors}; -crate use region_name::{RegionName, RegionNameSource}; -crate use rustc_const_eval::util::CallKind; +pub(crate) use bound_region_errors::{ToUniverseInfo, UniverseInfo}; +pub(crate) use mutability_errors::AccessKind; +pub(crate) use outlives_suggestion::OutlivesSuggestionBuilder; +pub(crate) use region_errors::{ErrorConstraintInfo, RegionErrorKind, RegionErrors}; +pub(crate) use region_name::{RegionName, RegionNameSource}; +pub(crate) use rustc_const_eval::util::CallKind; use rustc_middle::mir::tcx::PlaceTy; pub(super) struct IncludingDowncast(pub(super) bool); diff --git a/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs b/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs index ab9c206a46f45..9d81330745fe2 100644 --- a/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs +++ b/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs @@ -149,7 +149,7 @@ impl OutlivesSuggestionBuilder { } /// Add the outlives constraint `fr: outlived_fr` to the set of constraints we need to suggest. - crate fn collect_constraint(&mut self, fr: RegionVid, outlived_fr: RegionVid) { + pub(crate) fn collect_constraint(&mut self, fr: RegionVid, outlived_fr: RegionVid) { debug!("Collected {:?}: {:?}", fr, outlived_fr); // Add to set of constraints for final help note. @@ -158,10 +158,10 @@ impl OutlivesSuggestionBuilder { /// Emit an intermediate note on the given `Diagnostic` if the involved regions are /// suggestable. - crate fn intermediate_suggestion( + pub(crate) fn intermediate_suggestion( &mut self, mbcx: &MirBorrowckCtxt<'_, '_>, - errci: &ErrorConstraintInfo, + errci: &ErrorConstraintInfo<'_>, diag: &mut Diagnostic, ) { // Emit an intermediate note. @@ -179,7 +179,7 @@ impl OutlivesSuggestionBuilder { /// If there is a suggestion to emit, add a diagnostic to the buffer. This is the final /// suggestion including all collected constraints. - crate fn add_suggestion(&self, mbcx: &mut MirBorrowckCtxt<'_, '_>) { + pub(crate) fn add_suggestion(&self, mbcx: &mut MirBorrowckCtxt<'_, '_>) { // No constraints to add? Done. if self.constraints_to_add.is_empty() { debug!("No constraints to suggest."); diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index 6f1c8daf42e3f..35f805ce76e1c 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -1,10 +1,14 @@ //! Error reporting machinery for lifetime errors. -use rustc_errors::{Diagnostic, DiagnosticBuilder, ErrorGuaranteed}; +use rustc_data_structures::stable_set::FxHashSet; +use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan}; +use rustc_hir::def_id::DefId; +use rustc_hir::intravisit::Visitor; +use rustc_hir::{self as hir, Item, ItemKind, Node}; use rustc_infer::infer::{ error_reporting::nice_region_error::{ self, find_anon_type, find_param_with_region, suggest_adding_lifetime_params, - NiceRegionError, + HirTraitObjectVisitor, NiceRegionError, TraitObjectVisitor, }, error_reporting::unexpected_hidden_region_diagnostic, NllRegionVariableOrigin, RelateParamBound, @@ -12,8 +16,11 @@ use rustc_infer::infer::{ use rustc_middle::hir::place::PlaceBase; use rustc_middle::mir::{ConstraintCategory, ReturnConstraint}; use rustc_middle::ty::subst::InternalSubsts; +use rustc_middle::ty::Region; +use rustc_middle::ty::TypeVisitor; use rustc_middle::ty::{self, RegionVid, Ty}; use rustc_span::symbol::sym; +use rustc_span::symbol::Ident; use rustc_span::Span; use crate::borrowck_errors; @@ -27,7 +34,7 @@ use crate::{ MirBorrowckCtxt, }; -impl ConstraintDescription for ConstraintCategory { +impl<'tcx> ConstraintDescription for ConstraintCategory<'tcx> { fn description(&self) -> &'static str { // Must end with a space. Allows for empty names to be provided. match self { @@ -37,7 +44,7 @@ impl ConstraintDescription for ConstraintCategory { ConstraintCategory::UseAsConst => "using this value as a constant ", ConstraintCategory::UseAsStatic => "using this value as a static ", ConstraintCategory::Cast => "cast ", - ConstraintCategory::CallArgument => "argument ", + ConstraintCategory::CallArgument(_) => "argument ", ConstraintCategory::TypeAnnotation => "type annotation ", ConstraintCategory::ClosureBounds => "closure body ", ConstraintCategory::SizedBound => "proving this value is `Sized` ", @@ -58,10 +65,10 @@ impl ConstraintDescription for ConstraintCategory { /// /// Usually we expect this to either be empty or contain a small number of items, so we can avoid /// allocation most of the time. -crate type RegionErrors<'tcx> = Vec>; +pub(crate) type RegionErrors<'tcx> = Vec>; #[derive(Clone, Debug)] -crate enum RegionErrorKind<'tcx> { +pub(crate) enum RegionErrorKind<'tcx> { /// A generic bound failure for a type test (`T: 'a`). TypeTestError { type_test: TypeTest<'tcx> }, @@ -101,7 +108,7 @@ crate enum RegionErrorKind<'tcx> { /// Information about the various region constraints involved in a borrow checker error. #[derive(Clone, Debug)] -pub struct ErrorConstraintInfo { +pub struct ErrorConstraintInfo<'tcx> { // fr: outlived_fr pub(super) fr: RegionVid, pub(super) fr_is_local: bool, @@ -109,7 +116,7 @@ pub struct ErrorConstraintInfo { pub(super) outlived_fr_is_local: bool, // Category and span for best blame constraint - pub(super) category: ConstraintCategory, + pub(super) category: ConstraintCategory<'tcx>, pub(super) span: Span, } @@ -256,6 +263,70 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { outlives_suggestion.add_suggestion(self); } + fn get_impl_ident_and_self_ty_from_trait( + &self, + def_id: DefId, + trait_objects: &FxHashSet, + ) -> Option<(Ident, &'tcx hir::Ty<'tcx>)> { + let tcx = self.infcx.tcx; + match tcx.hir().get_if_local(def_id) { + Some(Node::ImplItem(impl_item)) => { + match tcx.hir().find_by_def_id(tcx.hir().get_parent_item(impl_item.hir_id())) { + Some(Node::Item(Item { + kind: ItemKind::Impl(hir::Impl { self_ty, .. }), + .. + })) => Some((impl_item.ident, self_ty)), + _ => None, + } + } + Some(Node::TraitItem(trait_item)) => { + let trait_did = tcx.hir().get_parent_item(trait_item.hir_id()); + match tcx.hir().find_by_def_id(trait_did) { + Some(Node::Item(Item { kind: ItemKind::Trait(..), .. })) => { + // The method being called is defined in the `trait`, but the `'static` + // obligation comes from the `impl`. Find that `impl` so that we can point + // at it in the suggestion. + let trait_did = trait_did.to_def_id(); + match tcx + .hir() + .trait_impls(trait_did) + .iter() + .filter_map(|&impl_did| { + match tcx.hir().get_if_local(impl_did.to_def_id()) { + Some(Node::Item(Item { + kind: ItemKind::Impl(hir::Impl { self_ty, .. }), + .. + })) if trait_objects.iter().all(|did| { + // FIXME: we should check `self_ty` against the receiver + // type in the `UnifyReceiver` context, but for now, use + // this imperfect proxy. This will fail if there are + // multiple `impl`s for the same trait like + // `impl Foo for Box` and `impl Foo for dyn Bar`. + // In that case, only the first one will get suggestions. + let mut traits = vec![]; + let mut hir_v = HirTraitObjectVisitor(&mut traits, *did); + hir_v.visit_ty(self_ty); + !traits.is_empty() + }) => + { + Some(self_ty) + } + _ => None, + } + }) + .next() + { + Some(self_ty) => Some((trait_item.ident, self_ty)), + _ => None, + } + } + _ => None, + } + } + _ => None, + } + } + /// Report an error because the universal region `fr` was required to outlive /// `outlived_fr` but it is not known to do so. For example: /// @@ -279,6 +350,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { }); debug!("report_region_error: category={:?} {:?} {:?}", category, cause, variance_info); + // Check if we can use one of the "nice region errors". if let (Some(f), Some(o)) = (self.to_error_region(fr), self.to_error_region(outlived_fr)) { let nice = NiceRegionError::new_from_span(self.infcx, cause.span, o, f); @@ -312,7 +384,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { self.report_fnmut_error(&errci, kind) } (ConstraintCategory::Assignment, true, false) - | (ConstraintCategory::CallArgument, true, false) => { + | (ConstraintCategory::CallArgument(_), true, false) => { let mut db = self.report_escaping_data_error(&errci); outlives_suggestion.intermediate_suggestion(self, &errci, &mut db); @@ -405,7 +477,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { /// ``` fn report_fnmut_error( &self, - errci: &ErrorConstraintInfo, + errci: &ErrorConstraintInfo<'tcx>, kind: ReturnConstraint, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { let ErrorConstraintInfo { outlived_fr, span, .. } = errci; @@ -450,10 +522,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { _ => None, }; - if defined_hir.is_some() { + if let Some(def_hir) = defined_hir { let upvars_map = self.infcx.tcx.upvars_mentioned(def_id).unwrap(); - let upvar_def_span = self.infcx.tcx.hir().span(defined_hir.unwrap()); - let upvar_span = upvars_map.get(&defined_hir.unwrap()).unwrap().span; + let upvar_def_span = self.infcx.tcx.hir().span(def_hir); + let upvar_span = upvars_map.get(&def_hir).unwrap().span; diag.span_label(upvar_def_span, "variable defined here"); diag.span_label(upvar_span, "variable captured here"); } @@ -486,7 +558,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { /// ``` fn report_escaping_data_error( &self, - errci: &ErrorConstraintInfo, + errci: &ErrorConstraintInfo<'tcx>, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { let ErrorConstraintInfo { span, category, .. } = errci; @@ -548,24 +620,28 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { // Only show an extra note if we can find an 'error region' for both of the region // variables. This avoids showing a noisy note that just mentions 'synthetic' regions // that don't help the user understand the error. - if self.to_error_region(errci.fr).is_some() - && self.to_error_region(errci.outlived_fr).is_some() - { - let fr_region_name = self.give_region_a_name(errci.fr).unwrap(); - fr_region_name.highlight_region_name(&mut diag); - let outlived_fr_region_name = self.give_region_a_name(errci.outlived_fr).unwrap(); - outlived_fr_region_name.highlight_region_name(&mut diag); + match (self.to_error_region(errci.fr), self.to_error_region(errci.outlived_fr)) { + (Some(f), Some(o)) => { + self.maybe_suggest_constrain_dyn_trait_impl(&mut diag, f, o, category); - diag.span_label( - *span, - format!( - "{}requires that `{}` must outlive `{}`", - category.description(), - fr_region_name, - outlived_fr_region_name, - ), - ); + let fr_region_name = self.give_region_a_name(errci.fr).unwrap(); + fr_region_name.highlight_region_name(&mut diag); + let outlived_fr_region_name = self.give_region_a_name(errci.outlived_fr).unwrap(); + outlived_fr_region_name.highlight_region_name(&mut diag); + + diag.span_label( + *span, + format!( + "{}requires that `{}` must outlive `{}`", + category.description(), + fr_region_name, + outlived_fr_region_name, + ), + ); + } + _ => {} } + diag } @@ -586,7 +662,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { /// ``` fn report_general_error( &self, - errci: &ErrorConstraintInfo, + errci: &ErrorConstraintInfo<'tcx>, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { let ErrorConstraintInfo { fr, @@ -699,6 +775,100 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } } + fn maybe_suggest_constrain_dyn_trait_impl( + &self, + diag: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>, + f: Region<'tcx>, + o: Region<'tcx>, + category: &ConstraintCategory<'tcx>, + ) { + if !o.is_static() { + return; + } + + let tcx = self.infcx.tcx; + + let instance = if let ConstraintCategory::CallArgument(Some(func_ty)) = category { + let (fn_did, substs) = match func_ty.kind() { + ty::FnDef(fn_did, substs) => (fn_did, substs), + _ => return, + }; + debug!(?fn_did, ?substs); + + // Only suggest this on function calls, not closures + let ty = tcx.type_of(fn_did); + debug!("ty: {:?}, ty.kind: {:?}", ty, ty.kind()); + if let ty::Closure(_, _) = ty.kind() { + return; + } + + if let Ok(Some(instance)) = ty::Instance::resolve( + tcx, + self.param_env, + *fn_did, + self.infcx.resolve_vars_if_possible(substs), + ) { + instance + } else { + return; + } + } else { + return; + }; + + let param = match find_param_with_region(tcx, f, o) { + Some(param) => param, + None => return, + }; + debug!(?param); + + let mut visitor = TraitObjectVisitor(FxHashSet::default()); + visitor.visit_ty(param.param_ty); + + let Some((ident, self_ty)) = + self.get_impl_ident_and_self_ty_from_trait(instance.def_id(), &visitor.0) else {return}; + + self.suggest_constrain_dyn_trait_in_impl(diag, &visitor.0, ident, self_ty); + } + + #[instrument(skip(self, err), level = "debug")] + fn suggest_constrain_dyn_trait_in_impl( + &self, + err: &mut Diagnostic, + found_dids: &FxHashSet, + ident: Ident, + self_ty: &hir::Ty<'_>, + ) -> bool { + debug!("err: {:#?}", err); + let mut suggested = false; + for found_did in found_dids { + let mut traits = vec![]; + let mut hir_v = HirTraitObjectVisitor(&mut traits, *found_did); + hir_v.visit_ty(&self_ty); + debug!("trait spans found: {:?}", traits); + for span in &traits { + let mut multi_span: MultiSpan = vec![*span].into(); + multi_span.push_span_label( + *span, + "this has an implicit `'static` lifetime requirement".to_string(), + ); + multi_span.push_span_label( + ident.span, + "calling this method introduces the `impl`'s 'static` requirement".to_string(), + ); + err.span_note(multi_span, "the used `impl` has a `'static` requirement"); + err.span_suggestion_verbose( + span.shrink_to_hi(), + "consider relaxing the implicit `'static` requirement", + " + '_".to_string(), + Applicability::MaybeIncorrect, + ); + suggested = true; + } + } + suggested + } + fn suggest_adding_lifetime_params( &self, diag: &mut Diagnostic, diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs index c4cef5710aecb..4d2a16aa60984 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs @@ -15,18 +15,18 @@ use crate::{nll::ToRegionVid, universal_regions::DefiningTy, MirBorrowckCtxt}; /// A name for a particular region used in emitting diagnostics. This name could be a generated /// name like `'1`, a name used by the user like `'a`, or a name like `'static`. #[derive(Debug, Clone)] -crate struct RegionName { +pub(crate) struct RegionName { /// The name of the region (interned). - crate name: Symbol, + pub(crate) name: Symbol, /// Where the region comes from. - crate source: RegionNameSource, + pub(crate) source: RegionNameSource, } /// Denotes the source of a region that is named by a `RegionName`. For example, a free region that /// was named by the user would get `NamedFreeRegion` and `'static` lifetime would get `Static`. /// This helps to print the right kinds of diagnostics. #[derive(Debug, Clone)] -crate enum RegionNameSource { +pub(crate) enum RegionNameSource { /// A bound (not free) region that was substituted at the def site (not an HRTB). NamedEarlyBoundRegion(Span), /// A free region that the user has a name (`'a`) for. @@ -50,7 +50,7 @@ crate enum RegionNameSource { /// Describes what to highlight to explain to the user that we're giving an anonymous region a /// synthesized name, and how to highlight it. #[derive(Debug, Clone)] -crate enum RegionNameHighlight { +pub(crate) enum RegionNameHighlight { /// The anonymous region corresponds to a reference that was found by traversing the type in the HIR. MatchedHirTy(Span), /// The anonymous region corresponds to a `'_` in the generics list of a struct/enum/union. @@ -65,7 +65,7 @@ crate enum RegionNameHighlight { } impl RegionName { - crate fn was_named(&self) -> bool { + pub(crate) fn was_named(&self) -> bool { match self.source { RegionNameSource::NamedEarlyBoundRegion(..) | RegionNameSource::NamedFreeRegion(..) @@ -79,7 +79,7 @@ impl RegionName { } } - crate fn span(&self) -> Option { + pub(crate) fn span(&self) -> Option { match self.source { RegionNameSource::Static => None, RegionNameSource::NamedEarlyBoundRegion(span) @@ -98,7 +98,7 @@ impl RegionName { } } - crate fn highlight_region_name(&self, diag: &mut Diagnostic) { + pub(crate) fn highlight_region_name(&self, diag: &mut Diagnostic) { match &self.source { RegionNameSource::NamedFreeRegion(span) | RegionNameSource::NamedEarlyBoundRegion(span) => { @@ -178,11 +178,11 @@ impl Display for RegionName { } impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { - crate fn mir_def_id(&self) -> hir::def_id::LocalDefId { + pub(crate) fn mir_def_id(&self) -> hir::def_id::LocalDefId { self.body.source.def_id().as_local().unwrap() } - crate fn mir_hir_id(&self) -> hir::HirId { + pub(crate) fn mir_hir_id(&self) -> hir::HirId { self.infcx.tcx.hir().local_def_id_to_hir_id(self.mir_def_id()) } @@ -222,7 +222,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { /// ``` /// /// and then return the name `'1` for us to use. - crate fn give_region_a_name(&self, fr: RegionVid) -> Option { + pub(crate) fn give_region_a_name(&self, fr: RegionVid) -> Option { debug!( "give_region_a_name(fr={:?}, counter={:?})", fr, diff --git a/compiler/rustc_borrowck/src/diagnostics/var_name.rs b/compiler/rustc_borrowck/src/diagnostics/var_name.rs index 00f6280675355..9ba29f04b1a9a 100644 --- a/compiler/rustc_borrowck/src/diagnostics/var_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/var_name.rs @@ -7,7 +7,7 @@ use rustc_span::source_map::Span; use rustc_span::symbol::Symbol; impl<'tcx> RegionInferenceContext<'tcx> { - crate fn get_var_name_and_span_for_region( + pub(crate) fn get_var_name_and_span_for_region( &self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>, @@ -34,7 +34,11 @@ impl<'tcx> RegionInferenceContext<'tcx> { } /// Search the upvars (if any) to find one that references fr. Return its index. - crate fn get_upvar_index_for_region(&self, tcx: TyCtxt<'tcx>, fr: RegionVid) -> Option { + pub(crate) fn get_upvar_index_for_region( + &self, + tcx: TyCtxt<'tcx>, + fr: RegionVid, + ) -> Option { let upvar_index = self.universal_regions().defining_ty.upvar_tys().position(|upvar_ty| { debug!("get_upvar_index_for_region: upvar_ty={:?}", upvar_ty); @@ -57,7 +61,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// Given the index of an upvar, finds its name and the span from where it was /// declared. - crate fn get_upvar_name_and_span_for_region( + pub(crate) fn get_upvar_name_and_span_for_region( &self, tcx: TyCtxt<'tcx>, upvars: &[Upvar<'tcx>], @@ -81,7 +85,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// /// N.B., in the case of a closure, the index is indexing into the signature as seen by the /// user - in particular, index 0 is not the implicit self parameter. - crate fn get_argument_index_for_region( + pub(crate) fn get_argument_index_for_region( &self, tcx: TyCtxt<'tcx>, fr: RegionVid, @@ -107,7 +111,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// Given the index of an argument, finds its name (if any) and the span from where it was /// declared. - crate fn get_argument_name_and_span_for_region( + pub(crate) fn get_argument_name_and_span_for_region( &self, body: &Body<'tcx>, local_names: &IndexVec>, diff --git a/compiler/rustc_borrowck/src/facts.rs b/compiler/rustc_borrowck/src/facts.rs index 86b719bdfa0c7..7f0a637c9d30b 100644 --- a/compiler/rustc_borrowck/src/facts.rs +++ b/compiler/rustc_borrowck/src/facts.rs @@ -25,7 +25,7 @@ impl polonius_engine::FactTypes for RustcFacts { pub type AllFacts = PoloniusFacts; -crate trait AllFactsExt { +pub(crate) trait AllFactsExt { /// Returns `true` if there is a need to gather `AllFacts` given the /// current `-Z` flags. fn enabled(tcx: TyCtxt<'_>) -> bool; diff --git a/compiler/rustc_borrowck/src/invalidation.rs b/compiler/rustc_borrowck/src/invalidation.rs index 76d240bb89f59..0425c53d9dc3c 100644 --- a/compiler/rustc_borrowck/src/invalidation.rs +++ b/compiler/rustc_borrowck/src/invalidation.rs @@ -124,6 +124,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> { ref func, ref args, destination, + target: _, cleanup: _, from_hir_call: _, fn_span: _, @@ -132,9 +133,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> { for arg in args { self.consume_operand(location, arg); } - if let Some((dest, _ /*bb*/)) = destination { - self.mutate_place(location, *dest, Deep); - } + self.mutate_place(location, *destination, Deep); } TerminatorKind::Assert { ref cond, expected: _, ref msg, target: _, cleanup: _ } => { self.consume_operand(location, cond); diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 4661805bb1c34..bf38ca19484c9 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -2,7 +2,6 @@ #![allow(rustc::potential_query_instability)] #![feature(box_patterns)] -#![feature(crate_visibility_modifier)] #![feature(let_chains)] #![feature(let_else)] #![feature(min_specialization)] @@ -99,7 +98,11 @@ struct Upvar<'tcx> { by_ref: bool, } -const DEREF_PROJECTION: &[PlaceElem<'_>; 1] = &[ProjectionElem::Deref]; +/// Associate some local constants with the `'tcx` lifetime +struct TyCtxtConsts<'tcx>(TyCtxt<'tcx>); +impl<'tcx> TyCtxtConsts<'tcx> { + const DEREF_PROJECTION: &'tcx [PlaceElem<'tcx>; 1] = &[ProjectionElem::Deref]; +} pub fn provide(providers: &mut Providers) { *providers = Providers { @@ -662,7 +665,8 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx TerminatorKind::Call { ref func, ref args, - ref destination, + destination, + target: _, cleanup: _, from_hir_call: _, fn_span: _, @@ -671,9 +675,7 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx for arg in args { self.consume_operand(loc, (arg, span), flow_state); } - if let Some((dest, _ /*bb*/)) = *destination { - self.mutate_place(loc, (dest, span), Deep, flow_state); - } + self.mutate_place(loc, (destination, span), Deep, flow_state); } TerminatorKind::Assert { ref cond, expected: _, ref msg, target: _, cleanup: _ } => { self.consume_operand(loc, (cond, span), flow_state); @@ -1445,7 +1447,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // Thread-locals might be dropped after the function exits // We have to dereference the outer reference because // borrows don't conflict behind shared references. - root_place.projection = DEREF_PROJECTION; + root_place.projection = TyCtxtConsts::DEREF_PROJECTION; (true, true) } else { (false, self.locals_are_invalidated_at_exit) diff --git a/compiler/rustc_borrowck/src/location.rs b/compiler/rustc_borrowck/src/location.rs index c89da5514fd15..70a3116949894 100644 --- a/compiler/rustc_borrowck/src/location.rs +++ b/compiler/rustc_borrowck/src/location.rs @@ -30,7 +30,7 @@ pub enum RichLocation { } impl LocationTable { - crate fn new(body: &Body<'_>) -> Self { + pub(crate) fn new(body: &Body<'_>) -> Self { let mut num_points = 0; let statements_before_block = body .basic_blocks() diff --git a/compiler/rustc_borrowck/src/member_constraints.rs b/compiler/rustc_borrowck/src/member_constraints.rs index f920d9d5c3f57..e91fcf1472df1 100644 --- a/compiler/rustc_borrowck/src/member_constraints.rs +++ b/compiler/rustc_borrowck/src/member_constraints.rs @@ -1,3 +1,4 @@ +use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxHashMap; use rustc_index::vec::IndexVec; use rustc_middle::infer::MemberConstraint; @@ -8,7 +9,7 @@ use std::ops::Index; /// Compactly stores a set of `R0 member of [R1...Rn]` constraints, /// indexed by the region `R0`. -crate struct MemberConstraintSet<'tcx, R> +pub(crate) struct MemberConstraintSet<'tcx, R> where R: Copy + Eq, { @@ -28,17 +29,17 @@ where } /// Represents a `R0 member of [R1..Rn]` constraint -crate struct NllMemberConstraint<'tcx> { +pub(crate) struct NllMemberConstraint<'tcx> { next_constraint: Option, /// The span where the hidden type was instantiated. - crate definition_span: Span, + pub(crate) definition_span: Span, /// The hidden type in which `R0` appears. (Used in error reporting.) - crate hidden_ty: Ty<'tcx>, + pub(crate) hidden_ty: Ty<'tcx>, /// The region `R0`. - crate member_region_vid: ty::RegionVid, + pub(crate) member_region_vid: ty::RegionVid, /// Index of `R1` in `choice_regions` vector from `MemberConstraintSet`. start_index: usize, @@ -48,7 +49,7 @@ crate struct NllMemberConstraint<'tcx> { } rustc_index::newtype_index! { - crate struct NllMemberConstraintIndex { + pub(crate) struct NllMemberConstraintIndex { DEBUG_FORMAT = "MemberConstraintIndex({})" } } @@ -73,7 +74,7 @@ impl<'tcx> MemberConstraintSet<'tcx, ty::RegionVid> { /// within into `RegionVid` format -- it typically consults the /// `UniversalRegions` data structure that is known to the caller /// (but which this code is unaware of). - crate fn push_constraint( + pub(crate) fn push_constraint( &mut self, m_c: &MemberConstraint<'tcx>, mut to_region_vid: impl FnMut(ty::Region<'tcx>) -> ty::RegionVid, @@ -106,7 +107,7 @@ where /// the original `RegionVid` to an scc index. In some cases, we /// may have multiple `R1` values mapping to the same `R2` key -- that /// is ok, the two sets will be merged. - crate fn into_mapped( + pub(crate) fn into_mapped( self, mut map_fn: impl FnMut(R1) -> R2, ) -> MemberConstraintSet<'tcx, R2> @@ -140,21 +141,23 @@ where } } -impl MemberConstraintSet<'_, R> +impl<'tcx, R> MemberConstraintSet<'tcx, R> where R: Copy + Hash + Eq, { - crate fn all_indices(&self) -> impl Iterator + '_ { + pub(crate) fn all_indices( + &self, + ) -> impl Iterator + Captures<'tcx> + '_ { self.constraints.indices() } /// Iterate down the constraint indices associated with a given /// peek-region. You can then use `choice_regions` and other /// methods to access data. - crate fn indices( + pub(crate) fn indices( &self, member_region_vid: R, - ) -> impl Iterator + '_ { + ) -> impl Iterator + Captures<'tcx> + '_ { let mut next = self.first_constraints.get(&member_region_vid).cloned(); std::iter::from_fn(move || -> Option { if let Some(current) = next { @@ -172,7 +175,7 @@ where /// ```text /// R0 member of [R1..Rn] /// ``` - crate fn choice_regions(&self, pci: NllMemberConstraintIndex) -> &[ty::RegionVid] { + pub(crate) fn choice_regions(&self, pci: NllMemberConstraintIndex) -> &[ty::RegionVid] { let NllMemberConstraint { start_index, end_index, .. } = &self.constraints[pci]; &self.choice_regions[*start_index..*end_index] } diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index 927eb080b2008..2440ae9780d23 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -42,7 +42,7 @@ pub type PoloniusOutput = Output; /// The output of `nll::compute_regions`. This includes the computed `RegionInferenceContext`, any /// closure requirements to propagate, and any generated errors. -crate struct NllOutput<'tcx> { +pub(crate) struct NllOutput<'tcx> { pub regioncx: RegionInferenceContext<'tcx>, pub opaque_type_values: VecMap>, pub polonius_input: Option>, @@ -108,7 +108,7 @@ fn populate_polonius_move_facts( // We are at the terminator of an init that has a panic path, // and where the init should not happen on panic - for &successor in block_data.terminator().successors() { + for successor in block_data.terminator().successors() { if body[successor].is_cleanup { continue; } @@ -457,6 +457,6 @@ impl ToRegionVid for RegionVid { } } -crate trait ConstraintDescription { +pub(crate) trait ConstraintDescription { fn description(&self) -> &'static str; } diff --git a/compiler/rustc_borrowck/src/place_ext.rs b/compiler/rustc_borrowck/src/place_ext.rs index 83ff1595b0be4..93d202e49a159 100644 --- a/compiler/rustc_borrowck/src/place_ext.rs +++ b/compiler/rustc_borrowck/src/place_ext.rs @@ -5,7 +5,7 @@ use rustc_middle::mir::{Body, Mutability, Place}; use rustc_middle::ty::{self, TyCtxt}; /// Extension methods for the `Place` type. -crate trait PlaceExt<'tcx> { +pub(crate) trait PlaceExt<'tcx> { /// Returns `true` if we can safely ignore borrows of this place. /// This is true whenever there is no action that the user can do /// to the place `self` that would invalidate the borrow. This is true diff --git a/compiler/rustc_borrowck/src/places_conflict.rs b/compiler/rustc_borrowck/src/places_conflict.rs index 5a935c3b8fbfd..97335fd0dffae 100644 --- a/compiler/rustc_borrowck/src/places_conflict.rs +++ b/compiler/rustc_borrowck/src/places_conflict.rs @@ -14,7 +14,7 @@ use std::iter; /// being run in the calling context, the conservative choice is to assume the compared indices /// are disjoint (and therefore, do not overlap). #[derive(Copy, Clone, Debug, Eq, PartialEq)] -crate enum PlaceConflictBias { +pub(crate) enum PlaceConflictBias { Overlap, NoOverlap, } @@ -22,7 +22,7 @@ crate enum PlaceConflictBias { /// Helper function for checking if places conflict with a mutable borrow and deep access depth. /// This is used to check for places conflicting outside of the borrow checking code (such as in /// dataflow). -crate fn places_conflict<'tcx>( +pub(crate) fn places_conflict<'tcx>( tcx: TyCtxt<'tcx>, body: &Body<'tcx>, borrow_place: Place<'tcx>, diff --git a/compiler/rustc_borrowck/src/region_infer/graphviz.rs b/compiler/rustc_borrowck/src/region_infer/graphviz.rs index 95048d50f117f..f31ccd74ca6f7 100644 --- a/compiler/rustc_borrowck/src/region_infer/graphviz.rs +++ b/compiler/rustc_borrowck/src/region_infer/graphviz.rs @@ -11,12 +11,12 @@ use rustc_graphviz as dot; impl<'tcx> RegionInferenceContext<'tcx> { /// Write out the region constraint graph. - crate fn dump_graphviz_raw_constraints(&self, mut w: &mut dyn Write) -> io::Result<()> { + pub(crate) fn dump_graphviz_raw_constraints(&self, mut w: &mut dyn Write) -> io::Result<()> { dot::render(&RawConstraints { regioncx: self }, &mut w) } /// Write out the region constraint graph. - crate fn dump_graphviz_scc_constraints(&self, mut w: &mut dyn Write) -> io::Result<()> { + pub(crate) fn dump_graphviz_scc_constraints(&self, mut w: &mut dyn Write) -> io::Result<()> { let mut nodes_per_scc: IndexVec = self.constraint_sccs.all_sccs().map(|_| Vec::new()).collect(); diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index b2fa16ce125af..2c460bcb72d8b 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -87,7 +87,7 @@ pub struct RegionInferenceContext<'tcx> { /// Map closure bounds to a `Span` that should be used for error reporting. closure_bounds_mapping: - FxHashMap>, + FxHashMap, Span)>>, /// Map universe indexes to information on why we created it. universe_causes: FxHashMap>, @@ -259,7 +259,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { member_constraints_in: MemberConstraintSet<'tcx, RegionVid>, closure_bounds_mapping: FxHashMap< Location, - FxHashMap<(RegionVid, RegionVid), (ConstraintCategory, Span)>, + FxHashMap<(RegionVid, RegionVid), (ConstraintCategory<'tcx>, Span)>, >, universe_causes: FxHashMap>, type_tests: Vec>, @@ -513,26 +513,26 @@ impl<'tcx> RegionInferenceContext<'tcx> { } /// Adds annotations for `#[rustc_regions]`; see `UniversalRegions::annotate`. - crate fn annotate(&self, tcx: TyCtxt<'tcx>, err: &mut Diagnostic) { + pub(crate) fn annotate(&self, tcx: TyCtxt<'tcx>, err: &mut Diagnostic) { self.universal_regions.annotate(tcx, err) } /// Returns `true` if the region `r` contains the point `p`. /// /// Panics if called before `solve()` executes, - crate fn region_contains(&self, r: impl ToRegionVid, p: impl ToElementIndex) -> bool { + pub(crate) fn region_contains(&self, r: impl ToRegionVid, p: impl ToElementIndex) -> bool { let scc = self.constraint_sccs.scc(r.to_region_vid()); self.scc_values.contains(scc, p) } /// Returns access to the value of `r` for debugging purposes. - crate fn region_value_str(&self, r: RegionVid) -> String { + pub(crate) fn region_value_str(&self, r: RegionVid) -> String { let scc = self.constraint_sccs.scc(r.to_region_vid()); self.scc_values.region_value_str(scc) } /// Returns access to the value of `r` for debugging purposes. - crate fn region_universe(&self, r: RegionVid) -> ty::UniverseIndex { + pub(crate) fn region_universe(&self, r: RegionVid) -> ty::UniverseIndex { let scc = self.constraint_sccs.scc(r.to_region_vid()); self.scc_universes[scc] } @@ -1693,7 +1693,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// that cannot be named by `fr1`; in that case, we will require /// that `fr1: 'static` because it is the only way to `fr1: r` to /// be satisfied. (See `add_incompatible_universe`.) - crate fn provides_universal_region( + pub(crate) fn provides_universal_region( &self, r: RegionVid, fr1: RegionVid, @@ -1712,7 +1712,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// If `r2` represents a placeholder region, then this returns /// `true` if `r1` cannot name that placeholder in its /// value; otherwise, returns `false`. - crate fn cannot_name_placeholder(&self, r1: RegionVid, r2: RegionVid) -> bool { + pub(crate) fn cannot_name_placeholder(&self, r1: RegionVid, r2: RegionVid) -> bool { debug!("cannot_name_value_of(r1={:?}, r2={:?})", r1, r2); match self.definitions[r2].origin { @@ -1731,7 +1731,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { } } - crate fn retrieve_closure_constraint_info( + pub(crate) fn retrieve_closure_constraint_info( &self, _body: &Body<'tcx>, constraint: &OutlivesConstraint<'tcx>, @@ -1766,13 +1766,13 @@ impl<'tcx> RegionInferenceContext<'tcx> { } /// Finds a good `ObligationCause` to blame for the fact that `fr1` outlives `fr2`. - crate fn find_outlives_blame_span( + pub(crate) fn find_outlives_blame_span( &self, body: &Body<'tcx>, fr1: RegionVid, fr1_origin: NllRegionVariableOrigin, fr2: RegionVid, - ) -> (ConstraintCategory, ObligationCause<'tcx>) { + ) -> (ConstraintCategory<'tcx>, ObligationCause<'tcx>) { let BlameConstraint { category, cause, .. } = self.best_blame_constraint(body, fr1, fr1_origin, |r| { self.provides_universal_region(r, fr1, fr2) @@ -1788,7 +1788,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// /// Returns: a series of constraints as well as the region `R` /// that passed the target test. - crate fn find_constraint_paths_between_regions( + pub(crate) fn find_constraint_paths_between_regions( &self, from_region: RegionVid, target_test: impl Fn(RegionVid) -> bool, @@ -1882,7 +1882,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// Finds some region R such that `fr1: R` and `R` is live at `elem`. #[instrument(skip(self), level = "trace")] - crate fn find_sub_region_live_at(&self, fr1: RegionVid, elem: Location) -> RegionVid { + pub(crate) fn find_sub_region_live_at(&self, fr1: RegionVid, elem: Location) -> RegionVid { trace!(scc = ?self.constraint_sccs.scc(fr1)); trace!(universe = ?self.scc_universes[self.constraint_sccs.scc(fr1)]); self.find_constraint_paths_between_regions(fr1, |r| { @@ -1919,7 +1919,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { } /// Get the region outlived by `longer_fr` and live at `element`. - crate fn region_from_element( + pub(crate) fn region_from_element( &self, longer_fr: RegionVid, element: &RegionElement, @@ -1939,17 +1939,17 @@ impl<'tcx> RegionInferenceContext<'tcx> { } /// Get the region definition of `r`. - crate fn region_definition(&self, r: RegionVid) -> &RegionDefinition<'tcx> { + pub(crate) fn region_definition(&self, r: RegionVid) -> &RegionDefinition<'tcx> { &self.definitions[r] } /// Check if the SCC of `r` contains `upper`. - crate fn upper_bound_in_region_scc(&self, r: RegionVid, upper: RegionVid) -> bool { + pub(crate) fn upper_bound_in_region_scc(&self, r: RegionVid, upper: RegionVid) -> bool { let r_scc = self.constraint_sccs.scc(r); self.scc_values.contains(r_scc, upper) } - crate fn universal_regions(&self) -> &UniversalRegions<'tcx> { + pub(crate) fn universal_regions(&self) -> &UniversalRegions<'tcx> { self.universal_regions.as_ref() } @@ -1959,7 +1959,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// creating a constraint path that forces `R` to outlive /// `from_region`, and then finding the best choices within that /// path to blame. - crate fn best_blame_constraint( + pub(crate) fn best_blame_constraint( &self, body: &Body<'tcx>, from_region: RegionVid, @@ -2171,7 +2171,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { categorized_path.remove(0) } - crate fn universe_info(&self, universe: ty::UniverseIndex) -> UniverseInfo<'tcx> { + pub(crate) fn universe_info(&self, universe: ty::UniverseIndex) -> UniverseInfo<'tcx> { self.universe_causes[&universe].clone() } } @@ -2270,7 +2270,7 @@ impl<'tcx> ClosureRegionRequirementsExt<'tcx> for ClosureRegionRequirements<'tcx #[derive(Clone, Debug)] pub struct BlameConstraint<'tcx> { - pub category: ConstraintCategory, + pub category: ConstraintCategory<'tcx>, pub from_closure: bool, pub cause: ObligationCause<'tcx>, pub variance_info: ty::VarianceDiagInfo<'tcx>, diff --git a/compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs b/compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs index 056907dcb1656..1e6798eee3df8 100644 --- a/compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs +++ b/compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs @@ -8,7 +8,7 @@ use rustc_middle::ty::RegionVid; use std::ops::Range; use std::rc::Rc; -crate struct ReverseSccGraph { +pub(crate) struct ReverseSccGraph { graph: VecGraph, /// For each SCC, the range of `universal_regions` that use that SCC as /// their value. diff --git a/compiler/rustc_borrowck/src/region_infer/values.rs b/compiler/rustc_borrowck/src/region_infer/values.rs index 4a70535c63bea..c81ef10f7c740 100644 --- a/compiler/rustc_borrowck/src/region_infer/values.rs +++ b/compiler/rustc_borrowck/src/region_infer/values.rs @@ -10,7 +10,7 @@ use std::fmt::Debug; use std::rc::Rc; /// Maps between a `Location` and a `PointIndex` (and vice versa). -crate struct RegionValueElements { +pub(crate) struct RegionValueElements { /// For each basic block, how many points are contained within? statements_before_block: IndexVec, @@ -22,7 +22,7 @@ crate struct RegionValueElements { } impl RegionValueElements { - crate fn new(body: &Body<'_>) -> Self { + pub(crate) fn new(body: &Body<'_>) -> Self { let mut num_points = 0; let statements_before_block: IndexVec = body .basic_blocks() @@ -45,30 +45,30 @@ impl RegionValueElements { } /// Total number of point indices - crate fn num_points(&self) -> usize { + pub(crate) fn num_points(&self) -> usize { self.num_points } /// Converts a `Location` into a `PointIndex`. O(1). - crate fn point_from_location(&self, location: Location) -> PointIndex { + pub(crate) fn point_from_location(&self, location: Location) -> PointIndex { let Location { block, statement_index } = location; let start_index = self.statements_before_block[block]; PointIndex::new(start_index + statement_index) } /// Converts a `Location` into a `PointIndex`. O(1). - crate fn entry_point(&self, block: BasicBlock) -> PointIndex { + pub(crate) fn entry_point(&self, block: BasicBlock) -> PointIndex { let start_index = self.statements_before_block[block]; PointIndex::new(start_index) } /// Return the PointIndex for the block start of this index. - crate fn to_block_start(&self, index: PointIndex) -> PointIndex { + pub(crate) fn to_block_start(&self, index: PointIndex) -> PointIndex { PointIndex::new(self.statements_before_block[self.basic_blocks[index]]) } /// Converts a `PointIndex` back to a location. O(1). - crate fn to_location(&self, index: PointIndex) -> Location { + pub(crate) fn to_location(&self, index: PointIndex) -> Location { assert!(index.index() < self.num_points); let block = self.basic_blocks[index]; let start_index = self.statements_before_block[block]; @@ -80,7 +80,7 @@ impl RegionValueElements { /// out of range (because they round up to the nearest 2^N number /// of bits). Use this function to filter such points out if you /// like. - crate fn point_in_range(&self, index: PointIndex) -> bool { + pub(crate) fn point_in_range(&self, index: PointIndex) -> bool { index.index() < self.num_points } } @@ -99,7 +99,7 @@ rustc_index::newtype_index! { /// An individual element in a region value -- the value of a /// particular region variable consists of a set of these elements. #[derive(Debug, Clone)] -crate enum RegionElement { +pub(crate) enum RegionElement { /// A point in the control-flow graph. Location(Location), @@ -114,7 +114,7 @@ crate enum RegionElement { /// When we initially compute liveness, we use an interval matrix storing /// liveness ranges for each region-vid. -crate struct LivenessValues { +pub(crate) struct LivenessValues { elements: Rc, points: SparseIntervalMatrix, } @@ -123,18 +123,18 @@ impl LivenessValues { /// Creates a new set of "region values" that tracks causal information. /// Each of the regions in num_region_variables will be initialized with an /// empty set of points and no causal information. - crate fn new(elements: Rc) -> Self { + pub(crate) fn new(elements: Rc) -> Self { Self { points: SparseIntervalMatrix::new(elements.num_points), elements } } /// Iterate through each region that has a value in this set. - crate fn rows(&self) -> impl Iterator { + pub(crate) fn rows(&self) -> impl Iterator { self.points.rows() } /// Adds the given element to the value for the given region. Returns whether /// the element is newly added (i.e., was not already present). - crate fn add_element(&mut self, row: N, location: Location) -> bool { + pub(crate) fn add_element(&mut self, row: N, location: Location) -> bool { debug!("LivenessValues::add(r={:?}, location={:?})", row, location); let index = self.elements.point_from_location(location); self.points.insert(row, index) @@ -142,24 +142,24 @@ impl LivenessValues { /// Adds all the elements in the given bit array into the given /// region. Returns whether any of them are newly added. - crate fn add_elements(&mut self, row: N, locations: &IntervalSet) -> bool { + pub(crate) fn add_elements(&mut self, row: N, locations: &IntervalSet) -> bool { debug!("LivenessValues::add_elements(row={:?}, locations={:?})", row, locations); self.points.union_row(row, locations) } /// Adds all the control-flow points to the values for `r`. - crate fn add_all_points(&mut self, row: N) { + pub(crate) fn add_all_points(&mut self, row: N) { self.points.insert_all_into_row(row); } /// Returns `true` if the region `r` contains the given element. - crate fn contains(&self, row: N, location: Location) -> bool { + pub(crate) fn contains(&self, row: N, location: Location) -> bool { let index = self.elements.point_from_location(location); self.points.row(row).map_or(false, |r| r.contains(index)) } /// Returns an iterator of all the elements contained by the region `r` - crate fn get_elements(&self, row: N) -> impl Iterator + '_ { + pub(crate) fn get_elements(&self, row: N) -> impl Iterator + '_ { self.points .row(row) .into_iter() @@ -169,7 +169,7 @@ impl LivenessValues { } /// Returns a "pretty" string value of the region. Meant for debugging. - crate fn region_value_str(&self, r: N) -> String { + pub(crate) fn region_value_str(&self, r: N) -> String { region_value_str(self.get_elements(r).map(RegionElement::Location)) } } @@ -178,25 +178,28 @@ impl LivenessValues { /// rustc to the internal `PlaceholderIndex` values that are used in /// NLL. #[derive(Default)] -crate struct PlaceholderIndices { +pub(crate) struct PlaceholderIndices { indices: FxIndexSet, } impl PlaceholderIndices { - crate fn insert(&mut self, placeholder: ty::PlaceholderRegion) -> PlaceholderIndex { + pub(crate) fn insert(&mut self, placeholder: ty::PlaceholderRegion) -> PlaceholderIndex { let (index, _) = self.indices.insert_full(placeholder); index.into() } - crate fn lookup_index(&self, placeholder: ty::PlaceholderRegion) -> PlaceholderIndex { + pub(crate) fn lookup_index(&self, placeholder: ty::PlaceholderRegion) -> PlaceholderIndex { self.indices.get_index_of(&placeholder).unwrap().into() } - crate fn lookup_placeholder(&self, placeholder: PlaceholderIndex) -> ty::PlaceholderRegion { + pub(crate) fn lookup_placeholder( + &self, + placeholder: PlaceholderIndex, + ) -> ty::PlaceholderRegion { self.indices[placeholder.index()] } - crate fn len(&self) -> usize { + pub(crate) fn len(&self) -> usize { self.indices.len() } } @@ -220,7 +223,7 @@ impl PlaceholderIndices { /// because (since it is returned) it must live for at least `'a`. But /// it would also contain various points from within the function. #[derive(Clone)] -crate struct RegionValues { +pub(crate) struct RegionValues { elements: Rc, placeholder_indices: Rc, points: SparseIntervalMatrix, @@ -235,7 +238,7 @@ impl RegionValues { /// Creates a new set of "region values" that tracks causal information. /// Each of the regions in num_region_variables will be initialized with an /// empty set of points and no causal information. - crate fn new( + pub(crate) fn new( elements: &Rc, num_universal_regions: usize, placeholder_indices: &Rc, @@ -252,33 +255,33 @@ impl RegionValues { /// Adds the given element to the value for the given region. Returns whether /// the element is newly added (i.e., was not already present). - crate fn add_element(&mut self, r: N, elem: impl ToElementIndex) -> bool { + pub(crate) fn add_element(&mut self, r: N, elem: impl ToElementIndex) -> bool { debug!("add(r={:?}, elem={:?})", r, elem); elem.add_to_row(self, r) } /// Adds all the control-flow points to the values for `r`. - crate fn add_all_points(&mut self, r: N) { + pub(crate) fn add_all_points(&mut self, r: N) { self.points.insert_all_into_row(r); } /// Adds all elements in `r_from` to `r_to` (because e.g., `r_to: /// r_from`). - crate fn add_region(&mut self, r_to: N, r_from: N) -> bool { + pub(crate) fn add_region(&mut self, r_to: N, r_from: N) -> bool { self.points.union_rows(r_from, r_to) | self.free_regions.union_rows(r_from, r_to) | self.placeholders.union_rows(r_from, r_to) } /// Returns `true` if the region `r` contains the given element. - crate fn contains(&self, r: N, elem: impl ToElementIndex) -> bool { + pub(crate) fn contains(&self, r: N, elem: impl ToElementIndex) -> bool { elem.contained_in_row(self, r) } /// `self[to] |= values[from]`, essentially: that is, take all the /// elements for the region `from` from `values` and add them to /// the region `to` in `self`. - crate fn merge_liveness(&mut self, to: N, from: M, values: &LivenessValues) { + pub(crate) fn merge_liveness(&mut self, to: N, from: M, values: &LivenessValues) { if let Some(set) = values.points.row(from) { self.points.union_row(to, set); } @@ -286,7 +289,7 @@ impl RegionValues { /// Returns `true` if `sup_region` contains all the CFG points that /// `sub_region` contains. Ignores universal regions. - crate fn contains_points(&self, sup_region: N, sub_region: N) -> bool { + pub(crate) fn contains_points(&self, sup_region: N, sub_region: N) -> bool { if let Some(sub_row) = self.points.row(sub_region) { if let Some(sup_row) = self.points.row(sup_region) { sup_row.superset(sub_row) @@ -301,7 +304,7 @@ impl RegionValues { } /// Returns the locations contained within a given region `r`. - crate fn locations_outlived_by<'a>(&'a self, r: N) -> impl Iterator + 'a { + pub(crate) fn locations_outlived_by<'a>(&'a self, r: N) -> impl Iterator + 'a { self.points.row(r).into_iter().flat_map(move |set| { set.iter() .take_while(move |&p| self.elements.point_in_range(p)) @@ -310,7 +313,7 @@ impl RegionValues { } /// Returns just the universal regions that are contained in a given region's value. - crate fn universal_regions_outlived_by<'a>( + pub(crate) fn universal_regions_outlived_by<'a>( &'a self, r: N, ) -> impl Iterator + 'a { @@ -318,7 +321,7 @@ impl RegionValues { } /// Returns all the elements contained in a given region's value. - crate fn placeholders_contained_in<'a>( + pub(crate) fn placeholders_contained_in<'a>( &'a self, r: N, ) -> impl Iterator + 'a { @@ -330,7 +333,10 @@ impl RegionValues { } /// Returns all the elements contained in a given region's value. - crate fn elements_contained_in<'a>(&'a self, r: N) -> impl Iterator + 'a { + pub(crate) fn elements_contained_in<'a>( + &'a self, + r: N, + ) -> impl Iterator + 'a { let points_iter = self.locations_outlived_by(r).map(RegionElement::Location); let free_regions_iter = @@ -343,12 +349,12 @@ impl RegionValues { } /// Returns a "pretty" string value of the region. Meant for debugging. - crate fn region_value_str(&self, r: N) -> String { + pub(crate) fn region_value_str(&self, r: N) -> String { region_value_str(self.elements_contained_in(r)) } } -crate trait ToElementIndex: Debug + Copy { +pub(crate) trait ToElementIndex: Debug + Copy { fn add_to_row(self, values: &mut RegionValues, row: N) -> bool; fn contained_in_row(self, values: &RegionValues, row: N) -> bool; @@ -388,7 +394,7 @@ impl ToElementIndex for ty::PlaceholderRegion { } } -crate fn location_set_str( +pub(crate) fn location_set_str( elements: &RegionValueElements, points: impl IntoIterator, ) -> String { diff --git a/compiler/rustc_borrowck/src/type_check/canonical.rs b/compiler/rustc_borrowck/src/type_check/canonical.rs index 3856b7f4a4b82..55c0bf05b4873 100644 --- a/compiler/rustc_borrowck/src/type_check/canonical.rs +++ b/compiler/rustc_borrowck/src/type_check/canonical.rs @@ -28,7 +28,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { pub(super) fn fully_perform_op( &mut self, locations: Locations, - category: ConstraintCategory, + category: ConstraintCategory<'tcx>, op: Op, ) -> Fallible where @@ -83,11 +83,12 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { instantiated } + #[instrument(skip(self), level = "debug")] pub(super) fn prove_trait_ref( &mut self, trait_ref: ty::TraitRef<'tcx>, locations: Locations, - category: ConstraintCategory, + category: ConstraintCategory<'tcx>, ) { self.prove_predicates( Some(ty::Binder::dummy(ty::PredicateKind::Trait(ty::TraitPredicate { @@ -113,6 +114,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { .into_iter() .zip(instantiated_predicates.spans.into_iter()) { + debug!(?predicate); let predicate = self.normalize(predicate, locations); self.prove_predicate(predicate, locations, ConstraintCategory::Predicate(span)); } @@ -122,7 +124,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { &mut self, predicates: impl IntoIterator>, locations: Locations, - category: ConstraintCategory, + category: ConstraintCategory<'tcx>, ) { for predicate in predicates { let predicate = predicate.to_predicate(self.tcx()); @@ -137,7 +139,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { &mut self, predicate: ty::Predicate<'tcx>, locations: Locations, - category: ConstraintCategory, + category: ConstraintCategory<'tcx>, ) { let param_env = self.param_env; self.fully_perform_op( diff --git a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs index 21190a850b7b1..3c9e3870aeac4 100644 --- a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs +++ b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs @@ -18,7 +18,7 @@ use crate::{ universal_regions::UniversalRegions, }; -crate struct ConstraintConversion<'a, 'tcx> { +pub(crate) struct ConstraintConversion<'a, 'tcx> { infcx: &'a InferCtxt<'a, 'tcx>, tcx: TyCtxt<'tcx>, universal_regions: &'a UniversalRegions<'tcx>, @@ -27,12 +27,12 @@ crate struct ConstraintConversion<'a, 'tcx> { param_env: ty::ParamEnv<'tcx>, locations: Locations, span: Span, - category: ConstraintCategory, + category: ConstraintCategory<'tcx>, constraints: &'a mut MirTypeckRegionConstraints<'tcx>, } impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { - crate fn new( + pub(crate) fn new( infcx: &'a InferCtxt<'a, 'tcx>, universal_regions: &'a UniversalRegions<'tcx>, region_bound_pairs: &'a RegionBoundPairs<'tcx>, @@ -40,7 +40,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { param_env: ty::ParamEnv<'tcx>, locations: Locations, span: Span, - category: ConstraintCategory, + category: ConstraintCategory<'tcx>, constraints: &'a mut MirTypeckRegionConstraints<'tcx>, ) -> Self { Self { diff --git a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs index f08f2e1b12da6..670b5549afc1d 100644 --- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs +++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs @@ -19,7 +19,7 @@ use crate::{ }; #[derive(Debug)] -crate struct UniversalRegionRelations<'tcx> { +pub(crate) struct UniversalRegionRelations<'tcx> { universal_regions: Rc>, /// Stores the outlives relations that are known to hold from the @@ -52,13 +52,13 @@ type RegionBoundPairs<'tcx> = Vec<(ty::Region<'tcx>, GenericKind<'tcx>)>; /// then the output type as the last element. type NormalizedInputsAndOutput<'tcx> = Vec>; -crate struct CreateResult<'tcx> { - crate universal_region_relations: Frozen>, - crate region_bound_pairs: RegionBoundPairs<'tcx>, - crate normalized_inputs_and_output: NormalizedInputsAndOutput<'tcx>, +pub(crate) struct CreateResult<'tcx> { + pub(crate) universal_region_relations: Frozen>, + pub(crate) region_bound_pairs: RegionBoundPairs<'tcx>, + pub(crate) normalized_inputs_and_output: NormalizedInputsAndOutput<'tcx>, } -crate fn create<'tcx>( +pub(crate) fn create<'tcx>( infcx: &InferCtxt<'_, 'tcx>, param_env: ty::ParamEnv<'tcx>, implicit_region_bound: Option>, @@ -96,7 +96,7 @@ impl UniversalRegionRelations<'_> { /// /// (See `TransitiveRelation::postdom_upper_bound` for details on /// the postdominating upper bound in general.) - crate fn postdom_upper_bound(&self, fr1: RegionVid, fr2: RegionVid) -> RegionVid { + pub(crate) fn postdom_upper_bound(&self, fr1: RegionVid, fr2: RegionVid) -> RegionVid { assert!(self.universal_regions.is_universal_region(fr1)); assert!(self.universal_regions.is_universal_region(fr2)); self.inverse_outlives @@ -109,7 +109,7 @@ impl UniversalRegionRelations<'_> { /// outlives `fr` and (b) is not local. /// /// (*) If there are multiple competing choices, we return all of them. - crate fn non_local_upper_bounds<'a>(&'a self, fr: RegionVid) -> Vec { + pub(crate) fn non_local_upper_bounds<'a>(&'a self, fr: RegionVid) -> Vec { debug!("non_local_upper_bound(fr={:?})", fr); let res = self.non_local_bounds(&self.inverse_outlives, fr); assert!(!res.is_empty(), "can't find an upper bound!?"); @@ -118,7 +118,7 @@ impl UniversalRegionRelations<'_> { /// Returns the "postdominating" bound of the set of /// `non_local_upper_bounds` for the given region. - crate fn non_local_upper_bound(&self, fr: RegionVid) -> RegionVid { + pub(crate) fn non_local_upper_bound(&self, fr: RegionVid) -> RegionVid { let upper_bounds = self.non_local_upper_bounds(fr); // In case we find more than one, reduce to one for @@ -147,7 +147,7 @@ impl UniversalRegionRelations<'_> { /// /// (*) If there are multiple competing choices, we pick the "postdominating" /// one. See `TransitiveRelation::postdom_upper_bound` for details. - crate fn non_local_lower_bound(&self, fr: RegionVid) -> Option { + pub(crate) fn non_local_lower_bound(&self, fr: RegionVid) -> Option { debug!("non_local_lower_bound(fr={:?})", fr); let lower_bounds = self.non_local_bounds(&self.outlives, fr); @@ -203,18 +203,18 @@ impl UniversalRegionRelations<'_> { /// Returns `true` if fr1 is known to outlive fr2. /// /// This will only ever be true for universally quantified regions. - crate fn outlives(&self, fr1: RegionVid, fr2: RegionVid) -> bool { + pub(crate) fn outlives(&self, fr1: RegionVid, fr2: RegionVid) -> bool { self.outlives.contains(fr1, fr2) } /// Returns a vector of free regions `x` such that `fr1: x` is /// known to hold. - crate fn regions_outlived_by(&self, fr1: RegionVid) -> Vec { + pub(crate) fn regions_outlived_by(&self, fr1: RegionVid) -> Vec { self.outlives.reachable_from(fr1) } /// Returns the _non-transitive_ set of known `outlives` constraints between free regions. - crate fn known_outlives(&self) -> impl Iterator + '_ { + pub(crate) fn known_outlives(&self) -> impl Iterator + '_ { self.outlives.base_edges() } } @@ -232,7 +232,7 @@ struct UniversalRegionRelationsBuilder<'this, 'tcx> { } impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { - crate fn create(mut self) -> CreateResult<'tcx> { + pub(crate) fn create(mut self) -> CreateResult<'tcx> { let unnormalized_input_output_tys = self .universal_regions .unnormalized_input_tys diff --git a/compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs b/compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs index dd23683fae8de..b88f6e689cc80 100644 --- a/compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs +++ b/compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs @@ -18,7 +18,7 @@ use crate::region_infer::values::{PointIndex, RegionValueElements}; /// (and code simplicity) was favored. The rationale is that we only keep /// a small number of `IndexVec`s throughout the entire analysis while, in /// contrast, we're accessing each `Local` *many* times. -crate struct LocalUseMap { +pub(crate) struct LocalUseMap { /// Head of a linked list of **definitions** of each variable -- /// definition in this context means assignment, e.g., `x` is /// defined in `x = y` but not `y`; that first def is the head of @@ -58,7 +58,11 @@ impl vll::LinkElem for Appearance { } impl LocalUseMap { - crate fn build(live_locals: &[Local], elements: &RegionValueElements, body: &Body<'_>) -> Self { + pub(crate) fn build( + live_locals: &[Local], + elements: &RegionValueElements, + body: &Body<'_>, + ) -> Self { let nones = IndexVec::from_elem_n(None, body.local_decls.len()); let mut local_use_map = LocalUseMap { first_def_at: nones.clone(), @@ -81,17 +85,17 @@ impl LocalUseMap { local_use_map } - crate fn defs(&self, local: Local) -> impl Iterator + '_ { + pub(crate) fn defs(&self, local: Local) -> impl Iterator + '_ { vll::iter(self.first_def_at[local], &self.appearances) .map(move |aa| self.appearances[aa].point_index) } - crate fn uses(&self, local: Local) -> impl Iterator + '_ { + pub(crate) fn uses(&self, local: Local) -> impl Iterator + '_ { vll::iter(self.first_use_at[local], &self.appearances) .map(move |aa| self.appearances[aa].point_index) } - crate fn drops(&self, local: Local) -> impl Iterator + '_ { + pub(crate) fn drops(&self, local: Local) -> impl Iterator + '_ { vll::iter(self.first_drop_at[local], &self.appearances) .map(move |aa| self.appearances[aa].point_index) } diff --git a/compiler/rustc_borrowck/src/type_check/liveness/polonius.rs b/compiler/rustc_borrowck/src/type_check/liveness/polonius.rs index ee067c4872f67..8070f3579194d 100644 --- a/compiler/rustc_borrowck/src/type_check/liveness/polonius.rs +++ b/compiler/rustc_borrowck/src/type_check/liveness/polonius.rs @@ -10,17 +10,17 @@ use super::TypeChecker; type VarPointRelation = Vec<(Local, LocationIndex)>; type PathPointRelation = Vec<(MovePathIndex, LocationIndex)>; -struct UseFactsExtractor<'me> { +struct UseFactsExtractor<'me, 'tcx> { var_defined_at: &'me mut VarPointRelation, var_used_at: &'me mut VarPointRelation, location_table: &'me LocationTable, var_dropped_at: &'me mut VarPointRelation, - move_data: &'me MoveData<'me>, + move_data: &'me MoveData<'tcx>, path_accessed_at_base: &'me mut PathPointRelation, } // A Visitor to walk through the MIR and extract point-wise facts -impl UseFactsExtractor<'_> { +impl UseFactsExtractor<'_, '_> { fn location_to_index(&self, location: Location) -> LocationIndex { self.location_table.mid_index(location) } @@ -53,7 +53,7 @@ impl UseFactsExtractor<'_> { } } -impl Visitor<'_> for UseFactsExtractor<'_> { +impl<'a, 'tcx> Visitor<'tcx> for UseFactsExtractor<'a, 'tcx> { fn visit_local(&mut self, &local: &Local, context: PlaceContext, location: Location) { match def_use::categorize(context) { Some(DefUse::Def) => self.insert_def(local, location), @@ -63,7 +63,7 @@ impl Visitor<'_> for UseFactsExtractor<'_> { } } - fn visit_place(&mut self, place: &Place<'_>, context: PlaceContext, location: Location) { + fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, location: Location) { self.super_place(place, context, location); match context { PlaceContext::NonMutatingUse(_) => { @@ -82,11 +82,11 @@ impl Visitor<'_> for UseFactsExtractor<'_> { } } -pub(super) fn populate_access_facts<'tcx>( - typeck: &mut TypeChecker<'_, 'tcx>, +pub(super) fn populate_access_facts<'a, 'tcx>( + typeck: &mut TypeChecker<'a, 'tcx>, body: &Body<'tcx>, location_table: &LocationTable, - move_data: &MoveData<'_>, + move_data: &MoveData<'tcx>, dropped_at: &mut Vec<(Local, Location)>, ) { debug!("populate_access_facts()"); diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 4b905c23e156a..abf77acb8c7ad 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -94,7 +94,7 @@ mod canonical; mod constraint_conversion; pub mod free_region_relations; mod input_output; -crate mod liveness; +pub(crate) mod liveness; mod relate_tys; /// Type checks the given `mir` in the context of the inference @@ -162,6 +162,8 @@ pub(crate) fn type_check<'mir, 'tcx>( &mut constraints, ); + debug!(?normalized_inputs_and_output); + for u in ty::UniverseIndex::ROOT..infcx.universe() { let info = UniverseInfo::other(); constraints.universe_causes.insert(u, info); @@ -185,6 +187,7 @@ pub(crate) fn type_check<'mir, 'tcx>( implicit_region_bound, &mut borrowck_context, |mut cx| { + debug!("inside extra closure of type_check_internal"); cx.equate_inputs_and_outputs(&body, universal_regions, &normalized_inputs_and_output); liveness::generate( &mut cx, @@ -257,6 +260,7 @@ fn type_check_internal<'a, 'tcx, R>( borrowck_context: &'a mut BorrowCheckContext<'a, 'tcx>, extra: impl FnOnce(TypeChecker<'a, 'tcx>) -> R, ) -> R { + debug!("body: {:#?}", body); let mut checker = TypeChecker::new( infcx, body, @@ -897,28 +901,29 @@ struct BorrowCheckContext<'a, 'tcx> { upvars: &'a [Upvar<'tcx>], } -crate struct MirTypeckResults<'tcx> { - crate constraints: MirTypeckRegionConstraints<'tcx>, - crate universal_region_relations: Frozen>, - crate opaque_type_values: VecMap, (OpaqueHiddenType<'tcx>, OpaqueTyOrigin)>, +pub(crate) struct MirTypeckResults<'tcx> { + pub(crate) constraints: MirTypeckRegionConstraints<'tcx>, + pub(crate) universal_region_relations: Frozen>, + pub(crate) opaque_type_values: + VecMap, (OpaqueHiddenType<'tcx>, OpaqueTyOrigin)>, } /// A collection of region constraints that must be satisfied for the /// program to be considered well-typed. -crate struct MirTypeckRegionConstraints<'tcx> { +pub(crate) struct MirTypeckRegionConstraints<'tcx> { /// Maps from a `ty::Placeholder` to the corresponding /// `PlaceholderIndex` bit that we will use for it. /// /// To keep everything in sync, do not insert this set /// directly. Instead, use the `placeholder_region` helper. - crate placeholder_indices: PlaceholderIndices, + pub(crate) placeholder_indices: PlaceholderIndices, /// Each time we add a placeholder to `placeholder_indices`, we /// also create a corresponding "representative" region vid for /// that wraps it. This vector tracks those. This way, when we /// convert the same `ty::RePlaceholder(p)` twice, we can map to /// the same underlying `RegionVid`. - crate placeholder_index_to_region: IndexVec>, + pub(crate) placeholder_index_to_region: IndexVec>, /// In general, the type-checker is not responsible for enforcing /// liveness constraints; this job falls to the region inferencer, @@ -927,18 +932,18 @@ crate struct MirTypeckRegionConstraints<'tcx> { /// not otherwise appear in the MIR -- in particular, the /// late-bound regions that it instantiates at call-sites -- and /// hence it must report on their liveness constraints. - crate liveness_constraints: LivenessValues, + pub(crate) liveness_constraints: LivenessValues, - crate outlives_constraints: OutlivesConstraintSet<'tcx>, + pub(crate) outlives_constraints: OutlivesConstraintSet<'tcx>, - crate member_constraints: MemberConstraintSet<'tcx, RegionVid>, + pub(crate) member_constraints: MemberConstraintSet<'tcx, RegionVid>, - crate closure_bounds_mapping: - FxHashMap>, + pub(crate) closure_bounds_mapping: + FxHashMap, Span)>>, - crate universe_causes: FxHashMap>, + pub(crate) universe_causes: FxHashMap>, - crate type_tests: Vec>, + pub(crate) type_tests: Vec>, } impl<'tcx> MirTypeckRegionConstraints<'tcx> { @@ -1124,7 +1129,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { fn push_region_constraints( &mut self, locations: Locations, - category: ConstraintCategory, + category: ConstraintCategory<'tcx>, data: &QueryRegionConstraints<'tcx>, ) { debug!("constraints generated: {:#?}", data); @@ -1149,7 +1154,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { sub: Ty<'tcx>, sup: Ty<'tcx>, locations: Locations, - category: ConstraintCategory, + category: ConstraintCategory<'tcx>, ) -> Fallible<()> { // Use this order of parameters because the sup type is usually the // "expected" type in diagnostics. @@ -1162,7 +1167,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { expected: Ty<'tcx>, found: Ty<'tcx>, locations: Locations, - category: ConstraintCategory, + category: ConstraintCategory<'tcx>, ) -> Fallible<()> { self.relate_types(expected, ty::Variance::Invariant, found, locations, category) } @@ -1174,7 +1179,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { v: ty::Variance, user_ty: &UserTypeProjection, locations: Locations, - category: ConstraintCategory, + category: ConstraintCategory<'tcx>, ) -> Fallible<()> { let annotated_type = self.user_type_annotations[user_ty.base].inferred_ty; let mut curr_projected_ty = PlaceTy::from_ty(annotated_type); @@ -1211,6 +1216,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { #[instrument(skip(self, body, location), level = "debug")] fn check_stmt(&mut self, body: &Body<'tcx>, stmt: &Statement<'tcx>, location: Location) { let tcx = self.tcx(); + debug!("stmt kind: {:?}", stmt.kind); match stmt.kind { StatementKind::Assign(box (ref place, ref rv)) => { // Assignments to temporaries are not "interesting"; @@ -1250,9 +1256,13 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { ); let place_ty = place.ty(body, tcx).ty; + debug!(?place_ty); let place_ty = self.normalize(place_ty, location); + debug!("place_ty normalized: {:?}", place_ty); let rv_ty = rv.ty(body, tcx); + debug!(?rv_ty); let rv_ty = self.normalize(rv_ty, location); + debug!("normalized rv_ty: {:?}", rv_ty); if let Err(terr) = self.sub_types(rv_ty, place_ty, location.to_locations(), category) { @@ -1346,6 +1356,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { term_location: Location, ) { let tcx = self.tcx(); + debug!("terminator kind: {:?}", term.kind); match term.kind { TerminatorKind::Goto { .. } | TerminatorKind::Resume @@ -1402,14 +1413,22 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } // FIXME: check the values } - TerminatorKind::Call { ref func, ref args, ref destination, from_hir_call, .. } => { + TerminatorKind::Call { + ref func, + ref args, + ref destination, + from_hir_call, + target, + .. + } => { self.check_operand(func, term_location); for arg in args { self.check_operand(arg, term_location); } let func_ty = func.ty(body, tcx); - debug!("check_terminator: call, func_ty={:?}", func_ty); + debug!("func_ty.kind: {:?}", func_ty.kind()); + let sig = match func_ty.kind() { ty::FnDef(..) | ty::FnPtr(_) => func_ty.fn_sig(tcx), _ => { @@ -1422,8 +1441,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { LateBoundRegionConversionTime::FnCall, sig, ); + debug!(?sig); let sig = self.normalize(sig, term_location); - self.check_call_dest(body, term, &sig, destination, term_location); + self.check_call_dest(body, term, &sig, *destination, target, term_location); self.prove_predicates( sig.inputs_and_output @@ -1501,15 +1521,16 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { body: &Body<'tcx>, term: &Terminator<'tcx>, sig: &ty::FnSig<'tcx>, - destination: &Option<(Place<'tcx>, BasicBlock)>, + destination: Place<'tcx>, + target: Option, term_location: Location, ) { let tcx = self.tcx(); - match *destination { - Some((ref dest, _target_block)) => { - let dest_ty = dest.ty(body, tcx).ty; + match target { + Some(_) => { + let dest_ty = destination.ty(body, tcx).ty; let dest_ty = self.normalize(dest_ty, term_location); - let category = match dest.as_local() { + let category = match destination.as_local() { Some(RETURN_PLACE) => { if let BorrowCheckContext { universal_regions: @@ -1581,11 +1602,20 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { if args.len() < sig.inputs().len() || (args.len() > sig.inputs().len() && !sig.c_variadic) { span_mirbug!(self, term, "call to {:?} with wrong # of args", sig); } + + let func_ty = if let TerminatorKind::Call { func, .. } = &term.kind { + Some(func.ty(body, self.infcx.tcx)) + } else { + None + }; + debug!(?func_ty); + for (n, (fn_arg, op_arg)) in iter::zip(sig.inputs(), args).enumerate() { let op_arg_ty = op_arg.ty(body, self.tcx()); + let op_arg_ty = self.normalize(op_arg_ty, term_location); let category = if from_hir_call { - ConstraintCategory::CallArgument + ConstraintCategory::CallArgument(func_ty) } else { ConstraintCategory::Boring }; @@ -1658,8 +1688,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { self.assert_iscleanup(body, block_data, unwind, true); } } - TerminatorKind::Call { ref destination, cleanup, .. } => { - if let &Some((_, target)) = destination { + TerminatorKind::Call { ref target, cleanup, .. } => { + if let &Some(target) = target { self.assert_iscleanup(body, block_data, target, is_cleanup); } if let Some(cleanup) = cleanup { @@ -1837,6 +1867,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } + #[instrument(skip(self, body), level = "debug")] fn check_rvalue(&mut self, body: &Body<'tcx>, rvalue: &Rvalue<'tcx>, location: Location) { let tcx = self.tcx(); @@ -2116,6 +2147,18 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } + CastKind::PointerExposeAddress => { + let ty_from = op.ty(body, tcx); + let cast_ty_from = CastTy::from_ty(ty_from); + let cast_ty_to = CastTy::from_ty(*ty); + match (cast_ty_from, cast_ty_to) { + (Some(CastTy::Ptr(_) | CastTy::FnPtr), Some(CastTy::Int(_))) => (), + _ => { + span_mirbug!(self, rvalue, "Invalid cast {:?} -> {:?}", ty_from, ty) + } + } + } + CastKind::Misc => { let ty_from = op.ty(body, tcx); let cast_ty_from = CastTy::from_ty(ty_from); @@ -2124,7 +2167,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { (None, _) | (_, None | Some(CastTy::FnPtr)) | (Some(CastTy::Float), Some(CastTy::Ptr(_))) - | (Some(CastTy::Ptr(_) | CastTy::FnPtr), Some(CastTy::Float)) => { + | ( + Some(CastTy::Ptr(_) | CastTy::FnPtr), + Some(CastTy::Float | CastTy::Int(_)), + ) => { span_mirbug!(self, rvalue, "Invalid cast {:?} -> {:?}", ty_from, ty,) } ( @@ -2132,8 +2178,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { Some(CastTy::Int(_) | CastTy::Float | CastTy::Ptr(_)), ) | (Some(CastTy::Float), Some(CastTy::Int(_) | CastTy::Float)) - | (Some(CastTy::Ptr(_)), Some(CastTy::Int(_) | CastTy::Ptr(_))) - | (Some(CastTy::FnPtr), Some(CastTy::Int(_) | CastTy::Ptr(_))) => (), + | (Some(CastTy::Ptr(_) | CastTy::FnPtr), Some(CastTy::Ptr(_))) => (), } } } diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs index f98d2c3128c52..c45850c6d840f 100644 --- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs +++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs @@ -28,7 +28,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { v: ty::Variance, b: Ty<'tcx>, locations: Locations, - category: ConstraintCategory, + category: ConstraintCategory<'tcx>, ) -> Fallible<()> { TypeRelating::new( self.infcx, @@ -47,7 +47,7 @@ struct NllTypeRelatingDelegate<'me, 'bccx, 'tcx> { locations: Locations, /// What category do we assign the resulting `'a: 'b` relationships? - category: ConstraintCategory, + category: ConstraintCategory<'tcx>, /// Information so that error reporting knows what types we are relating /// when reporting a bound region error. @@ -58,7 +58,7 @@ impl<'me, 'bccx, 'tcx> NllTypeRelatingDelegate<'me, 'bccx, 'tcx> { fn new( type_checker: &'me mut TypeChecker<'bccx, 'tcx>, locations: Locations, - category: ConstraintCategory, + category: ConstraintCategory<'tcx>, universe_info: UniverseInfo<'tcx>, ) -> Self { Self { type_checker, locations, category, universe_info } diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs index 0fcac9a1c6c7b..7b63ec516b8c4 100644 --- a/compiler/rustc_borrowck/src/universal_regions.rs +++ b/compiler/rustc_borrowck/src/universal_regions.rs @@ -336,7 +336,7 @@ impl<'tcx> UniversalRegions<'tcx> { /// that this region imposes on others. The methods in this file /// handle the part about dumping the inference context internal /// state. - crate fn annotate(&self, tcx: TyCtxt<'tcx>, err: &mut Diagnostic) { + pub(crate) fn annotate(&self, tcx: TyCtxt<'tcx>, err: &mut Diagnostic) { match self.defining_ty { DefiningTy::Closure(def_id, substs) => { err.note(&format!( diff --git a/compiler/rustc_borrowck/src/used_muts.rs b/compiler/rustc_borrowck/src/used_muts.rs index 6022a9809502b..1093167fa8299 100644 --- a/compiler/rustc_borrowck/src/used_muts.rs +++ b/compiler/rustc_borrowck/src/used_muts.rs @@ -22,7 +22,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { /// been assigned to - this set is used as a proxy for locals that were not initialized due to /// unreachable code. These locals are then considered "used" to silence the lint for them. /// See #55344 for context. - crate fn gather_used_muts( + pub(crate) fn gather_used_muts( &mut self, temporary_used_locals: FxHashSet, mut never_initialized_mut_locals: FxHashSet, @@ -66,8 +66,8 @@ impl<'visit, 'cx, 'tcx> Visitor<'tcx> for GatherUsedMutsVisitor<'visit, 'cx, 'tc fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { debug!("visit_terminator: terminator={:?}", terminator); match &terminator.kind { - TerminatorKind::Call { destination: Some((into, _)), .. } => { - self.remove_never_initialized_mut_locals(*into); + TerminatorKind::Call { destination, .. } => { + self.remove_never_initialized_mut_locals(*destination); } TerminatorKind::DropAndReplace { place, .. } => { self.remove_never_initialized_mut_locals(*place); diff --git a/compiler/rustc_builtin_macros/src/cfg_accessible.rs b/compiler/rustc_builtin_macros/src/cfg_accessible.rs index 7b7db3eaea613..cb5359dd1e27e 100644 --- a/compiler/rustc_builtin_macros/src/cfg_accessible.rs +++ b/compiler/rustc_builtin_macros/src/cfg_accessible.rs @@ -7,7 +7,7 @@ use rustc_parse::validate_attr; use rustc_span::symbol::sym; use rustc_span::Span; -crate struct Expander; +pub(crate) struct Expander; fn validate_input<'a>(ecx: &mut ExtCtxt<'_>, mi: &'a ast::MetaItem) -> Option<&'a ast::Path> { match mi.meta_item_list() { diff --git a/compiler/rustc_builtin_macros/src/cfg_eval.rs b/compiler/rustc_builtin_macros/src/cfg_eval.rs index 4278fedfee992..89b2c329236d4 100644 --- a/compiler/rustc_builtin_macros/src/cfg_eval.rs +++ b/compiler/rustc_builtin_macros/src/cfg_eval.rs @@ -3,7 +3,6 @@ use crate::util::{check_builtin_macro_attribute, warn_on_duplicate_attribute}; use rustc_ast as ast; use rustc_ast::mut_visit::MutVisitor; use rustc_ast::ptr::P; -use rustc_ast::tokenstream::CanSynthesizeMissingTokens; use rustc_ast::visit::Visitor; use rustc_ast::NodeId; use rustc_ast::{mut_visit, visit}; @@ -13,13 +12,12 @@ use rustc_expand::config::StripUnconfigured; use rustc_expand::configure; use rustc_feature::Features; use rustc_parse::parser::{ForceCollect, Parser}; -use rustc_session::utils::FlattenNonterminals; use rustc_session::Session; use rustc_span::symbol::sym; use rustc_span::Span; use smallvec::SmallVec; -crate fn expand( +pub(crate) fn expand( ecx: &mut ExtCtxt<'_>, _span: Span, meta_item: &ast::MetaItem, @@ -30,7 +28,7 @@ crate fn expand( vec![cfg_eval(ecx.sess, ecx.ecfg.features, annotatable, ecx.current_expansion.lint_node_id)] } -crate fn cfg_eval( +pub(crate) fn cfg_eval( sess: &Session, features: Option<&Features>, annotatable: Annotatable, @@ -174,8 +172,6 @@ impl CfgEval<'_, '_> { _ => unreachable!(), }; - let mut orig_tokens = annotatable.to_tokens(&self.cfg.sess.parse_sess); - // 'Flatten' all nonterminals (i.e. `TokenKind::Interpolated`) // to `None`-delimited groups containing the corresponding tokens. This // is normally delayed until the proc-macro server actually needs to @@ -189,12 +185,7 @@ impl CfgEval<'_, '_> { // where `$item` is `#[cfg_attr] struct Foo {}`. We want to make // sure to evaluate *all* `#[cfg]` and `#[cfg_attr]` attributes - the simplest // way to do this is to do a single parse of a stream without any nonterminals. - let mut flatten = FlattenNonterminals { - nt_to_tokenstream: rustc_parse::nt_to_tokenstream, - parse_sess: &self.cfg.sess.parse_sess, - synthesize_tokens: CanSynthesizeMissingTokens::No, - }; - orig_tokens = flatten.process_token_stream(orig_tokens); + let orig_tokens = annotatable.to_tokens().flattened(); // Re-parse the tokens, setting the `capture_cfg` flag to save extra information // to the captured `AttrAnnotatedTokenStream` (specifically, we capture diff --git a/compiler/rustc_builtin_macros/src/derive.rs b/compiler/rustc_builtin_macros/src/derive.rs index 391c46d18132f..7f25b23734b3e 100644 --- a/compiler/rustc_builtin_macros/src/derive.rs +++ b/compiler/rustc_builtin_macros/src/derive.rs @@ -10,7 +10,7 @@ use rustc_session::Session; use rustc_span::symbol::{sym, Ident}; use rustc_span::Span; -crate struct Expander; +pub(crate) struct Expander; impl MultiItemModifier for Expander { fn expand( diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index 0fd23fd281e19..53369afae278c 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -257,7 +257,7 @@ pub struct Substructure<'a> { pub type_ident: Ident, /// ident of the method pub method_ident: Ident, - /// dereferenced access to any [`Self_`] or [`Ptr(Self_, _)][ptr]` arguments + /// dereferenced access to any [`Self_`] or [`Ptr(Self_, _)`][ptr] arguments /// /// [`Self_`]: ty::Ty::Self_ /// [ptr]: ty::Ty::Ptr @@ -1039,7 +1039,9 @@ impl<'a> MethodDef<'a> { let span = trait_.span; let mut patterns = Vec::new(); for i in 0..self_args.len() { - let struct_path = cx.path(span, vec![type_ident]); + // We could use `type_ident` instead of `Self`, but in the case of a type parameter + // shadowing the struct name, that causes a second, unnecessary E0578 error. #97343 + let struct_path = cx.path(span, vec![Ident::new(kw::SelfUpper, type_ident.span)]); let (pat, ident_expr) = trait_.create_struct_pattern( cx, struct_path, diff --git a/compiler/rustc_builtin_macros/src/deriving/mod.rs b/compiler/rustc_builtin_macros/src/deriving/mod.rs index 812d86af6e8f2..c678c8cbd159e 100644 --- a/compiler/rustc_builtin_macros/src/deriving/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/mod.rs @@ -38,8 +38,8 @@ pub mod partial_ord; pub mod generic; -crate struct BuiltinDerive( - crate fn(&mut ExtCtxt<'_>, Span, &MetaItem, &Annotatable, &mut dyn FnMut(Annotatable)), +pub(crate) struct BuiltinDerive( + pub(crate) fn(&mut ExtCtxt<'_>, Span, &MetaItem, &Annotatable, &mut dyn FnMut(Annotatable)), ); impl MultiItemModifier for BuiltinDerive { diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index 468ca7d7aa932..0c9e3c22bcf3c 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -4,7 +4,6 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(array_windows)] #![feature(box_patterns)] -#![feature(crate_visibility_modifier)] #![feature(decl_macro)] #![feature(is_sorted)] #![feature(nll)] diff --git a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs index 407ca2301e124..03159d4395066 100644 --- a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs +++ b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs @@ -22,21 +22,16 @@ struct ProcMacroDerive { attrs: Vec, } -enum ProcMacroDefType { - Attr, - Bang, -} - struct ProcMacroDef { id: NodeId, function_name: Ident, span: Span, - def_type: ProcMacroDefType, } enum ProcMacro { Derive(ProcMacroDerive), - Def(ProcMacroDef), + Attr(ProcMacroDef), + Bang(ProcMacroDef), } struct CollectProcMacros<'a> { @@ -128,11 +123,10 @@ impl<'a> CollectProcMacros<'a> { fn collect_attr_proc_macro(&mut self, item: &'a ast::Item) { if self.in_root && item.vis.kind.is_pub() { - self.macros.push(ProcMacro::Def(ProcMacroDef { + self.macros.push(ProcMacro::Attr(ProcMacroDef { id: item.id, span: item.span, function_name: item.ident, - def_type: ProcMacroDefType::Attr, })); } else { let msg = if !self.in_root { @@ -147,11 +141,10 @@ impl<'a> CollectProcMacros<'a> { fn collect_bang_proc_macro(&mut self, item: &'a ast::Item) { if self.in_root && item.vis.kind.is_pub() { - self.macros.push(ProcMacro::Def(ProcMacroDef { + self.macros.push(ProcMacro::Bang(ProcMacroDef { id: item.id, span: item.span, function_name: item.ident, - def_type: ProcMacroDefType::Bang, })); } else { let msg = if !self.in_root { @@ -301,53 +294,57 @@ fn mk_decls(cx: &mut ExtCtxt<'_>, macros: &[ProcMacro]) -> P { // that we generate expressions. The position of each NodeId // in the 'proc_macros' Vec corresponds to its position // in the static array that will be generated - let decls = { - let local_path = |cx: &ExtCtxt<'_>, sp: Span, name| { - cx.expr_path(cx.path(sp.with_ctxt(span.ctxt()), vec![name])) - }; - let proc_macro_ty_method_path = |cx: &ExtCtxt<'_>, method| { - cx.expr_path(cx.path(span, vec![proc_macro, bridge, client, proc_macro_ty, method])) - }; - macros - .iter() - .map(|m| match m { + let decls = macros + .iter() + .map(|m| { + let harness_span = span; + let span = match m { + ProcMacro::Derive(m) => m.span, + ProcMacro::Attr(m) | ProcMacro::Bang(m) => m.span, + }; + let local_path = |cx: &ExtCtxt<'_>, name| cx.expr_path(cx.path(span, vec![name])); + let proc_macro_ty_method_path = |cx: &ExtCtxt<'_>, method| { + cx.expr_path(cx.path( + span.with_ctxt(harness_span.ctxt()), + vec![proc_macro, bridge, client, proc_macro_ty, method], + )) + }; + match m { ProcMacro::Derive(cd) => { cx.resolver.declare_proc_macro(cd.id); cx.expr_call( span, proc_macro_ty_method_path(cx, custom_derive), vec![ - cx.expr_str(cd.span, cd.trait_name), + cx.expr_str(span, cd.trait_name), cx.expr_vec_slice( span, - cd.attrs - .iter() - .map(|&s| cx.expr_str(cd.span, s)) - .collect::>(), + cd.attrs.iter().map(|&s| cx.expr_str(span, s)).collect::>(), ), - local_path(cx, cd.span, cd.function_name), + local_path(cx, cd.function_name), ], ) } - ProcMacro::Def(ca) => { + ProcMacro::Attr(ca) | ProcMacro::Bang(ca) => { cx.resolver.declare_proc_macro(ca.id); - let ident = match ca.def_type { - ProcMacroDefType::Attr => attr, - ProcMacroDefType::Bang => bang, + let ident = match m { + ProcMacro::Attr(_) => attr, + ProcMacro::Bang(_) => bang, + ProcMacro::Derive(_) => unreachable!(), }; cx.expr_call( span, proc_macro_ty_method_path(cx, ident), vec![ - cx.expr_str(ca.span, ca.function_name.name), - local_path(cx, ca.span, ca.function_name), + cx.expr_str(span, ca.function_name.name), + local_path(cx, ca.function_name), ], ) } - }) - .collect() - }; + } + }) + .collect(); let decls_static = cx .item_static( diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs index b163a42619172..decb784199064 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs @@ -312,13 +312,14 @@ pub(crate) fn codegen_terminator_call<'tcx>( source_info: mir::SourceInfo, func: &Operand<'tcx>, args: &[Operand<'tcx>], - mir_dest: Option<(Place<'tcx>, BasicBlock)>, + destination: Place<'tcx>, + target: Option, ) { let fn_ty = fx.monomorphize(func.ty(fx.mir, fx.tcx)); let fn_sig = fx.tcx.normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), fn_ty.fn_sig(fx.tcx)); - let destination = mir_dest.map(|(place, bb)| (codegen_place(fx, place), bb)); + let ret_place = codegen_place(fx, destination); // Handle special calls like instrinsics and empty drop glue. let instance = if let ty::FnDef(def_id, substs) = *fn_ty.kind() { @@ -333,7 +334,8 @@ pub(crate) fn codegen_terminator_call<'tcx>( &fx.tcx.symbol_name(instance).name, substs, args, - destination, + ret_place, + target, ); return; } @@ -344,14 +346,15 @@ pub(crate) fn codegen_terminator_call<'tcx>( fx, instance, args, - destination, + ret_place, + target, source_info, ); return; } InstanceDef::DropGlue(_, None) => { // empty drop glue - a nop. - let (_, dest) = destination.expect("Non terminating drop_in_place_real???"); + let dest = target.expect("Non terminating drop_in_place_real???"); let ret_block = fx.get_block(dest); fx.bcx.ins().jump(ret_block, &[]); return; @@ -377,7 +380,7 @@ pub(crate) fn codegen_terminator_call<'tcx>( .unwrap_or(false); if is_cold { fx.bcx.set_cold_block(fx.bcx.current_block().unwrap()); - if let Some((_place, destination_block)) = destination { + if let Some(destination_block) = target { fx.bcx.set_cold_block(fx.get_block(destination_block)); } } @@ -459,7 +462,6 @@ pub(crate) fn codegen_terminator_call<'tcx>( } }; - let ret_place = destination.map(|(place, _)| place); self::returning::codegen_with_call_return_arg(fx, &fn_abi.ret, ret_place, |fx, return_ptr| { let call_args = return_ptr .into_iter() @@ -511,7 +513,7 @@ pub(crate) fn codegen_terminator_call<'tcx>( call_inst }); - if let Some((_, dest)) = destination { + if let Some(dest) = target { let ret_block = fx.get_block(dest); fx.bcx.ins().jump(ret_block, &[]); } else { diff --git a/compiler/rustc_codegen_cranelift/src/abi/returning.rs b/compiler/rustc_codegen_cranelift/src/abi/returning.rs index c1bdba43e6ccb..ff3bb2dfd000f 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/returning.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/returning.rs @@ -56,23 +56,22 @@ pub(super) fn codegen_return_param<'tcx>( pub(super) fn codegen_with_call_return_arg<'tcx>( fx: &mut FunctionCx<'_, '_, 'tcx>, ret_arg_abi: &ArgAbi<'tcx, Ty<'tcx>>, - ret_place: Option>, + ret_place: CPlace<'tcx>, f: impl FnOnce(&mut FunctionCx<'_, '_, 'tcx>, Option) -> Inst, ) { let (ret_temp_place, return_ptr) = match ret_arg_abi.mode { PassMode::Ignore => (None, None), - PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } => match ret_place { - Some(ret_place) if matches!(ret_place.inner(), CPlaceInner::Addr(_, None)) => { + PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } => { + if matches!(ret_place.inner(), CPlaceInner::Addr(_, None)) { // This is an optimization to prevent unnecessary copies of the return value when // the return place is already a memory place as opposed to a register. // This match arm can be safely removed. (None, Some(ret_place.to_ptr().get_addr(fx))) - } - _ => { + } else { let place = CPlace::new_stack_slot(fx, ret_arg_abi.layout); (Some(place), Some(place.to_ptr().get_addr(fx))) } - }, + } PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => { unreachable!("unsized return value") } @@ -84,39 +83,25 @@ pub(super) fn codegen_with_call_return_arg<'tcx>( match ret_arg_abi.mode { PassMode::Ignore => {} PassMode::Direct(_) => { - if let Some(ret_place) = ret_place { - let ret_val = fx.bcx.inst_results(call_inst)[0]; - ret_place.write_cvalue(fx, CValue::by_val(ret_val, ret_arg_abi.layout)); - } + let ret_val = fx.bcx.inst_results(call_inst)[0]; + ret_place.write_cvalue(fx, CValue::by_val(ret_val, ret_arg_abi.layout)); } PassMode::Pair(_, _) => { - if let Some(ret_place) = ret_place { - let ret_val_a = fx.bcx.inst_results(call_inst)[0]; - let ret_val_b = fx.bcx.inst_results(call_inst)[1]; - ret_place.write_cvalue( - fx, - CValue::by_val_pair(ret_val_a, ret_val_b, ret_arg_abi.layout), - ); - } + let ret_val_a = fx.bcx.inst_results(call_inst)[0]; + let ret_val_b = fx.bcx.inst_results(call_inst)[1]; + ret_place + .write_cvalue(fx, CValue::by_val_pair(ret_val_a, ret_val_b, ret_arg_abi.layout)); } PassMode::Cast(cast) => { - if let Some(ret_place) = ret_place { - let results = fx - .bcx - .inst_results(call_inst) - .iter() - .copied() - .collect::>(); - let result = - super::pass_mode::from_casted_value(fx, &results, ret_place.layout(), cast); - ret_place.write_cvalue(fx, result); - } + let results = + fx.bcx.inst_results(call_inst).iter().copied().collect::>(); + let result = + super::pass_mode::from_casted_value(fx, &results, ret_place.layout(), cast); + ret_place.write_cvalue(fx, result); } PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } => { - if let (Some(ret_place), Some(ret_temp_place)) = (ret_place, ret_temp_place) { - // Both ret_place and ret_temp_place must be Some. If ret_place is None, this is - // a non-returning call. If ret_temp_place is None, it is not necessary to copy the - // return value. + if let Some(ret_temp_place) = ret_temp_place { + // If ret_temp_place is None, it is not necessary to copy the return value. let ret_temp_value = ret_temp_place.to_cvalue(fx); ret_place.write_cvalue(fx, ret_temp_value); } diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index 65e5812a8a5b0..58bec183c94aa 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -393,6 +393,7 @@ fn codegen_fn_content(fx: &mut FunctionCx<'_, '_, '_>) { func, args, destination, + target, fn_span, cleanup: _, from_hir_call: _, @@ -404,6 +405,7 @@ fn codegen_fn_content(fx: &mut FunctionCx<'_, '_, '_>) { func, args, *destination, + *target, ) }); } @@ -605,7 +607,11 @@ fn codegen_stmt<'tcx>( let operand = codegen_operand(fx, operand); lval.write_cvalue(fx, operand.cast_pointer_to(to_layout)); } - Rvalue::Cast(CastKind::Misc, ref operand, to_ty) => { + Rvalue::Cast( + CastKind::Misc | CastKind::PointerExposeAddress, + ref operand, + to_ty, + ) => { let operand = codegen_operand(fx, operand); let from_ty = operand.layout().ty; let to_ty = fx.monomorphize(to_ty); diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs index 57074f00210fe..7d2e3e52f3443 100644 --- a/compiler/rustc_codegen_cranelift/src/constant.rs +++ b/compiler/rustc_codegen_cranelift/src/constant.rs @@ -542,8 +542,8 @@ pub(crate) fn mir_operand_get_const_val<'tcx>( | TerminatorKind::FalseEdge { .. } | TerminatorKind::FalseUnwind { .. } => unreachable!(), TerminatorKind::InlineAsm { .. } => return None, - TerminatorKind::Call { destination: Some((call_place, _)), .. } - if call_place == place => + TerminatorKind::Call { destination, target: Some(_), .. } + if destination == place => { return None; } diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs index 0e4f7ee907a51..77ac46540a9ba 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs @@ -10,10 +10,9 @@ pub(crate) fn codegen_llvm_intrinsic_call<'tcx>( intrinsic: &str, _substs: SubstsRef<'tcx>, args: &[mir::Operand<'tcx>], - destination: Option<(CPlace<'tcx>, BasicBlock)>, + ret: CPlace<'tcx>, + target: Option, ) { - let ret = destination.unwrap().0; - intrinsic_match! { fx, intrinsic, args, _ => { @@ -126,7 +125,7 @@ pub(crate) fn codegen_llvm_intrinsic_call<'tcx>( }; } - let dest = destination.expect("all llvm intrinsics used by stdlib should return").1; + let dest = target.expect("all llvm intrinsics used by stdlib should return"); let ret_block = fx.get_block(dest); fx.bcx.ins().jump(ret_block, &[]); } diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs index 29b3f36b2bef2..6937e658ed5ee 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs @@ -58,6 +58,7 @@ pub(crate) use llvm::codegen_llvm_intrinsic_call; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::subst::SubstsRef; use rustc_span::symbol::{kw, sym, Symbol}; +use rustc_target::abi::InitKind; use crate::prelude::*; use cranelift_codegen::ir::AtomicRmwOp; @@ -217,35 +218,42 @@ pub(crate) fn codegen_intrinsic_call<'tcx>( fx: &mut FunctionCx<'_, '_, 'tcx>, instance: Instance<'tcx>, args: &[mir::Operand<'tcx>], - destination: Option<(CPlace<'tcx>, BasicBlock)>, + destination: CPlace<'tcx>, + target: Option, source_info: mir::SourceInfo, ) { let intrinsic = fx.tcx.item_name(instance.def_id()); let substs = instance.substs; - let ret = match destination { - Some((place, _)) => place, - None => { - // Insert non returning intrinsics here - match intrinsic { - sym::abort => { - fx.bcx.ins().trap(TrapCode::User(0)); - } - sym::transmute => { - crate::base::codegen_panic(fx, "Transmuting to uninhabited type.", source_info); - } - _ => unimplemented!("unsupported instrinsic {}", intrinsic), + let target = if let Some(target) = target { + target + } else { + // Insert non returning intrinsics here + match intrinsic { + sym::abort => { + fx.bcx.ins().trap(TrapCode::User(0)); + } + sym::transmute => { + crate::base::codegen_panic(fx, "Transmuting to uninhabited type.", source_info); } - return; + _ => unimplemented!("unsupported instrinsic {}", intrinsic), } + return; }; if intrinsic.as_str().starts_with("simd_") { - self::simd::codegen_simd_intrinsic_call(fx, intrinsic, substs, args, ret, source_info.span); - let ret_block = fx.get_block(destination.expect("SIMD intrinsics don't diverge").1); + self::simd::codegen_simd_intrinsic_call( + fx, + intrinsic, + substs, + args, + destination, + source_info.span, + ); + let ret_block = fx.get_block(target); fx.bcx.ins().jump(ret_block, &[]); - } else if codegen_float_intrinsic_call(fx, intrinsic, args, ret) { - let ret_block = fx.get_block(destination.expect("Float intrinsics don't diverge").1); + } else if codegen_float_intrinsic_call(fx, intrinsic, args, destination) { + let ret_block = fx.get_block(target); fx.bcx.ins().jump(ret_block, &[]); } else { codegen_regular_intrinsic_call( @@ -254,9 +262,9 @@ pub(crate) fn codegen_intrinsic_call<'tcx>( intrinsic, substs, args, - ret, - source_info, destination, + Some(target), + source_info, ); } } @@ -339,8 +347,8 @@ fn codegen_regular_intrinsic_call<'tcx>( substs: SubstsRef<'tcx>, args: &[mir::Operand<'tcx>], ret: CPlace<'tcx>, + destination: Option, source_info: mir::SourceInfo, - destination: Option<(CPlace<'tcx>, BasicBlock)>, ) { let usize_layout = fx.layout_of(fx.tcx.types.usize); @@ -664,7 +672,12 @@ fn codegen_regular_intrinsic_call<'tcx>( return; } - if intrinsic == sym::assert_zero_valid && !layout.might_permit_raw_init(fx, /*zero:*/ true) { + if intrinsic == sym::assert_zero_valid + && !layout.might_permit_raw_init( + fx, + InitKind::Zero, + fx.tcx.sess.opts.debugging_opts.strict_init_checks) { + with_no_trimmed_paths!({ crate::base::codegen_panic( fx, @@ -675,7 +688,12 @@ fn codegen_regular_intrinsic_call<'tcx>( return; } - if intrinsic == sym::assert_uninit_valid && !layout.might_permit_raw_init(fx, /*zero:*/ false) { + if intrinsic == sym::assert_uninit_valid + && !layout.might_permit_raw_init( + fx, + InitKind::Uninit, + fx.tcx.sess.opts.debugging_opts.strict_init_checks) { + with_no_trimmed_paths!({ crate::base::codegen_panic( fx, @@ -761,7 +779,7 @@ fn codegen_regular_intrinsic_call<'tcx>( if fx.tcx.is_compiler_builtins(LOCAL_CRATE) { // special case for compiler-builtins to avoid having to patch it crate::trap::trap_unimplemented(fx, "128bit atomics not yet supported"); - let ret_block = fx.get_block(destination.unwrap().1); + let ret_block = fx.get_block(destination.unwrap()); fx.bcx.ins().jump(ret_block, &[]); return; } else { @@ -789,7 +807,7 @@ fn codegen_regular_intrinsic_call<'tcx>( if fx.tcx.is_compiler_builtins(LOCAL_CRATE) { // special case for compiler-builtins to avoid having to patch it crate::trap::trap_unimplemented(fx, "128bit atomics not yet supported"); - let ret_block = fx.get_block(destination.unwrap().1); + let ret_block = fx.get_block(destination.unwrap()); fx.bcx.ins().jump(ret_block, &[]); return; } else { @@ -1130,6 +1148,6 @@ fn codegen_regular_intrinsic_call<'tcx>( }; } - let ret_block = fx.get_block(destination.unwrap().1); + let ret_block = fx.get_block(destination.unwrap()); fx.bcx.ins().jump(ret_block, &[]); } diff --git a/compiler/rustc_codegen_gcc/src/asm.rs b/compiler/rustc_codegen_gcc/src/asm.rs index 2e8cd934eb298..20d91b80e8c52 100644 --- a/compiler/rustc_codegen_gcc/src/asm.rs +++ b/compiler/rustc_codegen_gcc/src/asm.rs @@ -592,7 +592,7 @@ fn reg_to_gcc(reg: InlineAsmRegOrRegClass) -> ConstraintOrRegister { InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg0) => unimplemented!(), InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => unimplemented!(), InlineAsmRegClass::X86( - X86InlineAsmRegClass::x87_reg | X86InlineAsmRegClass::mmx_reg, + X86InlineAsmRegClass::x87_reg | X86InlineAsmRegClass::mmx_reg | X86InlineAsmRegClass::tmm_reg, ) => unreachable!("clobber-only"), InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => { bug!("GCC backend does not support SPIR-V") @@ -656,6 +656,7 @@ fn dummy_output_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, reg: InlineAsmRegCl InlineAsmRegClass::X86(X86InlineAsmRegClass::x87_reg) => unimplemented!(), InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => cx.type_i16(), InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg0) => cx.type_i16(), + InlineAsmRegClass::X86(X86InlineAsmRegClass::tmm_reg) => unimplemented!(), InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => cx.type_i32(), InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => { bug!("LLVM backend does not support SPIR-V") @@ -787,7 +788,7 @@ fn modifier_to_gcc(arch: InlineAsmArch, reg: InlineAsmRegClass, modifier: Option }, InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => None, InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg0) => None, - InlineAsmRegClass::X86(X86InlineAsmRegClass::x87_reg | X86InlineAsmRegClass::mmx_reg) => { + InlineAsmRegClass::X86(X86InlineAsmRegClass::x87_reg | X86InlineAsmRegClass::mmx_reg | X86InlineAsmRegClass::tmm_reg) => { unreachable!("clobber-only") } InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => unimplemented!(), diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs index 41f88f119e2a2..479328a557cfa 100644 --- a/compiler/rustc_codegen_gcc/src/builder.rs +++ b/compiler/rustc_codegen_gcc/src/builder.rs @@ -61,24 +61,6 @@ enum ExtremumOperation { Min, } -trait EnumClone { - fn clone(&self) -> Self; -} - -impl EnumClone for AtomicOrdering { - fn clone(&self) -> Self { - match *self { - AtomicOrdering::NotAtomic => AtomicOrdering::NotAtomic, - AtomicOrdering::Unordered => AtomicOrdering::Unordered, - AtomicOrdering::Monotonic => AtomicOrdering::Monotonic, - AtomicOrdering::Acquire => AtomicOrdering::Acquire, - AtomicOrdering::Release => AtomicOrdering::Release, - AtomicOrdering::AcquireRelease => AtomicOrdering::AcquireRelease, - AtomicOrdering::SequentiallyConsistent => AtomicOrdering::SequentiallyConsistent, - } - } -} - pub struct Builder<'a: 'gcc, 'gcc, 'tcx> { pub cx: &'a CodegenCx<'gcc, 'tcx>, pub block: Block<'gcc>, @@ -103,9 +85,9 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { match order { // TODO(antoyo): does this make sense? AtomicOrdering::AcquireRelease | AtomicOrdering::Release => AtomicOrdering::Acquire, - _ => order.clone(), + _ => order, }; - let previous_value = self.atomic_load(dst.get_type(), dst, load_ordering.clone(), Size::from_bytes(size)); + let previous_value = self.atomic_load(dst.get_type(), dst, load_ordering, Size::from_bytes(size)); let previous_var = func.new_local(None, previous_value.get_type(), "previous_value"); let return_value = func.new_local(None, previous_value.get_type(), "return_value"); self.llbb().add_assignment(None, previous_var, previous_value); @@ -1384,9 +1366,8 @@ impl ToGccOrdering for AtomicOrdering { let ordering = match self { - AtomicOrdering::NotAtomic => __ATOMIC_RELAXED, // TODO(antoyo): check if that's the same. AtomicOrdering::Unordered => __ATOMIC_RELAXED, - AtomicOrdering::Monotonic => __ATOMIC_RELAXED, // TODO(antoyo): check if that's the same. + AtomicOrdering::Relaxed => __ATOMIC_RELAXED, // TODO(antoyo): check if that's the same. AtomicOrdering::Acquire => __ATOMIC_ACQUIRE, AtomicOrdering::Release => __ATOMIC_RELEASE, AtomicOrdering::AcquireRelease => __ATOMIC_ACQ_REL, diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs index 7d7811c878219..a613e117904eb 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs @@ -13,6 +13,7 @@ use crate::builder::Builder; pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>, name: Symbol, callee_ty: Ty<'tcx>, args: &[OperandRef<'tcx, RValue<'gcc>>], ret_ty: Ty<'tcx>, llret_ty: Type<'gcc>, span: Span) -> Result, ()> { // macros for error handling: + #[allow(unused_macro_rules)] macro_rules! emit_error { ($msg: tt) => { emit_error!($msg, ) diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index e994001f96fd9..a53946995ee1c 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -604,7 +604,8 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'_>>) -> InlineAsmRegClass::X86( X86InlineAsmRegClass::x87_reg | X86InlineAsmRegClass::mmx_reg - | X86InlineAsmRegClass::kreg0, + | X86InlineAsmRegClass::kreg0 + | X86InlineAsmRegClass::tmm_reg, ) => unreachable!("clobber-only"), InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => "r", InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::reg) => "r", @@ -692,7 +693,8 @@ fn modifier_to_llvm( InlineAsmRegClass::X86( X86InlineAsmRegClass::x87_reg | X86InlineAsmRegClass::mmx_reg - | X86InlineAsmRegClass::kreg0, + | X86InlineAsmRegClass::kreg0 + | X86InlineAsmRegClass::tmm_reg, ) => { unreachable!("clobber-only") } @@ -766,7 +768,8 @@ fn dummy_output_type<'ll>(cx: &CodegenCx<'ll, '_>, reg: InlineAsmRegClass) -> &' InlineAsmRegClass::X86( X86InlineAsmRegClass::x87_reg | X86InlineAsmRegClass::mmx_reg - | X86InlineAsmRegClass::kreg0, + | X86InlineAsmRegClass::kreg0 + | X86InlineAsmRegClass::tmm_reg, ) => { unreachable!("clobber-only") } diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index d0724baf9e0ac..c7497bfd355e5 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -354,14 +354,14 @@ fn fat_lto( Ok(LtoModuleCodegen::Fat { module, _serialized_bitcode: serialized_bitcode }) } -crate struct Linker<'a>(&'a mut llvm::Linker<'a>); +pub(crate) struct Linker<'a>(&'a mut llvm::Linker<'a>); impl<'a> Linker<'a> { - crate fn new(llmod: &'a llvm::Module) -> Self { + pub(crate) fn new(llmod: &'a llvm::Module) -> Self { unsafe { Linker(llvm::LLVMRustLinkerNew(llmod)) } } - crate fn add(&mut self, bytecode: &[u8]) -> Result<(), ()> { + pub(crate) fn add(&mut self, bytecode: &[u8]) -> Result<(), ()> { unsafe { if llvm::LLVMRustLinkerAdd( self.0, diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 88b87951ecd35..c41a41980eb0b 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -509,15 +509,20 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { OperandValue::Ref(place.llval, Some(llextra), place.align) } else if place.layout.is_llvm_immediate() { let mut const_llval = None; + let llty = place.layout.llvm_type(self); unsafe { if let Some(global) = llvm::LLVMIsAGlobalVariable(place.llval) { if llvm::LLVMIsGlobalConstant(global) == llvm::True { - const_llval = llvm::LLVMGetInitializer(global); + if let Some(init) = llvm::LLVMGetInitializer(global) { + if self.val_ty(init) == llty { + const_llval = Some(init); + } + } } } } let llval = const_llval.unwrap_or_else(|| { - let load = self.load(place.layout.llvm_type(self), place.llval, place.align); + let load = self.load(llty, place.llval, place.align); if let abi::Abi::Scalar(scalar) = place.layout.abi { scalar_load_metadata(self, load, scalar, place.layout, Size::ZERO); } @@ -1412,7 +1417,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { unsafe { llvm::LLVMBuildVAArg(self.llbuilder, list, ty, UNNAMED) } } - crate fn call_intrinsic(&mut self, intrinsic: &str, args: &[&'ll Value]) -> &'ll Value { + pub(crate) fn call_intrinsic(&mut self, intrinsic: &str, args: &[&'ll Value]) -> &'ll Value { let (ty, f) = self.cx.get_intrinsic(intrinsic); self.call(ty, f, args, None) } diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index 4d3f3f318b80c..5bbbfe9a4ab78 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -212,11 +212,11 @@ pub fn ptrcast<'ll>(val: &'ll Value, ty: &'ll Type) -> &'ll Value { } impl<'ll> CodegenCx<'ll, '_> { - crate fn const_bitcast(&self, val: &'ll Value, ty: &'ll Type) -> &'ll Value { + pub(crate) fn const_bitcast(&self, val: &'ll Value, ty: &'ll Type) -> &'ll Value { unsafe { llvm::LLVMConstBitCast(val, ty) } } - crate fn static_addr_of_mut( + pub(crate) fn static_addr_of_mut( &self, cv: &'ll Value, align: Align, @@ -241,7 +241,7 @@ impl<'ll> CodegenCx<'ll, '_> { } } - crate fn get_static(&self, def_id: DefId) -> &'ll Value { + pub(crate) fn get_static(&self, def_id: DefId) -> &'ll Value { let instance = Instance::mono(self.tcx, def_id); if let Some(&g) = self.instances.borrow().get(&instance) { return g; diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index d296ee3b42ce1..5544f0d3f6058 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -330,7 +330,7 @@ pub unsafe fn create_module<'ll>( } impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { - crate fn new( + pub(crate) fn new( tcx: TyCtxt<'tcx>, codegen_unit: &'tcx CodegenUnit<'tcx>, llvm_module: &'ll crate::ModuleLlvm, @@ -447,7 +447,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { } } - crate fn statics_to_rauw(&self) -> &RefCell> { + pub(crate) fn statics_to_rauw(&self) -> &RefCell> { &self.statics_to_rauw } @@ -599,7 +599,7 @@ impl<'ll, 'tcx> MiscMethods<'tcx> for CodegenCx<'ll, 'tcx> { } impl<'ll> CodegenCx<'ll, '_> { - crate fn get_intrinsic(&self, key: &str) -> (&'ll Type, &'ll Value) { + pub(crate) fn get_intrinsic(&self, key: &str) -> (&'ll Type, &'ll Value) { if let Some(v) = self.intrinsics.borrow().get(key).cloned() { return v; } @@ -890,7 +890,7 @@ impl<'ll> CodegenCx<'ll, '_> { None } - crate fn eh_catch_typeinfo(&self) -> &'ll Value { + pub(crate) fn eh_catch_typeinfo(&self) -> &'ll Value { if let Some(eh_catch_typeinfo) = self.eh_catch_typeinfo.get() { return eh_catch_typeinfo; } diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs index 31a09242c5ada..5186aee57fb12 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs @@ -5,11 +5,14 @@ use crate::llvm; use crate::builder::Builder; use crate::common::CodegenCx; use crate::value::Value; +use rustc_codegen_ssa::base::collect_debugger_visualizers_transitive; use rustc_codegen_ssa::traits::*; +use rustc_hir::def_id::LOCAL_CRATE; use rustc_middle::bug; -use rustc_session::config::DebugInfo; +use rustc_session::config::{CrateType, DebugInfo}; use rustc_span::symbol::sym; +use rustc_span::DebuggerVisualizerType; /// Inserts a side-effect free instruction sequence that makes sure that the /// .debug_gdb_scripts global is referenced, so it isn't removed by the linker. @@ -37,9 +40,33 @@ pub fn get_or_insert_gdb_debug_scripts_section_global<'ll>(cx: &CodegenCx<'ll, ' section_var.unwrap_or_else(|| { let section_name = b".debug_gdb_scripts\0"; - let section_contents = b"\x01gdb_load_rust_pretty_printers.py\0"; + let mut section_contents = Vec::new(); + + // Add the pretty printers for the standard library first. + section_contents.extend_from_slice(b"\x01gdb_load_rust_pretty_printers.py\0"); + + // Next, add the pretty printers that were specified via the `#[debugger_visualizer]` attribute. + let visualizers = collect_debugger_visualizers_transitive( + cx.tcx, + DebuggerVisualizerType::GdbPrettyPrinter, + ); + let crate_name = cx.tcx.crate_name(LOCAL_CRATE); + for (index, visualizer) in visualizers.iter().enumerate() { + // The initial byte `4` instructs GDB that the following pretty printer + // is defined inline as opposed to in a standalone file. + section_contents.extend_from_slice(b"\x04"); + let vis_name = format!("pretty-printer-{}-{}\n", crate_name.as_str(), index); + section_contents.extend_from_slice(vis_name.as_bytes()); + section_contents.extend_from_slice(&visualizer.src); + + // The final byte `0` tells GDB that the pretty printer has been + // fully defined and can continue searching for additional + // pretty printers. + section_contents.extend_from_slice(b"\0"); + } unsafe { + let section_contents = section_contents.as_slice(); let llvm_type = cx.type_array(cx.type_i8(), section_contents.len() as u64); let section_var = cx @@ -62,7 +89,32 @@ pub fn needs_gdb_debug_scripts_section(cx: &CodegenCx<'_, '_>) -> bool { let omit_gdb_pretty_printer_section = cx.tcx.sess.contains_name(cx.tcx.hir().krate_attrs(), sym::omit_gdb_pretty_printer_section); + // To ensure the section `__rustc_debug_gdb_scripts_section__` will not create + // ODR violations at link time, this section will not be emitted for rlibs since + // each rlib could produce a different set of visualizers that would be embedded + // in the `.debug_gdb_scripts` section. For that reason, we make sure that the + // section is only emitted for leaf crates. + let embed_visualizers = cx.sess().crate_types().iter().any(|&crate_type| match crate_type { + CrateType::Executable | CrateType::Dylib | CrateType::Cdylib | CrateType::Staticlib => { + // These are crate types for which we will embed pretty printers since they + // are treated as leaf crates. + true + } + CrateType::ProcMacro => { + // We could embed pretty printers for proc macro crates too but it does not + // seem like a good default, since this is a rare use case and we don't + // want to slow down the common case. + false + } + CrateType::Rlib => { + // As per the above description, embedding pretty printers for rlibs could + // lead to ODR violations so we skip this crate type as well. + false + } + }); + !omit_gdb_pretty_printer_section && cx.sess().opts.debuginfo != DebugInfo::None && cx.sess().target.emit_debug_gdb_scripts + && embed_visualizers } diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index f2cf3b1ef5c1e..dd3adbf70a62f 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -33,23 +33,24 @@ use rustc_middle::mir::{self, GeneratorLayout}; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::layout::TyAndLayout; use rustc_middle::ty::subst::GenericArgKind; -use rustc_middle::ty::{self, AdtKind, Instance, ParamEnv, Ty, TyCtxt, COMMON_VTABLE_ENTRIES}; +use rustc_middle::ty::{self, AdtKind, Instance, ParamEnv, Ty, TyCtxt}; use rustc_session::config::{self, DebugInfo}; use rustc_span::symbol::Symbol; +use rustc_span::FileName; use rustc_span::FileNameDisplayPreference; -use rustc_span::{self, SourceFile, SourceFileHash}; +use rustc_span::{self, SourceFile}; use rustc_target::abi::{Align, Size}; use smallvec::smallvec; use tracing::debug; use libc::{c_longlong, c_uint}; use std::borrow::Cow; -use std::collections::hash_map::Entry; use std::fmt::{self, Write}; use std::hash::{Hash, Hasher}; use std::iter; use std::path::{Path, PathBuf}; use std::ptr; +use tracing::instrument; impl PartialEq for llvm::Metadata { fn eq(&self, other: &Self) -> bool { @@ -527,78 +528,105 @@ fn hex_encode(data: &[u8]) -> String { } pub fn file_metadata<'ll>(cx: &CodegenCx<'ll, '_>, source_file: &SourceFile) -> &'ll DIFile { - debug!("file_metadata: file_name: {:?}", source_file.name); - - let hash = Some(&source_file.src_hash); - let file_name = Some(source_file.name.prefer_remapped().to_string()); - let directory = if source_file.is_real_file() && !source_file.is_imported() { - Some( - cx.sess() - .opts - .working_dir - .to_string_lossy(FileNameDisplayPreference::Remapped) - .to_string(), - ) - } else { - // If the path comes from an upstream crate we assume it has been made - // independent of the compiler's working directory one way or another. - None - }; - file_metadata_raw(cx, file_name, directory, hash) -} - -pub fn unknown_file_metadata<'ll>(cx: &CodegenCx<'ll, '_>) -> &'ll DIFile { - file_metadata_raw(cx, None, None, None) -} - -fn file_metadata_raw<'ll>( - cx: &CodegenCx<'ll, '_>, - file_name: Option, - directory: Option, - hash: Option<&SourceFileHash>, -) -> &'ll DIFile { - let key = (file_name, directory); - - match debug_context(cx).created_files.borrow_mut().entry(key) { - Entry::Occupied(o) => o.get(), - Entry::Vacant(v) => { - let (file_name, directory) = v.key(); - debug!("file_metadata: file_name: {:?}, directory: {:?}", file_name, directory); - - let file_name = file_name.as_deref().unwrap_or(""); - let directory = directory.as_deref().unwrap_or(""); - - let (hash_kind, hash_value) = match hash { - Some(hash) => { - let kind = match hash.kind { - rustc_span::SourceFileHashAlgorithm::Md5 => llvm::ChecksumKind::MD5, - rustc_span::SourceFileHashAlgorithm::Sha1 => llvm::ChecksumKind::SHA1, - rustc_span::SourceFileHashAlgorithm::Sha256 => llvm::ChecksumKind::SHA256, - }; - (kind, hex_encode(hash.hash_bytes())) + let cache_key = Some((source_file.name_hash, source_file.src_hash)); + return debug_context(cx) + .created_files + .borrow_mut() + .entry(cache_key) + .or_insert_with(|| alloc_new_file_metadata(cx, source_file)); + + #[instrument(skip(cx, source_file), level = "debug")] + fn alloc_new_file_metadata<'ll>( + cx: &CodegenCx<'ll, '_>, + source_file: &SourceFile, + ) -> &'ll DIFile { + debug!(?source_file.name); + + let (directory, file_name) = match &source_file.name { + FileName::Real(filename) => { + let working_directory = &cx.sess().opts.working_dir; + debug!(?working_directory); + + let filename = cx + .sess() + .source_map() + .path_mapping() + .to_embeddable_absolute_path(filename.clone(), working_directory); + + // Construct the absolute path of the file + let abs_path = filename.remapped_path_if_available(); + debug!(?abs_path); + + if let Ok(rel_path) = + abs_path.strip_prefix(working_directory.remapped_path_if_available()) + { + // If the compiler's working directory (which also is the DW_AT_comp_dir of + // the compilation unit) is a prefix of the path we are about to emit, then + // only emit the part relative to the working directory. + // Because of path remapping we sometimes see strange things here: `abs_path` + // might actually look like a relative path + // (e.g. `/src/lib.rs`), so if we emit it without + // taking the working directory into account, downstream tooling will + // interpret it as `//src/lib.rs`, + // which makes no sense. Usually in such cases the working directory will also + // be remapped to `` or some other prefix of the path + // we are remapping, so we end up with + // `//src/lib.rs`. + // By moving the working directory portion into the `directory` part of the + // DIFile, we allow LLVM to emit just the relative path for DWARF, while + // still emitting the correct absolute path for CodeView. + ( + working_directory.to_string_lossy(FileNameDisplayPreference::Remapped), + rel_path.to_string_lossy().into_owned(), + ) + } else { + ("".into(), abs_path.to_string_lossy().into_owned()) } - None => (llvm::ChecksumKind::None, String::new()), - }; + } + other => ("".into(), other.prefer_remapped().to_string_lossy().into_owned()), + }; - let file_metadata = unsafe { - llvm::LLVMRustDIBuilderCreateFile( - DIB(cx), - file_name.as_ptr().cast(), - file_name.len(), - directory.as_ptr().cast(), - directory.len(), - hash_kind, - hash_value.as_ptr().cast(), - hash_value.len(), - ) - }; + let hash_kind = match source_file.src_hash.kind { + rustc_span::SourceFileHashAlgorithm::Md5 => llvm::ChecksumKind::MD5, + rustc_span::SourceFileHashAlgorithm::Sha1 => llvm::ChecksumKind::SHA1, + rustc_span::SourceFileHashAlgorithm::Sha256 => llvm::ChecksumKind::SHA256, + }; + let hash_value = hex_encode(source_file.src_hash.hash_bytes()); - v.insert(file_metadata); - file_metadata + unsafe { + llvm::LLVMRustDIBuilderCreateFile( + DIB(cx), + file_name.as_ptr().cast(), + file_name.len(), + directory.as_ptr().cast(), + directory.len(), + hash_kind, + hash_value.as_ptr().cast(), + hash_value.len(), + ) } } } +pub fn unknown_file_metadata<'ll>(cx: &CodegenCx<'ll, '_>) -> &'ll DIFile { + debug_context(cx).created_files.borrow_mut().entry(None).or_insert_with(|| unsafe { + let file_name = ""; + let directory = ""; + let hash_value = ""; + + llvm::LLVMRustDIBuilderCreateFile( + DIB(cx), + file_name.as_ptr().cast(), + file_name.len(), + directory.as_ptr().cast(), + directory.len(), + llvm::ChecksumKind::None, + hash_value.as_ptr().cast(), + hash_value.len(), + ) + }) +} + trait MsvcBasicName { fn msvc_basic_name(self) -> &'static str; } @@ -1364,7 +1392,7 @@ fn build_vtable_type_di_node<'ll, 'tcx>( tcx.vtable_entries(trait_ref) } else { - COMMON_VTABLE_ENTRIES + TyCtxt::COMMON_VTABLE_ENTRIES }; // All function pointers are described as opaque pointers. This could be improved in the future diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs index 6a164557a4719..0910e7c94ea12 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -31,7 +31,7 @@ use rustc_middle::ty::{self, Instance, ParamEnv, Ty, TypeFoldable}; use rustc_session::config::{self, DebugInfo}; use rustc_session::Session; use rustc_span::symbol::Symbol; -use rustc_span::{self, BytePos, Pos, SourceFile, SourceFileAndLine, Span}; +use rustc_span::{self, BytePos, Pos, SourceFile, SourceFileAndLine, SourceFileHash, Span}; use rustc_target::abi::Size; use libc::c_uint; @@ -61,7 +61,7 @@ pub struct CodegenUnitDebugContext<'ll, 'tcx> { llcontext: &'ll llvm::Context, llmod: &'ll llvm::Module, builder: &'ll mut DIBuilder<'ll>, - created_files: RefCell, Option), &'ll DIFile>>, + created_files: RefCell, &'ll DIFile>>, type_map: metadata::TypeMap<'ll, 'tcx>, namespace_map: RefCell>, diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 4407297c943a8..9927f5f399bcd 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -816,7 +816,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>( span: Span, ) -> Result<&'ll Value, ()> { // macros for error handling: - #[cfg_attr(not(bootstrap), allow(unused_macro_rules))] + #[allow(unused_macro_rules)] macro_rules! emit_error { ($msg: tt) => { emit_error!($msg, ) @@ -1145,7 +1145,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>( span: Span, args: &[OperandRef<'tcx, &'ll Value>], ) -> Result<&'ll Value, ()> { - #[cfg_attr(not(bootstrap), allow(unused_macro_rules))] + #[allow(unused_macro_rules)] macro_rules! emit_error { ($msg: tt) => { emit_error!($msg, ) diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 0bead4629a670..913cf4eea13a3 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -5,7 +5,6 @@ //! This API is completely unstable and subject to change. #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] -#![feature(crate_visibility_modifier)] #![feature(let_chains)] #![feature(let_else)] #![feature(extern_types)] @@ -305,8 +304,8 @@ impl CodegenBackend for LlvmCodegenBackend { local stack variable in the ABI.) basic - Generate stack canaries in functions with: - - local variables of `[T; N]` type, where `T` is byte-sized and `N` > 8. + Generate stack canaries in functions with local variables of `[T; N]` + type, where `T` is byte-sized and `N` >= 8. none Do not generate stack canaries. diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 13baaddccd4df..1d9a4655db637 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -381,9 +381,8 @@ pub enum AtomicOrdering { impl AtomicOrdering { pub fn from_generic(ao: rustc_codegen_ssa::common::AtomicOrdering) -> Self { match ao { - rustc_codegen_ssa::common::AtomicOrdering::NotAtomic => AtomicOrdering::NotAtomic, rustc_codegen_ssa::common::AtomicOrdering::Unordered => AtomicOrdering::Unordered, - rustc_codegen_ssa::common::AtomicOrdering::Monotonic => AtomicOrdering::Monotonic, + rustc_codegen_ssa::common::AtomicOrdering::Relaxed => AtomicOrdering::Monotonic, rustc_codegen_ssa::common::AtomicOrdering::Acquire => AtomicOrdering::Acquire, rustc_codegen_ssa::common::AtomicOrdering::Release => AtomicOrdering::Release, rustc_codegen_ssa::common::AtomicOrdering::AcquireRelease => { @@ -775,7 +774,7 @@ pub mod coverageinfo { } impl CounterMappingRegion { - crate fn code_region( + pub(crate) fn code_region( counter: coverage_map::Counter, file_id: u32, start_line: u32, @@ -799,7 +798,7 @@ pub mod coverageinfo { // This function might be used in the future; the LLVM API is still evolving, as is coverage // support. #[allow(dead_code)] - crate fn branch_region( + pub(crate) fn branch_region( counter: coverage_map::Counter, false_counter: coverage_map::Counter, file_id: u32, @@ -824,7 +823,7 @@ pub mod coverageinfo { // This function might be used in the future; the LLVM API is still evolving, as is coverage // support. #[allow(dead_code)] - crate fn expansion_region( + pub(crate) fn expansion_region( file_id: u32, expanded_file_id: u32, start_line: u32, @@ -848,7 +847,7 @@ pub mod coverageinfo { // This function might be used in the future; the LLVM API is still evolving, as is coverage // support. #[allow(dead_code)] - crate fn skipped_region( + pub(crate) fn skipped_region( file_id: u32, start_line: u32, start_col: u32, @@ -871,7 +870,7 @@ pub mod coverageinfo { // This function might be used in the future; the LLVM API is still evolving, as is coverage // support. #[allow(dead_code)] - crate fn gap_region( + pub(crate) fn gap_region( counter: coverage_map::Counter, file_id: u32, start_line: u32, diff --git a/compiler/rustc_codegen_llvm/src/type_.rs b/compiler/rustc_codegen_llvm/src/type_.rs index 21b77f7dea6fb..cf2d3c423c335 100644 --- a/compiler/rustc_codegen_llvm/src/type_.rs +++ b/compiler/rustc_codegen_llvm/src/type_.rs @@ -39,33 +39,33 @@ impl fmt::Debug for Type { } impl<'ll> CodegenCx<'ll, '_> { - crate fn type_named_struct(&self, name: &str) -> &'ll Type { + pub(crate) fn type_named_struct(&self, name: &str) -> &'ll Type { let name = SmallCStr::new(name); unsafe { llvm::LLVMStructCreateNamed(self.llcx, name.as_ptr()) } } - crate fn set_struct_body(&self, ty: &'ll Type, els: &[&'ll Type], packed: bool) { + pub(crate) fn set_struct_body(&self, ty: &'ll Type, els: &[&'ll Type], packed: bool) { unsafe { llvm::LLVMStructSetBody(ty, els.as_ptr(), els.len() as c_uint, packed as Bool) } } - crate fn type_void(&self) -> &'ll Type { + pub(crate) fn type_void(&self) -> &'ll Type { unsafe { llvm::LLVMVoidTypeInContext(self.llcx) } } - crate fn type_metadata(&self) -> &'ll Type { + pub(crate) fn type_metadata(&self) -> &'ll Type { unsafe { llvm::LLVMRustMetadataTypeInContext(self.llcx) } } ///x Creates an integer type with the given number of bits, e.g., i24 - crate fn type_ix(&self, num_bits: u64) -> &'ll Type { + pub(crate) fn type_ix(&self, num_bits: u64) -> &'ll Type { unsafe { llvm::LLVMIntTypeInContext(self.llcx, num_bits as c_uint) } } - crate fn type_vector(&self, ty: &'ll Type, len: u64) -> &'ll Type { + pub(crate) fn type_vector(&self, ty: &'ll Type, len: u64) -> &'ll Type { unsafe { llvm::LLVMVectorType(ty, len as c_uint) } } - crate fn func_params_types(&self, ty: &'ll Type) -> Vec<&'ll Type> { + pub(crate) fn func_params_types(&self, ty: &'ll Type) -> Vec<&'ll Type> { unsafe { let n_args = llvm::LLVMCountParamTypes(ty) as usize; let mut args = Vec::with_capacity(n_args); @@ -75,11 +75,11 @@ impl<'ll> CodegenCx<'ll, '_> { } } - crate fn type_bool(&self) -> &'ll Type { + pub(crate) fn type_bool(&self) -> &'ll Type { self.type_i8() } - crate fn type_int_from_ty(&self, t: ty::IntTy) -> &'ll Type { + pub(crate) fn type_int_from_ty(&self, t: ty::IntTy) -> &'ll Type { match t { ty::IntTy::Isize => self.type_isize(), ty::IntTy::I8 => self.type_i8(), @@ -90,7 +90,7 @@ impl<'ll> CodegenCx<'ll, '_> { } } - crate fn type_uint_from_ty(&self, t: ty::UintTy) -> &'ll Type { + pub(crate) fn type_uint_from_ty(&self, t: ty::UintTy) -> &'ll Type { match t { ty::UintTy::Usize => self.type_isize(), ty::UintTy::U8 => self.type_i8(), @@ -101,14 +101,14 @@ impl<'ll> CodegenCx<'ll, '_> { } } - crate fn type_float_from_ty(&self, t: ty::FloatTy) -> &'ll Type { + pub(crate) fn type_float_from_ty(&self, t: ty::FloatTy) -> &'ll Type { match t { ty::FloatTy::F32 => self.type_f32(), ty::FloatTy::F64 => self.type_f64(), } } - crate fn type_pointee_for_align(&self, align: Align) -> &'ll Type { + pub(crate) fn type_pointee_for_align(&self, align: Align) -> &'ll Type { // FIXME(eddyb) We could find a better approximation if ity.align < align. let ity = Integer::approximate_align(self, align); self.type_from_integer(ity) @@ -116,7 +116,7 @@ impl<'ll> CodegenCx<'ll, '_> { /// Return a LLVM type that has at most the required alignment, /// and exactly the required size, as a best-effort padding array. - crate fn type_padding_filler(&self, size: Size, align: Align) -> &'ll Type { + pub(crate) fn type_padding_filler(&self, size: Size, align: Align) -> &'ll Type { let unit = Integer::approximate_align(self, align); let size = size.bytes(); let unit_size = unit.size().bytes(); @@ -124,11 +124,11 @@ impl<'ll> CodegenCx<'ll, '_> { self.type_array(self.type_from_integer(unit), size / unit_size) } - crate fn type_variadic_func(&self, args: &[&'ll Type], ret: &'ll Type) -> &'ll Type { + pub(crate) fn type_variadic_func(&self, args: &[&'ll Type], ret: &'ll Type) -> &'ll Type { unsafe { llvm::LLVMFunctionType(ret, args.as_ptr(), args.len() as c_uint, True) } } - crate fn type_array(&self, ty: &'ll Type, len: u64) -> &'ll Type { + pub(crate) fn type_array(&self, ty: &'ll Type, len: u64) -> &'ll Type { unsafe { llvm::LLVMRustArrayType(ty, len) } } } diff --git a/compiler/rustc_codegen_ssa/src/back/command.rs b/compiler/rustc_codegen_ssa/src/back/command.rs index 17071ba1b5bf3..6c29692bd3bfe 100644 --- a/compiler/rustc_codegen_ssa/src/back/command.rs +++ b/compiler/rustc_codegen_ssa/src/back/command.rs @@ -105,12 +105,7 @@ impl Command { } Program::Lld(ref p, flavor) => { let mut c = process::Command::new(p); - c.arg("-flavor").arg(match flavor { - LldFlavor::Wasm => "wasm", - LldFlavor::Ld => "gnu", - LldFlavor::Link => "link", - LldFlavor::Ld64 => "darwin", - }); + c.arg("-flavor").arg(flavor.as_str()); if let LldFlavor::Wasm = flavor { // LLVM expects host-specific formatting for @file // arguments, but we always generate posix formatted files diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 04ec1e7f3c1af..fc30679be03cb 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -5,7 +5,7 @@ use rustc_data_structures::memmap::Mmap; use rustc_data_structures::temp_dir::MaybeTempDir; use rustc_errors::{ErrorGuaranteed, Handler}; use rustc_fs_util::fix_windows_verbatim_for_gcc; -use rustc_hir::def_id::{CrateNum, LOCAL_CRATE}; +use rustc_hir::def_id::CrateNum; use rustc_middle::middle::dependency_format::Linkage; use rustc_middle::middle::exported_symbols::SymbolExportKind; use rustc_session::config::{self, CFGuard, CrateType, DebugInfo, LdImpl, Strip}; @@ -18,6 +18,7 @@ use rustc_session::utils::NativeLibKind; /// need out of the shared crate context before we get rid of it. use rustc_session::{filesearch, Session}; use rustc_span::symbol::Symbol; +use rustc_span::DebuggerVisualizerFile; use rustc_target::spec::crt_objects::{CrtObjects, CrtObjectsFallback}; use rustc_target::spec::{LinkOutputKind, LinkerFlavor, LldFlavor, SplitDebuginfo}; use rustc_target::spec::{PanicStrategy, RelocModel, RelroLevel, SanitizerSet, Target}; @@ -37,6 +38,7 @@ use regex::Regex; use tempfile::Builder as TempFileBuilder; use std::borrow::Borrow; +use std::collections::BTreeSet; use std::ffi::OsString; use std::fs::{File, OpenOptions}; use std::io::{BufWriter, Write}; @@ -2099,14 +2101,16 @@ fn add_order_independent_options( // Pass optimization flags down to the linker. cmd.optimize(); - let debugger_visualizer_paths = if sess.target.is_like_msvc { - collect_debugger_visualizers(tmpdir, sess, &codegen_results.crate_info) - } else { - Vec::new() - }; + // Gather the set of NatVis files, if any, and write them out to a temp directory. + let natvis_visualizers = collect_natvis_visualizers( + tmpdir, + sess, + &codegen_results.crate_info.local_crate_name, + &codegen_results.crate_info.natvis_debugger_visualizers, + ); - // Pass debuginfo and strip flags down to the linker. - cmd.debuginfo(strip_value(sess), &debugger_visualizer_paths); + // Pass debuginfo, NatVis debugger visualizers and strip flags down to the linker. + cmd.debuginfo(strip_value(sess), &natvis_visualizers); // We want to prevent the compiler from accidentally leaking in any system libraries, // so by default we tell linkers not to link to any default libraries. @@ -2125,43 +2129,33 @@ fn add_order_independent_options( add_rpath_args(cmd, sess, codegen_results, out_filename); } -// Write the debugger visualizer files for each crate to the temp directory and gather the file paths. -fn collect_debugger_visualizers( +// Write the NatVis debugger visualizer files for each crate to the temp directory and gather the file paths. +fn collect_natvis_visualizers( tmpdir: &Path, sess: &Session, - crate_info: &CrateInfo, + crate_name: &Symbol, + natvis_debugger_visualizers: &BTreeSet, ) -> Vec { - let mut visualizer_paths = Vec::new(); - let debugger_visualizers = &crate_info.debugger_visualizers; - let mut index = 0; + let mut visualizer_paths = Vec::with_capacity(natvis_debugger_visualizers.len()); - for (&cnum, visualizers) in debugger_visualizers { - let crate_name = if cnum == LOCAL_CRATE { - crate_info.local_crate_name.as_str() - } else { - crate_info.crate_name[&cnum].as_str() - }; - - for visualizer in visualizers { - let visualizer_out_file = tmpdir.join(format!("{}-{}.natvis", crate_name, index)); + for (index, visualizer) in natvis_debugger_visualizers.iter().enumerate() { + let visualizer_out_file = tmpdir.join(format!("{}-{}.natvis", crate_name.as_str(), index)); - match fs::write(&visualizer_out_file, &visualizer.src) { - Ok(()) => { - visualizer_paths.push(visualizer_out_file.clone()); - index += 1; - } - Err(error) => { - sess.warn( - format!( - "Unable to write debugger visualizer file `{}`: {} ", - visualizer_out_file.display(), - error - ) - .as_str(), - ); - } - }; - } + match fs::write(&visualizer_out_file, &visualizer.src) { + Ok(()) => { + visualizer_paths.push(visualizer_out_file); + } + Err(error) => { + sess.warn( + format!( + "Unable to write debugger visualizer file `{}`: {} ", + visualizer_out_file.display(), + error + ) + .as_str(), + ); + } + }; } visualizer_paths } @@ -2698,37 +2692,20 @@ fn add_gcc_ld_path(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) { if let LinkerFlavor::Gcc = flavor { match ld_impl { LdImpl::Lld => { - if sess.target.lld_flavor == LldFlavor::Ld64 { - let tools_path = sess.get_tools_search_paths(false); - let ld64_exe = tools_path - .into_iter() - .map(|p| p.join("gcc-ld")) - .map(|p| { - p.join(if sess.host.is_like_windows { "ld64.exe" } else { "ld64" }) - }) - .find(|p| p.exists()) - .unwrap_or_else(|| sess.fatal("rust-lld (as ld64) not found")); - cmd.cmd().arg({ - let mut arg = OsString::from("-fuse-ld="); - arg.push(ld64_exe); - arg - }); - } else { - let tools_path = sess.get_tools_search_paths(false); - let lld_path = tools_path - .into_iter() - .map(|p| p.join("gcc-ld")) - .find(|p| { - p.join(if sess.host.is_like_windows { "ld.exe" } else { "ld" }) - .exists() - }) - .unwrap_or_else(|| sess.fatal("rust-lld (as ld) not found")); - cmd.cmd().arg({ - let mut arg = OsString::from("-B"); - arg.push(lld_path); - arg - }); - } + let tools_path = sess.get_tools_search_paths(false); + let gcc_ld_dir = tools_path + .into_iter() + .map(|p| p.join("gcc-ld")) + .find(|p| { + p.join(if sess.host.is_like_windows { "ld.exe" } else { "ld" }).exists() + }) + .unwrap_or_else(|| sess.fatal("rust-lld (as ld) not found")); + cmd.arg({ + let mut arg = OsString::from("-B"); + arg.push(gcc_ld_dir); + arg + }); + cmd.arg(format!("-Wl,-rustc-lld-flavor={}", sess.target.lld_flavor.as_str())); } } } else { diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index 2a71377d2f15b..e4236876463fc 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -183,7 +183,7 @@ pub trait Linker { fn optimize(&mut self); fn pgo_gen(&mut self); fn control_flow_guard(&mut self); - fn debuginfo(&mut self, strip: Strip, debugger_visualizers: &[PathBuf]); + fn debuginfo(&mut self, strip: Strip, natvis_debugger_visualizers: &[PathBuf]); fn no_crt_objects(&mut self); fn no_default_libraries(&mut self); fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType, symbols: &[String]); @@ -915,7 +915,7 @@ impl<'a> Linker for MsvcLinker<'a> { self.cmd.arg("/guard:cf"); } - fn debuginfo(&mut self, strip: Strip, debugger_visualizers: &[PathBuf]) { + fn debuginfo(&mut self, strip: Strip, natvis_debugger_visualizers: &[PathBuf]) { match strip { Strip::None => { // This will cause the Microsoft linker to generate a PDB file @@ -944,7 +944,7 @@ impl<'a> Linker for MsvcLinker<'a> { } // This will cause the Microsoft linker to embed .natvis info for all crates into the PDB file - for path in debugger_visualizers { + for path in natvis_debugger_visualizers { let mut arg = OsString::from("/NATVIS:"); arg.push(path); self.cmd.arg(arg); diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 7b7e09208a24a..420adec456f61 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -15,8 +15,9 @@ use rustc_attr as attr; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry}; +use rustc_data_structures::sync::par_iter; #[cfg(parallel_compiler)] -use rustc_data_structures::sync::{par_iter, ParallelIterator}; +use rustc_data_structures::sync::ParallelIterator; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_hir::lang_items::LangItem; @@ -30,11 +31,13 @@ use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, TyAndLayout}; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; use rustc_session::cgu_reuse_tracker::CguReuse; -use rustc_session::config::{self, EntryFnType, OutputType}; +use rustc_session::config::{self, CrateType, EntryFnType, OutputType}; use rustc_session::Session; use rustc_span::symbol::sym; +use rustc_span::{DebuggerVisualizerFile, DebuggerVisualizerType}; use rustc_target::abi::{Align, VariantIdx}; +use std::collections::BTreeSet; use std::convert::TryFrom; use std::ops::{Deref, DerefMut}; use std::time::{Duration, Instant}; @@ -486,6 +489,29 @@ fn get_argc_argv<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( } } +/// This function returns all of the debugger visualizers specified for the +/// current crate as well as all upstream crates transitively that match the +/// `visualizer_type` specified. +pub fn collect_debugger_visualizers_transitive( + tcx: TyCtxt<'_>, + visualizer_type: DebuggerVisualizerType, +) -> BTreeSet { + tcx.debugger_visualizers(LOCAL_CRATE) + .iter() + .chain( + tcx.crates(()) + .iter() + .filter(|&cnum| { + let used_crate_source = tcx.used_crate_source(*cnum); + used_crate_source.rlib.is_some() || used_crate_source.rmeta.is_some() + }) + .flat_map(|&cnum| tcx.debugger_visualizers(cnum)), + ) + .filter(|visualizer| visualizer.visualizer_type == visualizer_type) + .cloned() + .collect::>() +} + pub fn codegen_crate( backend: B, tcx: TyCtxt<'_>, @@ -607,6 +633,14 @@ pub fn codegen_crate( second_half.iter().rev().interleave(first_half).copied().collect() }; + // Calculate the CGU reuse + let cgu_reuse = tcx.sess.time("find_cgu_reuse", || { + codegen_units.iter().map(|cgu| determine_cgu_reuse(tcx, &cgu)).collect::>() + }); + + let mut total_codegen_time = Duration::new(0, 0); + let start_rss = tcx.sess.time_passes().then(|| get_resident_set_size()); + // The non-parallel compiler can only translate codegen units to LLVM IR // on a single thread, leading to a staircase effect where the N LLVM // threads have to wait on the single codegen threads to generate work @@ -617,8 +651,7 @@ pub fn codegen_crate( // This likely is a temporary measure. Once we don't have to support the // non-parallel compiler anymore, we can compile CGUs end-to-end in // parallel and get rid of the complicated scheduling logic. - #[cfg(parallel_compiler)] - let pre_compile_cgus = |cgu_reuse: &[CguReuse]| { + let mut pre_compiled_cgus = if cfg!(parallel_compiler) { tcx.sess.time("compile_first_CGU_batch", || { // Try to find one CGU to compile per thread. let cgus: Vec<_> = cgu_reuse @@ -638,48 +671,31 @@ pub fn codegen_crate( }) .collect(); - (pre_compiled_cgus, start_time.elapsed()) + total_codegen_time += start_time.elapsed(); + + pre_compiled_cgus }) + } else { + FxHashMap::default() }; - #[cfg(not(parallel_compiler))] - let pre_compile_cgus = |_: &[CguReuse]| (FxHashMap::default(), Duration::new(0, 0)); - - let mut cgu_reuse = Vec::new(); - let mut pre_compiled_cgus: Option> = None; - let mut total_codegen_time = Duration::new(0, 0); - let start_rss = tcx.sess.time_passes().then(|| get_resident_set_size()); - for (i, cgu) in codegen_units.iter().enumerate() { ongoing_codegen.wait_for_signal_to_codegen_item(); ongoing_codegen.check_for_errors(tcx.sess); - // Do some setup work in the first iteration - if pre_compiled_cgus.is_none() { - // Calculate the CGU reuse - cgu_reuse = tcx.sess.time("find_cgu_reuse", || { - codegen_units.iter().map(|cgu| determine_cgu_reuse(tcx, &cgu)).collect() - }); - // Pre compile some CGUs - let (compiled_cgus, codegen_time) = pre_compile_cgus(&cgu_reuse); - pre_compiled_cgus = Some(compiled_cgus); - total_codegen_time += codegen_time; - } - let cgu_reuse = cgu_reuse[i]; tcx.sess.cgu_reuse_tracker.set_actual_reuse(cgu.name().as_str(), cgu_reuse); match cgu_reuse { CguReuse::No => { - let (module, cost) = - if let Some(cgu) = pre_compiled_cgus.as_mut().unwrap().remove(&i) { - cgu - } else { - let start_time = Instant::now(); - let module = backend.compile_codegen_unit(tcx, cgu.name()); - total_codegen_time += start_time.elapsed(); - module - }; + let (module, cost) = if let Some(cgu) = pre_compiled_cgus.remove(&i) { + cgu + } else { + let start_time = Instant::now(); + let module = backend.compile_codegen_unit(tcx, cgu.name()); + total_codegen_time += start_time.elapsed(); + module + }; // This will unwind if there are errors, which triggers our `AbortCodegenOnDrop` // guard. Unfortunately, just skipping the `submit_codegened_module_to_llvm` makes // compilation hang on post-monomorphization errors. @@ -847,13 +863,8 @@ impl CrateInfo { missing_lang_items: Default::default(), dependency_formats: tcx.dependency_formats(()).clone(), windows_subsystem, - debugger_visualizers: Default::default(), + natvis_debugger_visualizers: Default::default(), }; - let debugger_visualizers = tcx.debugger_visualizers(LOCAL_CRATE).clone(); - if !debugger_visualizers.is_empty() { - info.debugger_visualizers.insert(LOCAL_CRATE, debugger_visualizers); - } - let lang_items = tcx.lang_items(); let crates = tcx.crates(()); @@ -891,14 +902,29 @@ impl CrateInfo { let missing = missing.iter().cloned().filter(|&l| lang_items::required(tcx, l)).collect(); info.missing_lang_items.insert(cnum, missing); + } - // Only include debugger visualizer files from crates that will be statically linked. - if used_crate_source.rlib.is_some() || used_crate_source.rmeta.is_some() { - let debugger_visualizers = tcx.debugger_visualizers(cnum).clone(); - if !debugger_visualizers.is_empty() { - info.debugger_visualizers.insert(cnum, debugger_visualizers); - } + let embed_visualizers = tcx.sess.crate_types().iter().any(|&crate_type| match crate_type { + CrateType::Executable | CrateType::Dylib | CrateType::Cdylib => { + // These are crate types for which we invoke the linker and can embed + // NatVis visualizers. + true + } + CrateType::ProcMacro => { + // We could embed NatVis for proc macro crates too (to improve the debugging + // experience for them) but it does not seem like a good default, since + // this is a rare use case and we don't want to slow down the common case. + false } + CrateType::Staticlib | CrateType::Rlib => { + // We don't invoke the linker for these, so we don't need to collect the NatVis for them. + false + } + }); + + if tcx.sess.target.is_like_msvc && embed_visualizers { + info.natvis_debugger_visualizers = + collect_debugger_visualizers_transitive(tcx, DebuggerVisualizerType::Natvis); } info diff --git a/compiler/rustc_codegen_ssa/src/common.rs b/compiler/rustc_codegen_ssa/src/common.rs index 1574b30497b4b..8ca1a6084cf6f 100644 --- a/compiler/rustc_codegen_ssa/src/common.rs +++ b/compiler/rustc_codegen_ssa/src/common.rs @@ -11,6 +11,7 @@ use rustc_span::Span; use crate::base; use crate::traits::*; +#[derive(Copy, Clone)] pub enum IntPredicate { IntEQ, IntNE, @@ -24,6 +25,7 @@ pub enum IntPredicate { IntSLE, } +#[derive(Copy, Clone)] pub enum RealPredicate { RealPredicateFalse, RealOEQ, @@ -43,6 +45,7 @@ pub enum RealPredicate { RealPredicateTrue, } +#[derive(Copy, Clone)] pub enum AtomicRmwBinOp { AtomicXchg, AtomicAdd, @@ -57,17 +60,17 @@ pub enum AtomicRmwBinOp { AtomicUMin, } +#[derive(Copy, Clone)] pub enum AtomicOrdering { - NotAtomic, Unordered, - Monotonic, - // Consume, // Not specified yet. + Relaxed, Acquire, Release, AcquireRelease, SequentiallyConsistent, } +#[derive(Copy, Clone)] pub enum SynchronizationScope { SingleThread, CrossThread, diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index 9e1fe588c5379..7fde700be393d 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -36,6 +36,7 @@ use rustc_session::cstore::{self, CrateSource}; use rustc_session::utils::NativeLibKind; use rustc_span::symbol::Symbol; use rustc_span::DebuggerVisualizerFile; +use std::collections::BTreeSet; use std::path::{Path, PathBuf}; pub mod back; @@ -157,7 +158,7 @@ pub struct CrateInfo { pub missing_lang_items: FxHashMap>, pub dependency_formats: Lrc, pub windows_subsystem: Option, - pub debugger_visualizers: FxHashMap>, + pub natvis_debugger_visualizers: BTreeSet, } #[derive(Encodable, Decodable)] diff --git a/compiler/rustc_codegen_ssa/src/mir/analyze.rs b/compiler/rustc_codegen_ssa/src/mir/analyze.rs index fa39e8dd247d5..80dab115fac46 100644 --- a/compiler/rustc_codegen_ssa/src/mir/analyze.rs +++ b/compiler/rustc_codegen_ssa/src/mir/analyze.rs @@ -328,7 +328,7 @@ pub fn cleanup_kinds(mir: &mir::Body<'_>) -> IndexVec> FunctionCx<'a, 'tcx, Bx> { intrinsic: Option, instance: Option>, source_info: mir::SourceInfo, - destination: &Option<(mir::Place<'tcx>, mir::BasicBlock)>, + target: Option, cleanup: Option, + strict_validity: bool, ) -> bool { // Emit a panic or a no-op for `assert_*` intrinsics. // These are intrinsics that compile to panics so that we can get a message @@ -543,8 +544,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let layout = bx.layout_of(ty); let do_panic = match intrinsic { Inhabited => layout.abi.is_uninhabited(), - ZeroValid => !layout.might_permit_raw_init(bx, /*zero:*/ true), - UninitValid => !layout.might_permit_raw_init(bx, /*zero:*/ false), + ZeroValid => !layout.might_permit_raw_init(bx, InitKind::Zero, strict_validity), + UninitValid => !layout.might_permit_raw_init(bx, InitKind::Uninit, strict_validity), }; if do_panic { let msg_str = with_no_visible_paths!({ @@ -576,12 +577,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { fn_abi, llfn, &[msg.0, msg.1, location], - destination.as_ref().map(|(_, bb)| (ReturnDest::Nothing, *bb)), + target.as_ref().map(|bb| (ReturnDest::Nothing, *bb)), cleanup, ); } else { // a NOP - let target = destination.as_ref().unwrap().1; + let target = target.unwrap(); helper.funclet_br(self, bx, target) } true @@ -597,7 +598,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { terminator: &mir::Terminator<'tcx>, func: &mir::Operand<'tcx>, args: &[mir::Operand<'tcx>], - destination: &Option<(mir::Place<'tcx>, mir::BasicBlock)>, + destination: mir::Place<'tcx>, + target: Option, cleanup: Option, fn_span: Span, ) { @@ -624,7 +626,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { if let Some(ty::InstanceDef::DropGlue(_, None)) = def { // Empty drop glue; a no-op. - let &(_, target) = destination.as_ref().unwrap(); + let target = target.unwrap(); helper.funclet_br(self, &mut bx, target); return; } @@ -653,9 +655,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { }; if intrinsic == Some(sym::transmute) { - if let Some(destination_ref) = destination.as_ref() { - let &(dest, target) = destination_ref; - self.codegen_transmute(&mut bx, &args[0], dest); + if let Some(target) = target { + self.codegen_transmute(&mut bx, &args[0], destination); helper.funclet_br(self, &mut bx, target); } else { // If we are trying to transmute to an uninhabited type, @@ -676,8 +677,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { intrinsic, instance, source_info, - destination, + target, cleanup, + self.cx.tcx().sess.opts.debugging_opts.strict_init_checks, ) { return; } @@ -687,15 +689,15 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let mut llargs = Vec::with_capacity(arg_count); // Prepare the return value destination - let ret_dest = if let Some((dest, _)) = *destination { + let ret_dest = if target.is_some() { let is_intrinsic = intrinsic.is_some(); - self.make_return_dest(&mut bx, dest, &fn_abi.ret, &mut llargs, is_intrinsic) + self.make_return_dest(&mut bx, destination, &fn_abi.ret, &mut llargs, is_intrinsic) } else { ReturnDest::Nothing }; if intrinsic == Some(sym::caller_location) { - if let Some((_, target)) = destination.as_ref() { + if let Some(target) = target { let location = self .get_caller_location(&mut bx, mir::SourceInfo { span: fn_span, ..source_info }); @@ -703,7 +705,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { location.val.store(&mut bx, tmp); } self.store_return(&mut bx, ret_dest, &fn_abi.ret, location.immediate()); - helper.funclet_br(self, &mut bx, *target); + helper.funclet_br(self, &mut bx, target); } return; } @@ -766,7 +768,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { self.store_return(&mut bx, ret_dest, &fn_abi.ret, dst.llval); } - if let Some((_, target)) = *destination { + if let Some(target) = target { helper.funclet_br(self, &mut bx, target); } else { bx.unreachable(); @@ -913,7 +915,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { fn_abi, fn_ptr, &llargs, - destination.as_ref().map(|&(_, target)| (ret_dest, target)), + target.as_ref().map(|&target| (ret_dest, target)), cleanup, ); @@ -930,7 +932,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { fn_abi, fn_ptr, &llargs, - destination.as_ref().map(|&(_, target)| (ret_dest, target)), + target.as_ref().map(|&target| (ret_dest, target)), cleanup, ); } @@ -1083,7 +1085,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { mir::TerminatorKind::Call { ref func, ref args, - ref destination, + destination, + target, cleanup, from_hir_call: _, fn_span, @@ -1095,6 +1098,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { func, args, destination, + target, cleanup, fn_span, ); diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs index 6d6d3ae01f4a3..0ed4c3f1d9430 100644 --- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs +++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs @@ -388,17 +388,17 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { 2 => (SequentiallyConsistent, SequentiallyConsistent), 3 => match split[2] { "unordered" => (Unordered, Unordered), - "relaxed" => (Monotonic, Monotonic), + "relaxed" => (Relaxed, Relaxed), "acq" => (Acquire, Acquire), - "rel" => (Release, Monotonic), + "rel" => (Release, Relaxed), "acqrel" => (AcquireRelease, Acquire), - "failrelaxed" if is_cxchg => (SequentiallyConsistent, Monotonic), + "failrelaxed" if is_cxchg => (SequentiallyConsistent, Relaxed), "failacq" if is_cxchg => (SequentiallyConsistent, Acquire), _ => bx.sess().fatal("unknown ordering in atomic intrinsic"), }, 4 => match (split[2], split[3]) { - ("acq", "failrelaxed") if is_cxchg => (Acquire, Monotonic), - ("acqrel", "failrelaxed") if is_cxchg => (AcquireRelease, Monotonic), + ("acq", "failrelaxed") if is_cxchg => (Acquire, Relaxed), + ("acqrel", "failrelaxed") if is_cxchg => (AcquireRelease, Relaxed), _ => bx.sess().fatal("unknown ordering in atomic intrinsic"), }, _ => bx.sess().fatal("Atomic intrinsic not in correct format"), diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs index b6a7bcae93284..3185b952ab886 100644 --- a/compiler/rustc_codegen_ssa/src/mir/place.rs +++ b/compiler/rustc_codegen_ssa/src/mir/place.rs @@ -462,7 +462,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } }; for elem in place_ref.projection[base..].iter() { - cg_base = match elem.clone() { + cg_base = match *elem { mir::ProjectionElem::Deref => { // a box with a non-zst allocator should not be directly dereferenced if cg_base.layout.ty.is_box() && !cg_base.layout.field(cx, 1).is_zst() { diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index fd29c9e281b92..6ff8d4aa44216 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -181,6 +181,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let cast = bx.cx().layout_of(self.monomorphize(mir_cast_ty)); let val = match *kind { + mir::CastKind::PointerExposeAddress => { + assert!(bx.cx().is_backend_immediate(cast)); + let llptr = operand.immediate(); + let llcast_ty = bx.cx().immediate_backend_type(cast); + let lladdr = bx.ptrtoint(llptr, llcast_ty); + OperandValue::Immediate(lladdr) + } mir::CastKind::Pointer(PointerCast::ReifyFnPointer) => { match *operand.layout.ty.kind() { ty::FnDef(def_id, substs) => { @@ -362,9 +369,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { (CastTy::Ptr(_) | CastTy::FnPtr, CastTy::Ptr(_)) => { bx.pointercast(llval, ll_t_out) } - (CastTy::Ptr(_) | CastTy::FnPtr, CastTy::Int(_)) => { - bx.ptrtoint(llval, ll_t_out) - } (CastTy::Int(_), CastTy::Ptr(_)) => { let usize_llval = bx.intcast(llval, bx.cx().type_isize(), signed); bx.inttoptr(usize_llval, ll_t_out) diff --git a/compiler/rustc_const_eval/Cargo.toml b/compiler/rustc_const_eval/Cargo.toml index 4ed908a383332..32e8233a0415f 100644 --- a/compiler/rustc_const_eval/Cargo.toml +++ b/compiler/rustc_const_eval/Cargo.toml @@ -24,3 +24,4 @@ rustc_session = { path = "../rustc_session" } rustc_target = { path = "../rustc_target" } rustc_trait_selection = { path = "../rustc_trait_selection" } rustc_span = { path = "../rustc_span" } +rustc_type_ir = { path = "../rustc_type_ir" } diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index 5c56e6ee5f5b7..0c20324e45239 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -60,7 +60,7 @@ fn eval_body_using_ecx<'mir, 'tcx>( ecx.push_stack_frame( cid.instance, body, - Some(&ret.into()), + &ret.into(), StackPopCleanup::Root { cleanup: false }, )?; @@ -135,7 +135,7 @@ pub(super) fn op_to_const<'tcx>( } else { // It is guaranteed that any non-slice scalar pair is actually ByRef here. // When we come back from raw const eval, we are always by-ref. The only way our op here is - // by-val is if we are in destructure_const, i.e., if this is (a field of) something that we + // by-val is if we are in destructure_mir_constant, i.e., if this is (a field of) something that we // "tried to make immediate" before. We wouldn't do that for non-slice scalar pairs or // structs containing such. op.try_as_mplace() diff --git a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs index 1f291db55be96..d6f62062d1f8e 100644 --- a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs @@ -4,13 +4,12 @@ use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{DefIdTree, TyCtxt}; use rustc_span::symbol::Symbol; -use rustc_target::spec::abi::Abi; /// Whether the `def_id` is an unstable const fn and what feature gate is necessary to enable it pub fn is_unstable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> Option { if tcx.is_const_fn_raw(def_id) { let const_stab = tcx.lookup_const_stability(def_id)?; - if const_stab.level.is_unstable() { Some(const_stab.feature) } else { None } + if const_stab.is_const_unstable() { Some(const_stab.feature) } else { None } } else { None } @@ -34,10 +33,7 @@ fn impl_constness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::Constness { hir::Node::ForeignItem(hir::ForeignItem { kind: hir::ForeignItemKind::Fn(..), .. }) => { // Intrinsics use `rustc_const_{un,}stable` attributes to indicate constness. All other // foreign items cannot be evaluated at compile-time. - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); - let is_const = if let Abi::RustIntrinsic | Abi::PlatformIntrinsic = - tcx.hir().get_foreign_abi(hir_id) - { + let is_const = if tcx.is_intrinsic(def_id) { tcx.lookup_const_stability(def_id).is_some() } else { false diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index c5a11aaceaf9a..ac529bf152f2b 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -163,7 +163,7 @@ impl interpret::AllocMap for FxHashMap { } } -crate type CompileTimeEvalContext<'mir, 'tcx> = +pub(crate) type CompileTimeEvalContext<'mir, 'tcx> = InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>>; #[derive(Debug, PartialEq, Eq, Copy, Clone)] @@ -265,7 +265,8 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, instance: ty::Instance<'tcx>, _abi: Abi, args: &[OpTy<'tcx>], - _ret: Option<(&PlaceTy<'tcx>, mir::BasicBlock)>, + _dest: &PlaceTy<'tcx>, + _ret: Option, _unwind: StackPopUnwind, // unwinding is not supported in consts ) -> InterpResult<'tcx, Option<(&'mir mir::Body<'tcx>, ty::Instance<'tcx>)>> { debug!("find_mir_or_eval_fn: {:?}", instance); @@ -276,8 +277,8 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, // sensitive check here. But we can at least rule out functions that are not const // at all. if !ecx.tcx.is_const_fn_raw(def.did) { - // allow calling functions marked with #[default_method_body_is_const]. - if !ecx.tcx.has_attr(def.did, sym::default_method_body_is_const) { + // allow calling functions inside a trait marked with #[const_trait]. + if !ecx.tcx.is_const_default_method(def.did) { // We certainly do *not* want to actually call the fn // though, so be sure we return here. throw_unsup_format!("calling non-const function `{}`", instance) @@ -293,6 +294,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, new_instance, _abi, args, + _dest, _ret, _unwind, )? @@ -307,17 +309,18 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, ecx: &mut InterpCx<'mir, 'tcx, Self>, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx>], - ret: Option<(&PlaceTy<'tcx>, mir::BasicBlock)>, + dest: &PlaceTy<'tcx, Self::PointerTag>, + target: Option, _unwind: StackPopUnwind, ) -> InterpResult<'tcx> { // Shared intrinsics. - if ecx.emulate_intrinsic(instance, args, ret)? { + if ecx.emulate_intrinsic(instance, args, dest, target)? { return Ok(()); } let intrinsic_name = ecx.tcx.item_name(instance.def_id()); // CTFE-specific intrinsics. - let Some((dest, ret)) = ret else { + let Some(ret) = target else { return Err(ConstEvalErrKind::NeedsRfc(format!( "calling intrinsic `{}`", intrinsic_name diff --git a/compiler/rustc_const_eval/src/const_eval/mod.rs b/compiler/rustc_const_eval/src/const_eval/mod.rs index 96c18d488ee8c..db43f7a425ce6 100644 --- a/compiler/rustc_const_eval/src/const_eval/mod.rs +++ b/compiler/rustc_const_eval/src/const_eval/mod.rs @@ -4,6 +4,7 @@ use std::convert::TryFrom; use rustc_hir::Mutability; use rustc_middle::mir; +use rustc_middle::mir::interpret::{EvalToValTreeResult, GlobalId}; use rustc_middle::ty::{self, TyCtxt}; use rustc_span::{source_map::DUMMY_SP, symbol::Symbol}; @@ -22,7 +23,7 @@ pub use error::*; pub use eval_queries::*; pub use fn_queries::*; pub use machine::*; -pub(crate) use valtrees::{const_to_valtree, valtree_to_const_value}; +pub(crate) use valtrees::{const_to_valtree_inner, valtree_to_const_value}; pub(crate) fn const_caller_location( tcx: TyCtxt<'_>, @@ -38,6 +39,57 @@ pub(crate) fn const_caller_location( ConstValue::Scalar(Scalar::from_maybe_pointer(loc_place.ptr, &tcx)) } +// We forbid type-level constants that contain more than `VALTREE_MAX_NODES` nodes. +const VALTREE_MAX_NODES: usize = 1000; + +pub(crate) enum ValTreeCreationError { + NodesOverflow, + NonSupportedType, + Other, +} +pub(crate) type ValTreeCreationResult<'tcx> = Result, ValTreeCreationError>; + +/// Evaluates a constant and turns it into a type-level constant value. +pub(crate) fn eval_to_valtree<'tcx>( + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + cid: GlobalId<'tcx>, +) -> EvalToValTreeResult<'tcx> { + let const_alloc = tcx.eval_to_allocation_raw(param_env.and(cid))?; + let ecx = mk_eval_cx( + tcx, DUMMY_SP, param_env, + // It is absolutely crucial for soundness that + // we do not read from static items or other mutable memory. + false, + ); + let place = ecx.raw_const_to_mplace(const_alloc).unwrap(); + debug!(?place); + + let mut num_nodes = 0; + let valtree_result = const_to_valtree_inner(&ecx, &place, &mut num_nodes); + + match valtree_result { + Ok(valtree) => Ok(Some(valtree)), + Err(err) => { + let did = cid.instance.def_id(); + let s = cid.display(tcx); + match err { + ValTreeCreationError::NodesOverflow => { + let msg = format!("maximum number of nodes exceeded in constant {}", &s); + let mut diag = match tcx.hir().span_if_local(did) { + Some(span) => tcx.sess.struct_span_err(span, &msg), + None => tcx.sess.struct_err(&msg), + }; + diag.emit(); + + Ok(None) + } + ValTreeCreationError::NonSupportedType | ValTreeCreationError::Other => Ok(None), + } + } + } +} + /// This function should never fail for validated constants. However, it is also invoked from the /// pretty printer which might attempt to format invalid constants and in that case it might fail. pub(crate) fn try_destructure_const<'tcx>( @@ -48,7 +100,6 @@ pub(crate) fn try_destructure_const<'tcx>( trace!("destructure_const: {:?}", val); let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, false); let op = ecx.const_to_op(val, None)?; - // We go to `usize` as we cannot allocate anything bigger anyway. let (field_count, variant, down) = match val.ty().kind() { ty::Array(_, len) => (usize::try_from(len.eval_usize(tcx, param_env)).unwrap(), None, op), @@ -64,7 +115,6 @@ pub(crate) fn try_destructure_const<'tcx>( ty::Tuple(substs) => (substs.len(), None, op), _ => bug!("cannot destructure constant {:?}", val), }; - let fields = (0..field_count) .map(|i| { let field_op = ecx.operand_field(&down, i)?; @@ -73,10 +123,46 @@ pub(crate) fn try_destructure_const<'tcx>( }) .collect::>>()?; let fields = tcx.arena.alloc_from_iter(fields); - Ok(mir::DestructuredConst { variant, fields }) } +#[instrument(skip(tcx), level = "debug")] +pub(crate) fn try_destructure_mir_constant<'tcx>( + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + val: mir::ConstantKind<'tcx>, +) -> InterpResult<'tcx, mir::DestructuredMirConstant<'tcx>> { + trace!("destructure_mir_constant: {:?}", val); + let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, false); + let op = ecx.mir_const_to_op(&val, None)?; + + // We go to `usize` as we cannot allocate anything bigger anyway. + let (field_count, variant, down) = match val.ty().kind() { + ty::Array(_, len) => (len.eval_usize(tcx, param_env) as usize, None, op), + ty::Adt(def, _) if def.variants().is_empty() => { + throw_ub!(Unreachable) + } + ty::Adt(def, _) => { + let variant = ecx.read_discriminant(&op).unwrap().1; + let down = ecx.operand_downcast(&op, variant).unwrap(); + (def.variants()[variant].fields.len(), Some(variant), down) + } + ty::Tuple(substs) => (substs.len(), None, op), + _ => bug!("cannot destructure mir constant {:?}", val), + }; + + let fields_iter = (0..field_count) + .map(|i| { + let field_op = ecx.operand_field(&down, i)?; + let val = op_to_const(&ecx, &field_op); + Ok(mir::ConstantKind::Val(val, field_op.layout.ty)) + }) + .collect::>>()?; + let fields = tcx.arena.alloc_from_iter(fields_iter); + + Ok(mir::DestructuredMirConstant { variant, fields }) +} + #[instrument(skip(tcx), level = "debug")] pub(crate) fn deref_const<'tcx>( tcx: TyCtxt<'tcx>, @@ -113,3 +199,39 @@ pub(crate) fn deref_const<'tcx>( tcx.mk_const(ty::ConstS { val: ty::ConstKind::Value(op_to_const(&ecx, &mplace.into())), ty }) } + +#[instrument(skip(tcx), level = "debug")] +pub(crate) fn deref_mir_constant<'tcx>( + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + val: mir::ConstantKind<'tcx>, +) -> mir::ConstantKind<'tcx> { + let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, false); + let op = ecx.mir_const_to_op(&val, None).unwrap(); + let mplace = ecx.deref_operand(&op).unwrap(); + if let Some(alloc_id) = mplace.ptr.provenance { + assert_eq!( + tcx.get_global_alloc(alloc_id).unwrap().unwrap_memory().0.0.mutability, + Mutability::Not, + "deref_const cannot be used with mutable allocations as \ + that could allow pattern matching to observe mutable statics", + ); + } + + let ty = match mplace.meta { + MemPlaceMeta::None => mplace.layout.ty, + MemPlaceMeta::Poison => bug!("poison metadata in `deref_const`: {:#?}", mplace), + // In case of unsized types, figure out the real type behind. + MemPlaceMeta::Meta(scalar) => match mplace.layout.ty.kind() { + ty::Str => bug!("there's no sized equivalent of a `str`"), + ty::Slice(elem_ty) => tcx.mk_array(*elem_ty, scalar.to_machine_usize(&tcx).unwrap()), + _ => bug!( + "type {} should not have metadata, but had {:?}", + mplace.layout.ty, + mplace.meta + ), + }, + }; + + mir::ConstantKind::Val(op_to_const(&ecx, &mplace.into()), ty) +} diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs index f57f25c19f90f..7346d69bb5de3 100644 --- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs +++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs @@ -1,33 +1,16 @@ use super::eval_queries::{mk_eval_cx, op_to_const}; use super::machine::CompileTimeEvalContext; +use super::{ValTreeCreationError, ValTreeCreationResult, VALTREE_MAX_NODES}; use crate::interpret::{ intern_const_alloc_recursive, ConstValue, ImmTy, Immediate, InternKind, MemPlaceMeta, MemoryKind, PlaceTy, Scalar, ScalarMaybeUninit, }; -use rustc_middle::mir::interpret::ConstAlloc; -use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt}; use rustc_span::source_map::DUMMY_SP; use rustc_target::abi::{Align, VariantIdx}; use crate::interpret::MPlaceTy; use crate::interpret::Value; - -/// Convert an evaluated constant to a type level constant -#[instrument(skip(tcx), level = "debug")] -pub(crate) fn const_to_valtree<'tcx>( - tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - raw: ConstAlloc<'tcx>, -) -> Option> { - let ecx = mk_eval_cx( - tcx, DUMMY_SP, param_env, - // It is absolutely crucial for soundness that - // we do not read from static items or other mutable memory. - false, - ); - let place = ecx.raw_const_to_mplace(raw).unwrap(); - const_to_valtree_inner(&ecx, &place) -} +use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt}; #[instrument(skip(ecx), level = "debug")] fn branches<'tcx>( @@ -35,7 +18,8 @@ fn branches<'tcx>( place: &MPlaceTy<'tcx>, n: usize, variant: Option, -) -> Option> { + num_nodes: &mut usize, +) -> ValTreeCreationResult<'tcx> { let place = match variant { Some(variant) => ecx.mplace_downcast(&place, variant).unwrap(), None => *place, @@ -43,82 +27,116 @@ fn branches<'tcx>( let variant = variant.map(|variant| Some(ty::ValTree::Leaf(ScalarInt::from(variant.as_u32())))); debug!(?place, ?variant); - let fields = (0..n).map(|i| { + let mut fields = Vec::with_capacity(n); + for i in 0..n { let field = ecx.mplace_field(&place, i).unwrap(); - const_to_valtree_inner(ecx, &field) - }); - // For enums, we preped their variant index before the variant's fields so we can figure out + let valtree = const_to_valtree_inner(ecx, &field, num_nodes)?; + fields.push(Some(valtree)); + } + + // For enums, we prepend their variant index before the variant's fields so we can figure out // the variant again when just seeing a valtree. - let branches = variant.into_iter().chain(fields); - Some(ty::ValTree::Branch(ecx.tcx.arena.alloc_from_iter(branches.collect::>>()?))) + let branches = variant + .into_iter() + .chain(fields.into_iter()) + .collect::>>() + .expect("should have already checked for errors in ValTree creation"); + + // Have to account for ZSTs here + if branches.len() == 0 { + *num_nodes += 1; + } + + Ok(ty::ValTree::Branch(ecx.tcx.arena.alloc_from_iter(branches))) } #[instrument(skip(ecx), level = "debug")] fn slice_branches<'tcx>( ecx: &CompileTimeEvalContext<'tcx, 'tcx>, place: &MPlaceTy<'tcx>, -) -> Option> { + num_nodes: &mut usize, +) -> ValTreeCreationResult<'tcx> { let n = place .len(&ecx.tcx.tcx) .unwrap_or_else(|_| panic!("expected to use len of place {:?}", place)); - let branches = (0..n).map(|i| { + + let mut elems = Vec::with_capacity(n as usize); + for i in 0..n { let place_elem = ecx.mplace_index(place, i).unwrap(); - const_to_valtree_inner(ecx, &place_elem) - }); + let valtree = const_to_valtree_inner(ecx, &place_elem, num_nodes)?; + elems.push(valtree); + } - Some(ty::ValTree::Branch(ecx.tcx.arena.alloc_from_iter(branches.collect::>>()?))) + Ok(ty::ValTree::Branch(ecx.tcx.arena.alloc_from_iter(elems))) } #[instrument(skip(ecx), level = "debug")] -fn const_to_valtree_inner<'tcx>( +pub(crate) fn const_to_valtree_inner<'tcx>( ecx: &CompileTimeEvalContext<'tcx, 'tcx>, place: &MPlaceTy<'tcx>, -) -> Option> { - match place.layout.ty.kind() { - ty::FnDef(..) => Some(ty::ValTree::zst()), + num_nodes: &mut usize, +) -> ValTreeCreationResult<'tcx> { + if *num_nodes >= VALTREE_MAX_NODES { + return Err(ValTreeCreationError::NodesOverflow); + } + + let ty = place.layout.ty; + debug!("ty kind: {:?}", ty.kind()); + + match ty.kind() { + ty::FnDef(..) => { + *num_nodes += 1; + Ok(ty::ValTree::zst()) + } ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Char => { - let val = ecx.read_immediate(&place.into()).unwrap(); + let Ok(val) = ecx.read_immediate(&place.into()) else { + return Err(ValTreeCreationError::Other); + }; let val = val.to_scalar().unwrap(); - Some(ty::ValTree::Leaf(val.assert_int())) + *num_nodes += 1; + + Ok(ty::ValTree::Leaf(val.assert_int())) } // Raw pointers are not allowed in type level constants, as we cannot properly test them for // equality at compile-time (see `ptr_guaranteed_eq`/`_ne`). // Technically we could allow function pointers (represented as `ty::Instance`), but this is not guaranteed to // agree with runtime equality tests. - ty::FnPtr(_) | ty::RawPtr(_) => None, + ty::FnPtr(_) | ty::RawPtr(_) => Err(ValTreeCreationError::NonSupportedType), ty::Ref(_, _, _) => { - let derefd_place = ecx.deref_operand(&place.into()).unwrap_or_else(|e| bug!("couldn't deref {:?}, error: {:?}", place, e)); + let Ok(derefd_place)= ecx.deref_operand(&place.into()) else { + return Err(ValTreeCreationError::Other); + }; debug!(?derefd_place); - const_to_valtree_inner(ecx, &derefd_place) + const_to_valtree_inner(ecx, &derefd_place, num_nodes) } ty::Str | ty::Slice(_) | ty::Array(_, _) => { - let valtree = slice_branches(ecx, place); - debug!(?valtree); - - valtree + slice_branches(ecx, place, num_nodes) } // Trait objects are not allowed in type level constants, as we have no concept for // resolving their backing type, even if we can do that at const eval time. We may // hypothetically be able to allow `dyn StructuralEq` trait objects in the future, // but it is unclear if this is useful. - ty::Dynamic(..) => None, + ty::Dynamic(..) => Err(ValTreeCreationError::NonSupportedType), - ty::Tuple(substs) => branches(ecx, place, substs.len(), None), + ty::Tuple(elem_tys) => { + branches(ecx, place, elem_tys.len(), None, num_nodes) + } ty::Adt(def, _) => { if def.is_union() { - return None + return Err(ValTreeCreationError::NonSupportedType); } else if def.variants().is_empty() { bug!("uninhabited types should have errored and never gotten converted to valtree") } - let variant = ecx.read_discriminant(&place.into()).unwrap().1; - - branches(ecx, place, def.variant(variant).fields.len(), def.is_enum().then_some(variant)) + let Ok((_, variant)) = ecx.read_discriminant(&place.into()) else { + return Err(ValTreeCreationError::Other); + }; + branches(ecx, place, def.variant(variant).fields.len(), def.is_enum().then_some(variant), num_nodes) } ty::Never @@ -136,7 +154,7 @@ fn const_to_valtree_inner<'tcx>( // FIXME(oli-obk): we can probably encode closures just like structs | ty::Closure(..) | ty::Generator(..) - | ty::GeneratorWitness(..) => None, + | ty::GeneratorWitness(..) => Err(ValTreeCreationError::NonSupportedType), } } @@ -225,8 +243,11 @@ fn create_pointee_place<'tcx>( .unwrap(); debug!(?ptr); - let mut place = MPlaceTy::from_aligned_ptr(ptr.into(), layout); - place.meta = MemPlaceMeta::Meta(Scalar::from_u64(num_elems as u64)); + let place = MPlaceTy::from_aligned_ptr_with_meta( + ptr.into(), + layout, + MemPlaceMeta::Meta(Scalar::from_u64(num_elems as u64)), + ); debug!(?place); place @@ -237,11 +258,11 @@ fn create_pointee_place<'tcx>( /// Converts a `ValTree` to a `ConstValue`, which is needed after mir /// construction has finished. -// FIXME Merge `valtree_to_const_value` and `fill_place_recursively` into one function +// FIXME Merge `valtree_to_const_value` and `valtree_into_mplace` into one function #[instrument(skip(tcx), level = "debug")] pub fn valtree_to_const_value<'tcx>( tcx: TyCtxt<'tcx>, - param_env_ty: ty::ParamEnvAnd<'tcx, Ty<'tcx>>, + ty: Ty<'tcx>, valtree: ty::ValTree<'tcx>, ) -> ConstValue<'tcx> { // Basic idea: We directly construct `Scalar` values from trivial `ValTree`s @@ -251,8 +272,8 @@ pub fn valtree_to_const_value<'tcx>( // create inner `MPlace`s which are filled recursively. // FIXME Does this need an example? - let (param_env, ty) = param_env_ty.into_parts(); - let mut ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, false); + let mut ecx = mk_eval_cx(tcx, DUMMY_SP, ty::ParamEnv::empty(), false); + let param_env_ty = ty::ParamEnv::empty().and(ty); match ty.kind() { ty::FnDef(..) => { @@ -275,7 +296,7 @@ pub fn valtree_to_const_value<'tcx>( }; debug!(?place); - fill_place_recursively(&mut ecx, &mut place, valtree); + valtree_into_mplace(&mut ecx, &mut place, valtree); dump_place(&ecx, place.into()); intern_const_alloc_recursive(&mut ecx, InternKind::Constant, &place).unwrap(); @@ -317,7 +338,7 @@ pub fn valtree_to_const_value<'tcx>( // FIXME Needs a better/correct name #[instrument(skip(ecx), level = "debug")] -fn fill_place_recursively<'tcx>( +fn valtree_into_mplace<'tcx>( ecx: &mut CompileTimeEvalContext<'tcx, 'tcx>, place: &mut MPlaceTy<'tcx>, valtree: ty::ValTree<'tcx>, @@ -349,7 +370,7 @@ fn fill_place_recursively<'tcx>( let mut pointee_place = create_pointee_place(ecx, *inner_ty, valtree); debug!(?pointee_place); - fill_place_recursively(ecx, &mut pointee_place, valtree); + valtree_into_mplace(ecx, &mut pointee_place, valtree); dump_place(ecx, pointee_place.into()); intern_const_alloc_recursive(ecx, InternKind::Constant, &pointee_place).unwrap(); @@ -437,7 +458,7 @@ fn fill_place_recursively<'tcx>( }; debug!(?place_inner); - fill_place_recursively(ecx, &mut place_inner, *inner_valtree); + valtree_into_mplace(ecx, &mut place_inner, *inner_valtree); dump_place(&ecx, place_inner.into()); } diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs index 92eeafc5df098..520ae409e6b9f 100644 --- a/compiler/rustc_const_eval/src/interpret/cast.rs +++ b/compiler/rustc_const_eval/src/interpret/cast.rs @@ -1,3 +1,4 @@ +use std::assert_matches::assert_matches; use std::convert::TryFrom; use rustc_apfloat::ieee::{Double, Single}; @@ -8,6 +9,7 @@ use rustc_middle::ty::adjustment::PointerCast; use rustc_middle::ty::layout::{IntegerExt, LayoutOf, TyAndLayout}; use rustc_middle::ty::{self, FloatTy, Ty, TypeAndMut}; use rustc_target::abi::{Integer, Variants}; +use rustc_type_ir::sty::TyKind::*; use super::{ util::ensure_monomorphic_enough, FnVal, ImmTy, Immediate, InterpCx, Machine, OpTy, PlaceTy, @@ -29,6 +31,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.unsize_into(src, cast_ty, dest)?; } + PointerExposeAddress => { + let src = self.read_immediate(src)?; + let res = self.pointer_expose_address_cast(&src, cast_ty)?; + self.write_immediate(res, dest)?; + } + Misc => { let src = self.read_immediate(src)?; let res = self.misc_cast(&src, cast_ty)?; @@ -102,7 +110,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { src: &ImmTy<'tcx, M::PointerTag>, cast_ty: Ty<'tcx>, ) -> InterpResult<'tcx, Immediate> { - use rustc_middle::ty::TyKind::*; + use rustc_type_ir::sty::TyKind::*; trace!("Casting {:?}: {:?} to {:?}", *src, src.layout.ty, cast_ty); match src.layout.ty.kind() { @@ -173,23 +181,23 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // # The remaining source values are scalar and "int-like". let scalar = src.to_scalar()?; + Ok(self.cast_from_int_like(scalar, src.layout, cast_ty)?.into()) + } - // If we are casting from a pointer to something - // that is not a pointer, mark the pointer as exposed - if src.layout.ty.is_any_ptr() && !cast_ty.is_any_ptr() { - let ptr = self.scalar_to_ptr(scalar)?; - - match ptr.into_pointer_or_addr() { - Ok(ptr) => { - M::expose_ptr(self, ptr)?; - } - Err(_) => { - // do nothing, exposing an invalid pointer - // has no meaning - } - }; - } + pub fn pointer_expose_address_cast( + &mut self, + src: &ImmTy<'tcx, M::PointerTag>, + cast_ty: Ty<'tcx>, + ) -> InterpResult<'tcx, Immediate> { + assert_matches!(src.layout.ty.kind(), ty::RawPtr(_) | ty::FnPtr(_)); + assert!(cast_ty.is_integral()); + let scalar = src.to_scalar()?; + let ptr = self.scalar_to_ptr(scalar)?; + match ptr.into_pointer_or_addr() { + Ok(ptr) => M::expose_ptr(self, ptr)?, + Err(_) => {} // do nothing, exposing an invalid pointer has no meaning + }; Ok(self.cast_from_int_like(scalar, src.layout, cast_ty)?.into()) } @@ -205,7 +213,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let v = scalar.to_bits(src_layout.size)?; let v = if signed { self.sign_extend(v, src_layout) } else { v }; trace!("cast_from_scalar: {}, {} -> {}", v, src_layout.ty, cast_ty); - use rustc_middle::ty::TyKind::*; Ok(match *cast_ty.kind() { Int(_) | Uint(_) => { @@ -225,9 +232,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let addr = u64::try_from(size.truncate(v)).unwrap(); let ptr = M::ptr_from_addr_cast(&self, addr); - if addr == 0 { - assert!(ptr.provenance.is_none(), "null pointer can never have an AllocId"); - } Scalar::from_maybe_pointer(ptr, self) } @@ -250,7 +254,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { where F: Float + Into> + FloatConvert + FloatConvert, { - use rustc_middle::ty::TyKind::*; + use rustc_type_ir::sty::TyKind::*; match *dest_ty.kind() { // float -> uint Uint(t) => { diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index dfb81a2afc4f7..0c954ac6e5f6e 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -105,7 +105,7 @@ pub struct Frame<'mir, 'tcx, Tag: Provenance = AllocId, Extra = ()> { /// The location where the result of the current stack frame should be written to, /// and its layout in the caller. - pub return_place: Option>, + pub return_place: PlaceTy<'tcx, Tag>, /// The list of locals for this stack frame, stored in order as /// `[return_ptr, arguments..., variables..., temporaries...]`. @@ -520,13 +520,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { frame .instance .try_subst_mir_and_normalize_erasing_regions(*self.tcx, self.param_env, value) - .or_else(|e| { + .map_err(|e| { self.tcx.sess.delay_span_bug( self.cur_span(), format!("failed to normalize {}", e.get_type_for_failure()).as_str(), ); - Err(InterpError::InvalidProgram(InvalidProgramInfo::TooGeneric)) + InterpError::InvalidProgram(InvalidProgramInfo::TooGeneric) }) } @@ -676,7 +676,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { &mut self, instance: ty::Instance<'tcx>, body: &'mir mir::Body<'tcx>, - return_place: Option<&PlaceTy<'tcx, M::PointerTag>>, + return_place: &PlaceTy<'tcx, M::PointerTag>, return_to_block: StackPopCleanup, ) -> InterpResult<'tcx> { trace!("body: {:#?}", body); @@ -685,7 +685,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { body, loc: Err(body.span), // Span used for errors caused during preamble. return_to_block, - return_place: return_place.copied(), + return_place: *return_place, // empty local array, we fill it in below, after we are inside the stack frame and // all methods actually know about the frame locals: IndexVec::new(), @@ -807,14 +807,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.stack_mut().pop().expect("tried to pop a stack frame, but there were none"); if !unwinding { - // Copy the return value to the caller's stack frame. - if let Some(ref return_place) = frame.return_place { - let op = self.access_local(&frame, mir::RETURN_PLACE, None)?; - self.copy_op_transmute(&op, return_place)?; - trace!("{:?}", self.dump_place(**return_place)); - } else { - throw_ub!(Unreachable); - } + let op = self.access_local(&frame, mir::RETURN_PLACE, None)?; + self.copy_op_transmute(&op, &frame.return_place)?; + trace!("{:?}", self.dump_place(*frame.return_place)); } let return_to_block = frame.return_to_block; @@ -1014,11 +1009,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> std::fmt::Debug } } - write!( - fmt, - ": {:?}", - self.ecx.dump_allocs(allocs.into_iter().filter_map(|x| x).collect()) - ) + write!(fmt, ": {:?}", self.ecx.dump_allocs(allocs.into_iter().flatten().collect())) } Place::Ptr(mplace) => match mplace.ptr.provenance.and_then(Provenance::get_alloc_id) { Some(alloc_id) => write!( @@ -1055,7 +1046,7 @@ where body.hash_stable(hcx, hasher); instance.hash_stable(hcx, hasher); return_to_block.hash_stable(hcx, hasher); - return_place.as_ref().map(|r| &**r).hash_stable(hcx, hasher); + return_place.hash_stable(hcx, hasher); locals.hash_stable(hcx, hasher); loc.hash_stable(hcx, hasher); extra.hash_stable(hcx, hasher); diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index 59ea40dc2f94e..bf1cf816ddd0b 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -15,7 +15,7 @@ use rustc_middle::ty::layout::LayoutOf as _; use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::{Ty, TyCtxt}; use rustc_span::symbol::{sym, Symbol}; -use rustc_target::abi::{Abi, Align, Primitive, Size}; +use rustc_target::abi::{Abi, Align, InitKind, Primitive, Size}; use super::{ util::ensure_monomorphic_enough, CheckInAllocMsg, ImmTy, InterpCx, Machine, OpTy, PlaceTy, @@ -44,7 +44,7 @@ fn numeric_intrinsic(name: Symbol, bits: u128, kind: Primitive) -> Scalar( +pub(crate) fn eval_nullary_intrinsic<'tcx>( tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, def_id: DefId, @@ -115,13 +115,14 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { &mut self, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx, M::PointerTag>], - ret: Option<(&PlaceTy<'tcx, M::PointerTag>, mir::BasicBlock)>, + dest: &PlaceTy<'tcx, M::PointerTag>, + ret: Option, ) -> InterpResult<'tcx, bool> { let substs = instance.substs; let intrinsic_name = self.tcx.item_name(instance.def_id()); // First handle intrinsics without return place. - let (dest, ret) = match ret { + let ret = match ret { None => match intrinsic_name { sym::transmute => throw_ub_format!("transmuting to uninhabited type"), sym::abort => M::abort(self, "the program aborted execution".to_owned())?, @@ -407,7 +408,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { )?; } if intrinsic_name == sym::assert_zero_valid - && !layout.might_permit_raw_init(self, /*zero:*/ true) + && !layout.might_permit_raw_init( + self, + InitKind::Zero, + self.tcx.sess.opts.debugging_opts.strict_init_checks, + ) { M::abort( self, @@ -418,7 +423,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { )?; } if intrinsic_name == sym::assert_uninit_valid - && !layout.might_permit_raw_init(self, /*zero:*/ false) + && !layout.might_permit_raw_init( + self, + InitKind::Uninit, + self.tcx.sess.opts.debugging_opts.strict_init_checks, + ) { M::abort( self, diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs b/compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs index 5ece19d7fb3d3..e66cb9837c999 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs @@ -15,7 +15,7 @@ use crate::interpret::{ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// Walks up the callstack from the intrinsic's callsite, searching for the first callsite in a /// frame which is not `#[track_caller]`. - crate fn find_closest_untracked_caller_location(&self) -> Span { + pub(crate) fn find_closest_untracked_caller_location(&self) -> Span { for frame in self.stack().iter().rev() { debug!("find_closest_untracked_caller_location: checking frame {:?}", frame.instance); @@ -74,7 +74,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } /// Allocate a `const core::panic::Location` with the provided filename and line/column numbers. - crate fn alloc_caller_location( + pub(crate) fn alloc_caller_location( &mut self, filename: Symbol, line: u32, @@ -113,7 +113,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { location } - crate fn location_triple_for_span(&self, span: Span) -> (Symbol, u32, u32) { + pub(crate) fn location_triple_for_span(&self, span: Span) -> (Symbol, u32, u32) { let topmost = span.ctxt().outer_expn().expansion_cause().unwrap_or(span); let caller = self.tcx.sess.source_map().lookup_char_pos(topmost.lo()); ( diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics/type_name.rs b/compiler/rustc_const_eval/src/interpret/intrinsics/type_name.rs index 447797f915caf..f9847742f0883 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics/type_name.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics/type_name.rs @@ -189,7 +189,7 @@ impl Write for AbsolutePathPrinter<'_> { } /// Directly returns an `Allocation` containing an absolute path representation of the given type. -crate fn alloc_type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> ConstAllocation<'tcx> { +pub(crate) fn alloc_type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> ConstAllocation<'tcx> { let path = AbsolutePathPrinter { tcx, path: String::new() }.print_type(ty).unwrap().path; let alloc = Allocation::from_bytes_byte_aligned_immutable(path.into_bytes()); tcx.intern_const_alloc(alloc) diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs index a79751ccb55b4..3572a9cc68174 100644 --- a/compiler/rustc_const_eval/src/interpret/machine.rs +++ b/compiler/rustc_const_eval/src/interpret/machine.rs @@ -133,9 +133,11 @@ pub trait Machine<'mir, 'tcx>: Sized { /// Whether to enforce the validity invariant fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool; - /// Whether to enforce validity (e.g., initialization and not having ptr provenance) - /// of integers and floats. - fn enforce_number_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool; + /// Whether to enforce integers and floats being initialized. + fn enforce_number_init(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool; + + /// Whether to enforce integers and floats not having provenance. + fn enforce_number_no_provenance(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool; /// Whether function calls should be [ABI](Abi)-checked. fn enforce_abi(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool { @@ -167,7 +169,8 @@ pub trait Machine<'mir, 'tcx>: Sized { instance: ty::Instance<'tcx>, abi: Abi, args: &[OpTy<'tcx, Self::PointerTag>], - ret: Option<(&PlaceTy<'tcx, Self::PointerTag>, mir::BasicBlock)>, + destination: &PlaceTy<'tcx, Self::PointerTag>, + target: Option, unwind: StackPopUnwind, ) -> InterpResult<'tcx, Option<(&'mir mir::Body<'tcx>, ty::Instance<'tcx>)>>; @@ -178,7 +181,8 @@ pub trait Machine<'mir, 'tcx>: Sized { fn_val: Self::ExtraFnVal, abi: Abi, args: &[OpTy<'tcx, Self::PointerTag>], - ret: Option<(&PlaceTy<'tcx, Self::PointerTag>, mir::BasicBlock)>, + destination: &PlaceTy<'tcx, Self::PointerTag>, + target: Option, unwind: StackPopUnwind, ) -> InterpResult<'tcx>; @@ -188,7 +192,8 @@ pub trait Machine<'mir, 'tcx>: Sized { ecx: &mut InterpCx<'mir, 'tcx, Self>, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx, Self::PointerTag>], - ret: Option<(&PlaceTy<'tcx, Self::PointerTag>, mir::BasicBlock)>, + destination: &PlaceTy<'tcx, Self::PointerTag>, + target: Option, unwind: StackPopUnwind, ) -> InterpResult<'tcx>; @@ -453,7 +458,12 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) { } #[inline(always)] - fn enforce_number_validity(_ecx: &InterpCx<$mir, $tcx, Self>) -> bool { + fn enforce_number_init(_ecx: &InterpCx<$mir, $tcx, Self>) -> bool { + true + } + + #[inline(always)] + fn enforce_number_no_provenance(_ecx: &InterpCx<$mir, $tcx, Self>) -> bool { true } @@ -463,7 +473,8 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) { fn_val: !, _abi: Abi, _args: &[OpTy<$tcx>], - _ret: Option<(&PlaceTy<$tcx>, mir::BasicBlock)>, + _destination: &PlaceTy<$tcx, Self::PointerTag>, + _target: Option, _unwind: StackPopUnwind, ) -> InterpResult<$tcx> { match fn_val {} diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index 33162a01ed201..9c032c55fe544 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -197,7 +197,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { size: Size, align: Align, kind: MemoryKind, - ) -> InterpResult<'static, Pointer> { + ) -> InterpResult<'tcx, Pointer> { let alloc = Allocation::uninit(size, align, M::PANIC_ON_ALLOC_FAIL)?; Ok(self.allocate_raw_ptr(alloc, kind)) } @@ -402,7 +402,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { msg: CheckInAllocMsg, alloc_size: impl FnOnce(AllocId, Size, M::TagExtra) -> InterpResult<'tcx, (Size, Align, T)>, ) -> InterpResult<'tcx, Option> { - fn check_offset_align(offset: u64, align: Align) -> InterpResult<'static> { + fn check_offset_align<'tcx>(offset: u64, align: Align) -> InterpResult<'tcx> { if offset % align.bytes() == 0 { Ok(()) } else { @@ -441,6 +441,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { msg, }) } + // Ensure we never consider the null pointer dereferencable. + if M::PointerTag::OFFSET_IS_ADDR { + assert_ne!(ptr.addr(), Size::ZERO); + } // Test align. Check this last; if both bounds and alignment are violated // we want the error to be about the bounds. if let Some(align) = align { @@ -654,7 +658,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { &self, id: AllocId, liveness: AllocCheck, - ) -> InterpResult<'static, (Size, Align)> { + ) -> InterpResult<'tcx, (Size, Align)> { // # Regular allocations // Don't use `self.get_raw` here as that will // a) cause cycles in case `id` refers to a static @@ -924,10 +928,15 @@ impl<'tcx, 'a, Tag: Provenance, Extra> AllocRef<'a, 'tcx, Tag, Extra> { self.read_scalar(alloc_range(offset, self.tcx.data_layout().pointer_size)) } - pub fn check_bytes(&self, range: AllocRange, allow_uninit_and_ptr: bool) -> InterpResult<'tcx> { + pub fn check_bytes( + &self, + range: AllocRange, + allow_uninit: bool, + allow_ptr: bool, + ) -> InterpResult<'tcx> { Ok(self .alloc - .check_bytes(&self.tcx, self.range.subrange(range), allow_uninit_and_ptr) + .check_bytes(&self.tcx, self.range.subrange(range), allow_uninit, allow_ptr) .map_err(|e| e.to_interp_error(self.alloc_id))?) } } @@ -1144,11 +1153,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Err(ptr) => ptr.into(), Ok(bits) => { let addr = u64::try_from(bits).unwrap(); - let ptr = M::ptr_from_addr_transmute(&self, addr); - if addr == 0 { - assert!(ptr.provenance.is_none(), "null pointer can never have an AllocId"); - } - ptr + M::ptr_from_addr_transmute(&self, addr) } }, ) diff --git a/compiler/rustc_const_eval/src/interpret/mod.rs b/compiler/rustc_const_eval/src/interpret/mod.rs index 69d6c8470a273..2b73ad568e0ee 100644 --- a/compiler/rustc_const_eval/src/interpret/mod.rs +++ b/compiler/rustc_const_eval/src/interpret/mod.rs @@ -29,5 +29,5 @@ pub use self::place::{MPlaceTy, MemPlace, MemPlaceMeta, Place, PlaceTy}; pub use self::validity::{CtfeValidationMode, RefTracking}; pub use self::visitor::{MutValueVisitor, Value, ValueVisitor}; -crate use self::intrinsics::eval_nullary_intrinsic; +pub(crate) use self::intrinsics::eval_nullary_intrinsic; use eval_context::{from_known_layout, mir_assign_valid_types}; diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs index 5c85c86107fea..f5e1ee4e23315 100644 --- a/compiler/rustc_const_eval/src/interpret/operand.rs +++ b/compiler/rustc_const_eval/src/interpret/operand.rs @@ -643,7 +643,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } } - crate fn const_val_to_op( + pub(crate) fn const_val_to_op( &self, val_val: ConstValue<'tcx>, ty: Ty<'tcx>, diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index 95d6f431391fc..955480a1a7411 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -115,12 +115,6 @@ impl<'tcx, Tag: Provenance> std::ops::Deref for MPlaceTy<'tcx, Tag> { } } -impl<'tcx, Tag: Provenance> std::ops::DerefMut for MPlaceTy<'tcx, Tag> { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.mplace - } -} - impl<'tcx, Tag: Provenance> From> for PlaceTy<'tcx, Tag> { #[inline(always)] fn from(mplace: MPlaceTy<'tcx, Tag>) -> Self { @@ -196,6 +190,18 @@ impl<'tcx, Tag: Provenance> MPlaceTy<'tcx, Tag> { MPlaceTy { mplace: MemPlace::from_ptr(ptr, layout.align.abi), layout } } + #[inline] + pub fn from_aligned_ptr_with_meta( + ptr: Pointer>, + layout: TyAndLayout<'tcx>, + meta: MemPlaceMeta, + ) -> Self { + let mut mplace = MemPlace::from_ptr(ptr, layout.align.abi); + mplace.meta = meta; + + MPlaceTy { mplace, layout } + } + #[inline] pub(crate) fn len(&self, cx: &impl HasDataLayout) -> InterpResult<'tcx, u64> { if self.layout.is_unsized() { @@ -495,7 +501,7 @@ where /// Project into an mplace #[instrument(skip(self), level = "debug")] - pub(crate) fn mplace_projection( + pub(super) fn mplace_projection( &self, base: &MPlaceTy<'tcx, M::PointerTag>, proj_elem: mir::PlaceElem<'tcx>, @@ -900,16 +906,12 @@ where } // We still require the sizes to match. if src.layout.size != dest.layout.size { - // FIXME: This should be an assert instead of an error, but if we transmute within an - // array length computation, `typeck` may not have yet been run and errored out. In fact - // most likely we *are* running `typeck` right now. Investigate whether we can bail out - // on `typeck_results().has_errors` at all const eval entry points. - debug!("Size mismatch when transmuting!\nsrc: {:#?}\ndest: {:#?}", src, dest); - self.tcx.sess.delay_span_bug( + span_bug!( self.cur_span(), - "size-changing transmute, should have been caught by transmute checking", + "size-changing transmute, should have been caught by transmute checking: {:#?}\ndest: {:#?}", + src, + dest ); - throw_inval!(TransmuteSizeDiff(src.layout.ty, dest.layout.ty)); } // Unsized copies rely on interpreting `src.meta` with `dest.layout`, we want // to avoid that here. @@ -1005,7 +1007,7 @@ where &mut self, layout: TyAndLayout<'tcx>, kind: MemoryKind, - ) -> InterpResult<'static, MPlaceTy<'tcx, M::PointerTag>> { + ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { let ptr = self.allocate_ptr(layout.size, layout.align.abi, kind)?; Ok(MPlaceTy::from_aligned_ptr(ptr.into(), layout)) } diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs index c2664565f15cb..10da2f803afe7 100644 --- a/compiler/rustc_const_eval/src/interpret/terminator.rs +++ b/compiler/rustc_const_eval/src/interpret/terminator.rs @@ -57,7 +57,15 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.go_to_block(target_block); } - Call { ref func, ref args, destination, ref cleanup, from_hir_call: _, fn_span: _ } => { + Call { + ref func, + ref args, + destination, + target, + ref cleanup, + from_hir_call: _, + fn_span: _, + } => { let old_stack = self.frame_idx(); let old_loc = self.frame().loc; let func = self.eval_operand(func, None)?; @@ -91,20 +99,14 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ), }; - let dest_place; - let ret = match destination { - Some((dest, ret)) => { - dest_place = self.eval_place(dest)?; - Some((&dest_place, ret)) - } - None => None, - }; + let destination = self.eval_place(destination)?; self.eval_fn_call( fn_val, (fn_sig.abi, fn_abi), &args, with_caller_location, - ret, + &destination, + target, match (cleanup, fn_abi.can_unwind) { (Some(cleanup), true) => StackPopUnwind::Cleanup(*cleanup), (None, true) => StackPopUnwind::Skip, @@ -183,7 +185,14 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // No question return true; } - // Compare layout + if caller_abi.layout.size != callee_abi.layout.size + || caller_abi.layout.align.abi != callee_abi.layout.align.abi + { + // This cannot go well... + // FIXME: What about unsized types? + return false; + } + // The rest *should* be okay, but we are extra conservative. match (caller_abi.layout.abi, callee_abi.layout.abi) { // Different valid ranges are okay (once we enforce validity, // that will take care to make it UB to leave the range, just @@ -299,7 +308,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { (caller_abi, caller_fn_abi): (Abi, &FnAbi<'tcx, Ty<'tcx>>), args: &[OpTy<'tcx, M::PointerTag>], with_caller_location: bool, - ret: Option<(&PlaceTy<'tcx, M::PointerTag>, mir::BasicBlock)>, + destination: &PlaceTy<'tcx, M::PointerTag>, + target: Option, mut unwind: StackPopUnwind, ) -> InterpResult<'tcx> { trace!("eval_fn_call: {:#?}", fn_val); @@ -307,15 +317,23 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let instance = match fn_val { FnVal::Instance(instance) => instance, FnVal::Other(extra) => { - return M::call_extra_fn(self, extra, caller_abi, args, ret, unwind); + return M::call_extra_fn( + self, + extra, + caller_abi, + args, + destination, + target, + unwind, + ); } }; match instance.def { - ty::InstanceDef::Intrinsic(..) => { - assert!(caller_abi == Abi::RustIntrinsic || caller_abi == Abi::PlatformIntrinsic); + ty::InstanceDef::Intrinsic(def_id) => { + assert!(self.tcx.is_intrinsic(def_id)); // caller_fn_abi is not relevant here, we interpret the arguments directly for each intrinsic. - M::call_intrinsic(self, instance, args, ret, unwind) + M::call_intrinsic(self, instance, args, destination, target, unwind) } ty::InstanceDef::VtableShim(..) | ty::InstanceDef::ReifyShim(..) @@ -326,7 +344,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { | ty::InstanceDef::Item(_) => { // We need MIR for this fn let Some((body, instance)) = - M::find_mir_or_eval_fn(self, instance, caller_abi, args, ret, unwind)? else { + M::find_mir_or_eval_fn(self, instance, caller_abi, args, destination, target, unwind)? else { return Ok(()); }; @@ -362,8 +380,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.push_stack_frame( instance, body, - ret.map(|p| p.0), - StackPopCleanup::Goto { ret: ret.map(|p| p.1), unwind }, + destination, + StackPopCleanup::Goto { ret: target, unwind }, )?; // If an error is raised here, pop the frame again to get an accurate backtrace. @@ -540,7 +558,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { (caller_abi, caller_fn_abi), &args, with_caller_location, - ret, + destination, + target, unwind, ) } @@ -582,7 +601,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { (Abi::Rust, fn_abi), &[arg.into()], false, - Some((&dest.into(), target)), + &dest.into(), + Some(target), match unwind { Some(cleanup) => StackPopUnwind::Cleanup(cleanup), None => StackPopUnwind::Skip, diff --git a/compiler/rustc_const_eval/src/interpret/traits.rs b/compiler/rustc_const_eval/src/interpret/traits.rs index 235938422a893..c4d1074e4379c 100644 --- a/compiler/rustc_const_eval/src/interpret/traits.rs +++ b/compiler/rustc_const_eval/src/interpret/traits.rs @@ -2,8 +2,8 @@ use std::convert::TryFrom; use rustc_middle::mir::interpret::{InterpResult, Pointer, PointerArithmetic}; use rustc_middle::ty::{ - self, Ty, COMMON_VTABLE_ENTRIES, COMMON_VTABLE_ENTRIES_ALIGN, - COMMON_VTABLE_ENTRIES_DROPINPLACE, COMMON_VTABLE_ENTRIES_SIZE, + self, Ty, TyCtxt, COMMON_VTABLE_ENTRIES_ALIGN, COMMON_VTABLE_ENTRIES_DROPINPLACE, + COMMON_VTABLE_ENTRIES_SIZE, }; use rustc_target::abi::{Align, Size}; @@ -38,7 +38,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } /// Resolves the function at the specified slot in the provided - /// vtable. Currently an index of '3' (`COMMON_VTABLE_ENTRIES.len()`) + /// vtable. Currently an index of '3' (`TyCtxt::COMMON_VTABLE_ENTRIES.len()`) /// corresponds to the first method declared in the trait of the provided vtable. pub fn get_vtable_slot( &self, @@ -64,7 +64,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let vtable = self .get_ptr_alloc( vtable, - pointer_size * u64::try_from(COMMON_VTABLE_ENTRIES.len()).unwrap(), + pointer_size * u64::try_from(TyCtxt::COMMON_VTABLE_ENTRIES.len()).unwrap(), self.tcx.data_layout.pointer_align.abi, )? .expect("cannot be a ZST"); @@ -99,7 +99,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let vtable = self .get_ptr_alloc( vtable, - pointer_size * u64::try_from(COMMON_VTABLE_ENTRIES.len()).unwrap(), + pointer_size * u64::try_from(TyCtxt::COMMON_VTABLE_ENTRIES.len()).unwrap(), self.tcx.data_layout.pointer_align.abi, )? .expect("cannot be a ZST"); diff --git a/compiler/rustc_const_eval/src/interpret/util.rs b/compiler/rustc_const_eval/src/interpret/util.rs index e17bd9a8c0899..1940b573db0d6 100644 --- a/compiler/rustc_const_eval/src/interpret/util.rs +++ b/compiler/rustc_const_eval/src/interpret/util.rs @@ -8,7 +8,7 @@ use std::ops::ControlFlow; /// In case it does, returns a `TooGeneric` const eval error. Note that due to polymorphization /// types may be "concrete enough" even though they still contain generic parameters in /// case these parameters are unused. -crate fn ensure_monomorphic_enough<'tcx, T>(tcx: TyCtxt<'tcx>, ty: T) -> InterpResult<'tcx> +pub(crate) fn ensure_monomorphic_enough<'tcx, T>(tcx: TyCtxt<'tcx>, ty: T) -> InterpResult<'tcx> where T: TypeFoldable<'tcx>, { diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index 2dab9ff89868f..b39a33aff097e 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -412,22 +412,27 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' self.path, err_ub!(AlignmentCheckFailed { required, has }) => { - "an unaligned {} (required {} byte alignment but found {})", - kind, + "an unaligned {kind} (required {} byte alignment but found {})", required.bytes(), has.bytes() }, err_ub!(DanglingIntPointer(0, _)) => - { "a null {}", kind }, + { "a null {kind}" }, err_ub!(DanglingIntPointer(i, _)) => - { "a dangling {} (address 0x{:x} is unallocated)", kind, i }, + { "a dangling {kind} (address 0x{i:x} is unallocated)" }, err_ub!(PointerOutOfBounds { .. }) => - { "a dangling {} (going beyond the bounds of its allocation)", kind }, + { "a dangling {kind} (going beyond the bounds of its allocation)" }, // This cannot happen during const-eval (because interning already detects // dangling pointers), but it can happen in Miri. err_ub!(PointerUseAfterFree(..)) => - { "a dangling {} (use-after-free)", kind }, + { "a dangling {kind} (use-after-free)" }, ); + // Do not allow pointers to uninhabited types. + if place.layout.abi.is_uninhabited() { + throw_validation_failure!(self.path, + { "a {kind} pointing to uninhabited type {}", place.layout.ty } + ) + } // Recursive checking if let Some(ref mut ref_tracking) = self.ref_tracking { // Proceed recursively even for ZST, no reason to skip them! @@ -531,15 +536,21 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' let value = self.read_scalar(value)?; // NOTE: Keep this in sync with the array optimization for int/float // types below! - if M::enforce_number_validity(self.ecx) { - // Integers/floats with number validity: Must be scalar bits, pointers are dangerous. + if M::enforce_number_init(self.ecx) { + try_validation!( + value.check_init(), + self.path, + err_ub!(InvalidUninitBytes(..)) => + { "{:x}", value } expected { "initialized bytes" } + ); + } + if M::enforce_number_no_provenance(self.ecx) { // As a special exception we *do* match on a `Scalar` here, since we truly want // to know its underlying representation (and *not* cast it to an integer). - let is_bits = - value.check_init().map_or(false, |v| matches!(v, Scalar::Int(..))); - if !is_bits { + let is_ptr = value.check_init().map_or(false, |v| matches!(v, Scalar::Ptr(..))); + if is_ptr { throw_validation_failure!(self.path, - { "{:x}", value } expected { "initialized plain (non-pointer) bytes" } + { "{:x}", value } expected { "plain (non-pointer) bytes" } ) } } @@ -646,7 +657,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' let size = scalar_layout.size(self.ecx); let is_full_range = match scalar_layout { ScalarAbi::Initialized { .. } => { - if M::enforce_number_validity(self.ecx) { + if M::enforce_number_init(self.ecx) { false // not "full" since uninit is not accepted } else { scalar_layout.is_always_valid(self.ecx) @@ -905,10 +916,10 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> return Ok(()); }; - let allow_uninit_and_ptr = !M::enforce_number_validity(self.ecx); match alloc.check_bytes( alloc_range(Size::ZERO, size), - allow_uninit_and_ptr, + /*allow_uninit*/ !M::enforce_number_init(self.ecx), + /*allow_ptr*/ !M::enforce_number_no_provenance(self.ecx), ) { // In the happy case, we needn't check anything else. Ok(()) => {} diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs index 1ab461a942129..d2b5ef8ea6fa6 100644 --- a/compiler/rustc_const_eval/src/lib.rs +++ b/compiler/rustc_const_eval/src/lib.rs @@ -7,9 +7,9 @@ Rust MIR: a lowered representation of Rust. #![feature(assert_matches)] #![feature(box_patterns)] #![feature(control_flow_enum)] -#![feature(crate_visibility_modifier)] #![feature(decl_macro)] #![feature(exact_size_is_empty)] +#![feature(let_chains)] #![feature(let_else)] #![feature(map_try_insert)] #![feature(min_specialization)] @@ -34,26 +34,32 @@ pub mod transform; pub mod util; use rustc_middle::ty::query::Providers; -use rustc_middle::ty::ParamEnv; pub fn provide(providers: &mut Providers) { const_eval::provide(providers); providers.eval_to_const_value_raw = const_eval::eval_to_const_value_raw_provider; providers.eval_to_allocation_raw = const_eval::eval_to_allocation_raw_provider; providers.const_caller_location = const_eval::const_caller_location; - providers.try_destructure_const = |tcx, param_env_and_value| { - let (param_env, value) = param_env_and_value.into_parts(); - const_eval::try_destructure_const(tcx, param_env, value).ok() + providers.try_destructure_const = |tcx, param_env_and_val| { + let (param_env, c) = param_env_and_val.into_parts(); + const_eval::try_destructure_const(tcx, param_env, c).ok() }; - providers.const_to_valtree = |tcx, param_env_and_value| { + providers.eval_to_valtree = |tcx, param_env_and_value| { let (param_env, raw) = param_env_and_value.into_parts(); - const_eval::const_to_valtree(tcx, param_env, raw) + const_eval::eval_to_valtree(tcx, param_env, raw) }; - providers.valtree_to_const_val = |tcx, (ty, valtree)| { - const_eval::valtree_to_const_value(tcx, ParamEnv::empty().and(ty), valtree) + providers.try_destructure_mir_constant = |tcx, param_env_and_value| { + let (param_env, value) = param_env_and_value.into_parts(); + const_eval::try_destructure_mir_constant(tcx, param_env, value).ok() }; + providers.valtree_to_const_val = + |tcx, (ty, valtree)| const_eval::valtree_to_const_value(tcx, ty, valtree); providers.deref_const = |tcx, param_env_and_value| { let (param_env, value) = param_env_and_value.into_parts(); const_eval::deref_const(tcx, param_env, value) }; + providers.deref_mir_constant = |tcx, param_env_and_value| { + let (param_env, value) = param_env_and_value.into_parts(); + const_eval::deref_mir_constant(tcx, param_env, value) + }; } 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 8d3bbefb37186..c07680515f4e7 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -8,7 +8,6 @@ use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::traits::{ImplSource, Obligation, ObligationCause}; use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::*; -use rustc_middle::ty::cast::CastTy; use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts}; use rustc_middle::ty::{self, adjustment::PointerCast, Instance, InstanceDef, Ty, TyCtxt}; use rustc_middle::ty::{Binder, TraitPredicate, TraitRef, TypeFoldable}; @@ -229,18 +228,6 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> { // The local type and predicate checks are not free and only relevant for `const fn`s. if self.const_kind() == hir::ConstContext::ConstFn { - // Prevent const trait methods from being annotated as `stable`. - // FIXME: Do this as part of stability checking. - if self.is_const_stable_const_fn() { - if crate::const_eval::is_parent_const_impl_raw(tcx, def_id) { - self.ccx - .tcx - .sess - .struct_span_err(self.span, "trait methods cannot be stable const fn") - .emit(); - } - } - for (idx, local) in body.local_decls.iter_enumerated() { // Handle the return place below. if idx == RETURN_PLACE || local.internal { @@ -555,16 +542,12 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { // in the type of any local, which also excludes casts). } - Rvalue::Cast(CastKind::Misc, ref operand, cast_ty) => { - let operand_ty = operand.ty(self.body, self.tcx); - let cast_in = CastTy::from_ty(operand_ty).expect("bad input type for cast"); - let cast_out = CastTy::from_ty(cast_ty).expect("bad output type for cast"); - - if let (CastTy::Ptr(_) | CastTy::FnPtr, CastTy::Int(_)) = (cast_in, cast_out) { - self.check_op(ops::RawPtrToIntCast); - } + Rvalue::Cast(CastKind::PointerExposeAddress, _, _) => { + self.check_op(ops::RawPtrToIntCast); } + Rvalue::Cast(CastKind::Misc, _, _) => {} + Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _) => {} Rvalue::ShallowInitBox(_, _) => {} @@ -702,8 +685,6 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { #[instrument(level = "debug", skip(self))] fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { - use rustc_target::spec::abi::Abi::RustIntrinsic; - self.super_terminator(terminator, location); match &terminator.kind { @@ -725,8 +706,6 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { } }; - let mut nonconst_call_permission = false; - // Attempting to call a trait method? if let Some(trait_id) = tcx.trait_of_item(callee) { trace!("attempting to call a trait method"); @@ -788,13 +767,12 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { } } _ if !tcx.is_const_fn_raw(callee) => { - // At this point, it is only legal when the caller is marked with - // #[default_method_body_is_const], and the callee is in the same - // trait. - let callee_trait = tcx.trait_of_item(callee); - if callee_trait.is_some() - && tcx.has_attr(caller.to_def_id(), sym::default_method_body_is_const) - && callee_trait == tcx.trait_of_item(caller) + // At this point, it is only legal when the caller is in a trait + // marked with #[const_trait], and the callee is in the same trait. + let mut nonconst_call_permission = false; + if let Some(callee_trait) = tcx.trait_of_item(callee) + && tcx.has_attr(callee_trait, sym::const_trait) + && Some(callee_trait) == tcx.trait_of_item(caller) // Can only call methods when it's `::f`. && tcx.types.self_param == substs.type_at(0) { @@ -885,19 +863,13 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { return; } - let is_intrinsic = tcx.fn_sig(callee).abi() == RustIntrinsic; + let is_intrinsic = tcx.is_intrinsic(callee); if !tcx.is_const_fn_raw(callee) { - if tcx.trait_of_item(callee).is_some() { - if tcx.has_attr(callee, sym::default_method_body_is_const) { - // To get to here we must have already found a const impl for the - // trait, but for it to still be non-const can be that the impl is - // using default method bodies. - nonconst_call_permission = true; - } - } - - if !nonconst_call_permission { + if !tcx.is_const_default_method(callee) { + // To get to here we must have already found a const impl for the + // trait, but for it to still be non-const can be that the impl is + // using default method bodies. self.check_op(ops::FnCallNonConst { caller, callee, @@ -946,7 +918,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { // have no `rustc_const_stable` attributes to be const-unstable as well. This // should be fixed later. let callee_is_unstable_unmarked = tcx.lookup_const_stability(callee).is_none() - && tcx.lookup_stability(callee).map_or(false, |s| s.level.is_unstable()); + && tcx.lookup_stability(callee).map_or(false, |s| s.is_unstable()); if callee_is_unstable_unmarked { trace!("callee_is_unstable_unmarked"); // We do not use `const` modifiers for intrinsic "functions", as intrinsics are diff --git a/compiler/rustc_const_eval/src/transform/check_consts/mod.rs b/compiler/rustc_const_eval/src/transform/check_consts/mod.rs index 23e2afae79183..25b420bed1766 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/mod.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/mod.rs @@ -9,7 +9,7 @@ use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::mir; use rustc_middle::ty::{self, TyCtxt}; -use rustc_span::{sym, Symbol}; +use rustc_span::Symbol; pub use self::qualifs::Qualif; @@ -84,34 +84,49 @@ pub fn rustc_allow_const_fn_unstable( // functions are subject to more stringent restrictions than "const-unstable" functions: They // cannot use unstable features and can only call other "const-stable" functions. pub fn is_const_stable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool { - use attr::{ConstStability, Stability, StabilityLevel}; - - // A default body marked const is not const-stable because const + // A default body in a `#[const_trait]` is not const-stable because const // trait fns currently cannot be const-stable. We shouldn't // restrict default bodies to only call const-stable functions. - if tcx.has_attr(def_id, sym::default_method_body_is_const) { + if tcx.is_const_default_method(def_id) { return false; } // Const-stability is only relevant for `const fn`. assert!(tcx.is_const_fn_raw(def_id)); - // Functions with `#[rustc_const_unstable]` are const-unstable. + // A function is only const-stable if it has `#[rustc_const_stable]` or it the trait it belongs + // to is const-stable. match tcx.lookup_const_stability(def_id) { - Some(ConstStability { level: StabilityLevel::Unstable { .. }, .. }) => return false, - Some(ConstStability { level: StabilityLevel::Stable { .. }, .. }) => return true, - None => {} + Some(stab) => stab.is_const_stable(), + None if is_parent_const_stable_trait(tcx, def_id) => { + // Remove this when `#![feature(const_trait_impl)]` is stabilized, + // returning `true` unconditionally. + tcx.sess.delay_span_bug( + tcx.def_span(def_id), + "trait implementations cannot be const stable yet", + ); + true + } + None => false, // By default, items are not const stable. } +} + +fn is_parent_const_stable_trait(tcx: TyCtxt<'_>, def_id: DefId) -> bool { + let local_def_id = def_id.expect_local(); + let hir_id = tcx.local_def_id_to_hir_id(local_def_id); + + let Some(parent) = tcx.hir().find_parent_node(hir_id) else { return false }; + let parent_def = tcx.hir().get(parent); - // Functions with `#[unstable]` are const-unstable. - // - // FIXME(ecstaticmorse): We should keep const-stability attributes wholly separate from normal stability - // attributes. `#[unstable]` should be irrelevant. - if let Some(Stability { level: StabilityLevel::Unstable { .. }, .. }) = - tcx.lookup_stability(def_id) - { + if !matches!( + parent_def, + hir::Node::Item(hir::Item { + kind: hir::ItemKind::Impl(hir::Impl { constness: hir::Constness::Const, .. }), + .. + }) + ) { return false; } - true + tcx.lookup_const_stability(parent.owner).map_or(false, |stab| stab.is_const_stable()) } diff --git a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs index 122471b208d80..4e71baa77b0fd 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs @@ -89,7 +89,10 @@ impl<'tcx> NonConstOp<'tcx> for FnCallIndirect { ccx: &ConstCx<'_, 'tcx>, span: Span, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { - ccx.tcx.sess.struct_span_err(span, "function pointers are not allowed in const fn") + ccx.tcx.sess.struct_span_err( + span, + &format!("function pointer calls are not allowed in {}s", ccx.const_kind()), + ) } } diff --git a/compiler/rustc_const_eval/src/transform/promote_consts.rs b/compiler/rustc_const_eval/src/transform/promote_consts.rs index f88538f61ec6e..cf5d7b6c70a30 100644 --- a/compiler/rustc_const_eval/src/transform/promote_consts.rs +++ b/compiler/rustc_const_eval/src/transform/promote_consts.rs @@ -16,7 +16,6 @@ use rustc_hir as hir; use rustc_middle::mir::traversal::ReversePostorderIter; use rustc_middle::mir::visit::{MutVisitor, MutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::*; -use rustc_middle::ty::cast::CastTy; use rustc_middle::ty::subst::InternalSubsts; use rustc_middle::ty::{self, List, TyCtxt, TypeFoldable}; use rustc_span::Span; @@ -502,18 +501,11 @@ impl<'tcx> Validator<'_, 'tcx> { Rvalue::ThreadLocalRef(_) => return Err(Unpromotable), - Rvalue::Cast(kind, operand, cast_ty) => { - if matches!(kind, CastKind::Misc) { - let operand_ty = operand.ty(self.body, self.tcx); - let cast_in = CastTy::from_ty(operand_ty).expect("bad input type for cast"); - let cast_out = CastTy::from_ty(*cast_ty).expect("bad output type for cast"); - if let (CastTy::Ptr(_) | CastTy::FnPtr, CastTy::Int(_)) = (cast_in, cast_out) { - // ptr-to-int casts are not possible in consts and thus not promotable - return Err(Unpromotable); - } - // int-to-ptr casts are fine, they just use the integer value at pointer type. - } + // ptr-to-int casts are not possible in consts and thus not promotable + Rvalue::Cast(CastKind::PointerExposeAddress, _, _) => return Err(Unpromotable), + // int-to-ptr casts are fine, they just use the integer value at pointer type. + Rvalue::Cast(_, operand, _) => { self.validate_operand(operand)?; } @@ -788,7 +780,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { } else { let terminator = self.source[loc.block].terminator_mut(); let target = match terminator.kind { - TerminatorKind::Call { destination: Some((_, target)), .. } => target, + TerminatorKind::Call { target: Some(target), .. } => target, ref kind => { span_bug!(terminator.source_info.span, "{:?} not promotable", kind); } @@ -814,7 +806,8 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { func, args, cleanup: None, - destination: Some((Place::from(new_temp), new_target)), + destination: Place::from(new_temp), + target: Some(new_target), from_hir_call, fn_span, }, @@ -1054,11 +1047,9 @@ pub fn is_const_fn_in_array_repeat_expression<'tcx>( { if let Operand::Constant(box Constant { literal, .. }) = func { if let ty::FnDef(def_id, _) = *literal.ty().kind() { - if let Some((destination_place, _)) = destination { - if destination_place == place { - if ccx.tcx.is_const_fn(def_id) { - return true; - } + if destination == place { + if ccx.tcx.is_const_fn(def_id) { + return true; } } } diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs index 3ce33d547c582..665b07c9f89ce 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -4,6 +4,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_index::bit_set::BitSet; use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::mir::interpret::Scalar; +use rustc_middle::mir::visit::NonUseContext::VarDebugInfo; use rustc_middle::mir::visit::{PlaceContext, Visitor}; use rustc_middle::mir::{ traversal, AggregateKind, BasicBlock, BinOp, Body, BorrowKind, Local, Location, MirPass, @@ -302,9 +303,17 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { self.super_projection_elem(local, proj_base, elem, context, location); } - fn visit_place(&mut self, place: &Place<'tcx>, _: PlaceContext, _: Location) { + fn visit_place(&mut self, place: &Place<'tcx>, cntxt: PlaceContext, location: Location) { // Set off any `bug!`s in the type computation code let _ = place.ty(&self.body.local_decls, self.tcx); + + if self.mir_phase >= MirPhase::Derefered + && place.projection.len() > 1 + && cntxt != PlaceContext::NonUse(VarDebugInfo) + && place.projection[1..].contains(&ProjectionElem::Deref) + { + self.fail(location, format!("{:?}, has deref at the wrong place", place)); + } } fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { @@ -673,7 +682,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { self.check_edge(location, *unwind, EdgeKind::Unwind); } } - TerminatorKind::Call { func, args, destination, cleanup, .. } => { + TerminatorKind::Call { func, args, destination, target, cleanup, .. } => { let func_ty = func.ty(&self.body.local_decls, self.tcx); match func_ty.kind() { ty::FnPtr(..) | ty::FnDef(..) => {} @@ -682,7 +691,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { format!("encountered non-callable type {} in `Call` terminator", func_ty), ), } - if let Some((_, target)) = destination { + if let Some(target) = target { self.check_edge(location, *target, EdgeKind::Normal); } if let Some(cleanup) = cleanup { @@ -693,9 +702,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { // passed by a reference to the callee. Consequently they must be non-overlapping. // Currently this simply checks for duplicate places. self.place_cache.clear(); - if let Some((destination, _)) = destination { - self.place_cache.push(destination.as_ref()); - } + self.place_cache.push(destination.as_ref()); for arg in args { if let Operand::Move(place) = arg { self.place_cache.push(place.as_ref()); diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml index 7cc8b5c20339a..33deadb32d447 100644 --- a/compiler/rustc_data_structures/Cargo.toml +++ b/compiler/rustc_data_structures/Cargo.toml @@ -9,7 +9,7 @@ doctest = false [dependencies] arrayvec = { version = "0.7", default-features = false } ena = "0.14" -indexmap = { version = "1.8.0" } +indexmap = { version = "1.8.2" } tracing = "0.1" jobserver_crate = { version = "0.1.13", package = "jobserver" } rustc_serialize = { path = "../rustc_serialize" } @@ -17,8 +17,8 @@ rustc_macros = { path = "../rustc_macros" } rustc_graphviz = { path = "../rustc_graphviz" } cfg-if = "0.1.2" stable_deref_trait = "1.0.0" -rayon = { version = "0.3.2", package = "rustc-rayon", optional = true } -rayon-core = { version = "0.3.2", package = "rustc-rayon-core", optional = true } +rayon = { version = "0.4.0", package = "rustc-rayon", optional = true } +rayon-core = { version = "0.4.0", package = "rustc-rayon-core", optional = true } rustc-hash = "1.1.0" smallvec = { version = "1.6.1", features = ["const_generics", "union", "may_dangle"] } rustc_index = { path = "../rustc_index", package = "rustc_index" } diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index 76ae17f28c613..0d072046d58ff 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -13,8 +13,6 @@ #![feature(control_flow_enum)] #![feature(core_intrinsics)] #![feature(extend_one)] -#![feature(generator_trait)] -#![feature(generators)] #![feature(let_else)] #![feature(hash_raw_entry)] #![feature(hasher_prefixfree_extras)] @@ -114,9 +112,6 @@ pub mod unhash; pub use ena::undo_log; pub use ena::unify; -use std::ops::{Generator, GeneratorState}; -use std::pin::Pin; - pub struct OnDrop(pub F); impl OnDrop { @@ -135,26 +130,6 @@ impl Drop for OnDrop { } } -struct IterFromGenerator(G); - -impl + Unpin> Iterator for IterFromGenerator { - type Item = G::Yield; - - fn next(&mut self) -> Option { - match Pin::new(&mut self.0).resume(()) { - GeneratorState::Yielded(n) => Some(n), - GeneratorState::Complete(_) => None, - } - } -} - -/// An adapter for turning a generator closure into an iterator, similar to `iter::from_fn`. -pub fn iter_from_generator + Unpin>( - generator: G, -) -> impl Iterator { - IterFromGenerator(generator) -} - // See comments in src/librustc_middle/lib.rs #[doc(hidden)] pub fn __noop_fix_for_27438() {} diff --git a/compiler/rustc_data_structures/src/sso/set.rs b/compiler/rustc_data_structures/src/sso/set.rs index f71522d37148a..4fda3adb7b878 100644 --- a/compiler/rustc_data_structures/src/sso/set.rs +++ b/compiler/rustc_data_structures/src/sso/set.rs @@ -126,9 +126,10 @@ impl SsoHashSet { /// Adds a value to the set. /// - /// If the set did not have this value present, `true` is returned. + /// Returns whether the value was newly inserted. That is: /// - /// If the set did have this value present, `false` is returned. + /// - If the set did not previously contain this value, `true` is returned. + /// - If the set already contained this value, `false` is returned. #[inline] pub fn insert(&mut self, elem: T) -> bool { self.map.insert(elem, ()).is_none() diff --git a/compiler/rustc_data_structures/src/stable_hasher.rs b/compiler/rustc_data_structures/src/stable_hasher.rs index c8bb4fc5e6af6..a915a4daa9541 100644 --- a/compiler/rustc_data_structures/src/stable_hasher.rs +++ b/compiler/rustc_data_structures/src/stable_hasher.rs @@ -632,10 +632,10 @@ fn stable_hash_reduce( } } -/// Controls what data we do or not not hash. +/// Controls what data we do or do not hash. /// Whenever a `HashStable` implementation caches its /// result, it needs to include `HashingControls` as part -/// of the key, to ensure that is does not produce an incorrect +/// of the key, to ensure that it does not produce an incorrect /// result (for example, using a `Fingerprint` produced while /// hashing `Span`s when a `Fingerprint` without `Span`s is /// being requested) diff --git a/compiler/rustc_error_messages/locales/en-US/parser.ftl b/compiler/rustc_error_messages/locales/en-US/parser.ftl index 3143b81b6098f..c98989b23c1a5 100644 --- a/compiler/rustc_error_messages/locales/en-US/parser.ftl +++ b/compiler/rustc_error_messages/locales/en-US/parser.ftl @@ -5,3 +5,12 @@ parser-struct-literal-body-without-path = parser-maybe-report-ambiguous-plus = ambiguous `+` in a type .suggestion = use parentheses to disambiguate + +parser-maybe-recover-from-bad-type-plus = + expected a path on the left-hand side of `+`, not `{$ty}` + +parser-add-paren = try adding parentheses + +parser-forgot-paren = perhaps you forgot parentheses? + +parser-expect-path = expected a path diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs index e1e0ed7222d55..02d076c95ca52 100644 --- a/compiler/rustc_error_messages/src/lib.rs +++ b/compiler/rustc_error_messages/src/lib.rs @@ -6,7 +6,7 @@ use fluent_bundle::FluentResource; use fluent_syntax::parser::ParserError; use rustc_data_structures::sync::Lrc; -use rustc_macros::{Decodable, Encodable}; +use rustc_macros::{fluent_messages, Decodable, Encodable}; use rustc_span::Span; use std::borrow::Cow; use std::error::Error; @@ -29,8 +29,13 @@ use intl_memoizer::IntlLangMemoizer; pub use fluent_bundle::{FluentArgs, FluentError, FluentValue}; pub use unic_langid::{langid, LanguageIdentifier}; -pub static DEFAULT_LOCALE_RESOURCES: &'static [&'static str] = - &[include_str!("../locales/en-US/typeck.ftl"), include_str!("../locales/en-US/parser.ftl")]; +// Generates `DEFAULT_LOCALE_RESOURCES` static and `fluent_generated` module. +fluent_messages! { + parser => "../locales/en-US/parser.ftl", + typeck => "../locales/en-US/typeck.ftl", +} + +pub use fluent_generated::{self as fluent, DEFAULT_LOCALE_RESOURCES}; pub type FluentBundle = fluent_bundle::bundle::FluentBundle; @@ -229,6 +234,48 @@ pub fn fallback_fluent_bundle( /// Identifier for the Fluent message/attribute corresponding to a diagnostic message. type FluentId = Cow<'static, str>; +/// Abstraction over a message in a subdiagnostic (i.e. label, note, help, etc) to support both +/// translatable and non-translatable diagnostic messages. +/// +/// Translatable messages for subdiagnostics are typically attributes attached to a larger Fluent +/// message so messages of this type must be combined with a `DiagnosticMessage` (using +/// `DiagnosticMessage::with_subdiagnostic_message`) before rendering. However, subdiagnostics from +/// the `SessionSubdiagnostic` derive refer to Fluent identifiers directly. +pub enum SubdiagnosticMessage { + /// Non-translatable diagnostic message. + // FIXME(davidtwco): can a `Cow<'static, str>` be used here? + Str(String), + /// Identifier of a Fluent message. Instances of this variant are generated by the + /// `SessionSubdiagnostic` derive. + FluentIdentifier(FluentId), + /// Attribute of a Fluent message. Needs to be combined with a Fluent identifier to produce an + /// actual translated message. Instances of this variant are generated by the `fluent_messages` + /// macro. + /// + /// + FluentAttr(FluentId), +} + +impl SubdiagnosticMessage { + /// Create a `SubdiagnosticMessage` for the provided Fluent attribute. + pub fn attr(id: impl Into) -> Self { + SubdiagnosticMessage::FluentAttr(id.into()) + } + + /// Create a `SubdiagnosticMessage` for the provided Fluent identifier. + pub fn message(id: impl Into) -> Self { + SubdiagnosticMessage::FluentIdentifier(id.into()) + } +} + +/// `From` impl that enables existing diagnostic calls to functions which now take +/// `impl Into` to continue to work as before. +impl> From for SubdiagnosticMessage { + fn from(s: S) -> Self { + SubdiagnosticMessage::Str(s.into()) + } +} + /// Abstraction over a message in a diagnostic to support both translatable and non-translatable /// diagnostic messages. /// @@ -247,6 +294,29 @@ pub enum DiagnosticMessage { } impl DiagnosticMessage { + /// Given a `SubdiagnosticMessage` which may contain a Fluent attribute, create a new + /// `DiagnosticMessage` that combines that attribute with the Fluent identifier of `self`. + /// + /// - If the `SubdiagnosticMessage` is non-translatable then return the message as a + /// `DiagnosticMessage`. + /// - If `self` is non-translatable then return `self`'s message. + pub fn with_subdiagnostic_message(&self, sub: SubdiagnosticMessage) -> Self { + let attr = match sub { + SubdiagnosticMessage::Str(s) => return DiagnosticMessage::Str(s.clone()), + SubdiagnosticMessage::FluentIdentifier(id) => { + return DiagnosticMessage::FluentIdentifier(id, None); + } + SubdiagnosticMessage::FluentAttr(attr) => attr, + }; + + match self { + DiagnosticMessage::Str(s) => DiagnosticMessage::Str(s.clone()), + DiagnosticMessage::FluentIdentifier(id, _) => { + DiagnosticMessage::FluentIdentifier(id.clone(), Some(attr)) + } + } + } + /// Returns the `String` contained within the `DiagnosticMessage::Str` variant, assuming that /// this diagnostic message is of the legacy, non-translatable variety. Panics if this /// assumption does not hold. @@ -261,14 +331,9 @@ impl DiagnosticMessage { } /// Create a `DiagnosticMessage` for the provided Fluent identifier. - pub fn fluent(id: impl Into) -> Self { + pub fn new(id: impl Into) -> Self { DiagnosticMessage::FluentIdentifier(id.into(), None) } - - /// Create a `DiagnosticMessage` for the provided Fluent identifier and attribute. - pub fn fluent_attr(id: impl Into, attr: impl Into) -> Self { - DiagnosticMessage::FluentIdentifier(id.into(), Some(attr.into())) - } } /// `From` impl that enables existing diagnostic calls to functions which now take diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index 909ed566f64ea..643f3c12134c9 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -1,7 +1,7 @@ use crate::snippet::Style; use crate::{ - CodeSuggestion, DiagnosticMessage, Level, MultiSpan, Substitution, SubstitutionPart, - SuggestionStyle, + CodeSuggestion, DiagnosticMessage, Level, MultiSpan, SubdiagnosticMessage, Substitution, + SubstitutionPart, SuggestionStyle, }; use rustc_data_structures::stable_map::FxHashMap; use rustc_error_messages::FluentValue; @@ -90,7 +90,7 @@ pub trait AddSubdiagnostic { pub struct Diagnostic { // NOTE(eddyb) this is private to disallow arbitrary after-the-fact changes, // outside of what methods in this crate themselves allow. - crate level: Level, + pub(crate) level: Level, pub message: Vec<(DiagnosticMessage, Style)>, pub code: Option, @@ -283,8 +283,8 @@ impl Diagnostic { /// /// This span is *not* considered a ["primary span"][`MultiSpan`]; only /// the `Span` supplied when creating the diagnostic is primary. - pub fn span_label(&mut self, span: Span, label: impl Into) -> &mut Self { - self.span.push_span_label(span, label.into()); + pub fn span_label(&mut self, span: Span, label: impl Into) -> &mut Self { + self.span.push_span_label(span, self.subdiagnostic_message_to_diagnostic_message(label)); self } @@ -401,12 +401,12 @@ impl Diagnostic { } /// Add a note attached to this diagnostic. - pub fn note(&mut self, msg: impl Into) -> &mut Self { + pub fn note(&mut self, msg: impl Into) -> &mut Self { self.sub(Level::Note, msg, MultiSpan::new(), None); self } - pub fn highlighted_note>( + pub fn highlighted_note>( &mut self, msg: Vec<(M, Style)>, ) -> &mut Self { @@ -416,7 +416,7 @@ impl Diagnostic { /// Prints the span with a note above it. /// This is like [`Diagnostic::note()`], but it gets its own span. - pub fn note_once(&mut self, msg: impl Into) -> &mut Self { + pub fn note_once(&mut self, msg: impl Into) -> &mut Self { self.sub(Level::OnceNote, msg, MultiSpan::new(), None); self } @@ -426,7 +426,7 @@ impl Diagnostic { pub fn span_note>( &mut self, sp: S, - msg: impl Into, + msg: impl Into, ) -> &mut Self { self.sub(Level::Note, msg, sp.into(), None); self @@ -437,14 +437,14 @@ impl Diagnostic { pub fn span_note_once>( &mut self, sp: S, - msg: impl Into, + msg: impl Into, ) -> &mut Self { self.sub(Level::OnceNote, msg, sp.into(), None); self } /// Add a warning attached to this diagnostic. - pub fn warn(&mut self, msg: impl Into) -> &mut Self { + pub fn warn(&mut self, msg: impl Into) -> &mut Self { self.sub(Level::Warning, msg, MultiSpan::new(), None); self } @@ -454,14 +454,14 @@ impl Diagnostic { pub fn span_warn>( &mut self, sp: S, - msg: impl Into, + msg: impl Into, ) -> &mut Self { self.sub(Level::Warning, msg, sp.into(), None); self } /// Add a help message attached to this diagnostic. - pub fn help(&mut self, msg: impl Into) -> &mut Self { + pub fn help(&mut self, msg: impl Into) -> &mut Self { self.sub(Level::Help, msg, MultiSpan::new(), None); self } @@ -477,7 +477,7 @@ impl Diagnostic { pub fn span_help>( &mut self, sp: S, - msg: impl Into, + msg: impl Into, ) -> &mut Self { self.sub(Level::Help, msg, sp.into(), None); self @@ -514,7 +514,7 @@ impl Diagnostic { /// In other words, multiple changes need to be applied as part of this suggestion. pub fn multipart_suggestion( &mut self, - msg: impl Into, + msg: impl Into, suggestion: Vec<(Span, String)>, applicability: Applicability, ) -> &mut Self { @@ -530,7 +530,7 @@ impl Diagnostic { /// In other words, multiple changes need to be applied as part of this suggestion. pub fn multipart_suggestion_verbose( &mut self, - msg: impl Into, + msg: impl Into, suggestion: Vec<(Span, String)>, applicability: Applicability, ) -> &mut Self { @@ -544,7 +544,7 @@ impl Diagnostic { /// [`Diagnostic::multipart_suggestion()`] but you can set the [`SuggestionStyle`]. pub fn multipart_suggestion_with_style( &mut self, - msg: impl Into, + msg: impl Into, suggestion: Vec<(Span, String)>, applicability: Applicability, style: SuggestionStyle, @@ -557,7 +557,7 @@ impl Diagnostic { .map(|(span, snippet)| SubstitutionPart { snippet, span }) .collect(), }], - msg: msg.into(), + msg: self.subdiagnostic_message_to_diagnostic_message(msg), style, applicability, }); @@ -572,7 +572,7 @@ impl Diagnostic { /// improve understandability. pub fn tool_only_multipart_suggestion( &mut self, - msg: impl Into, + msg: impl Into, suggestion: Vec<(Span, String)>, applicability: Applicability, ) -> &mut Self { @@ -584,7 +584,7 @@ impl Diagnostic { .map(|(span, snippet)| SubstitutionPart { snippet, span }) .collect(), }], - msg: msg.into(), + msg: self.subdiagnostic_message_to_diagnostic_message(msg), style: SuggestionStyle::CompletelyHidden, applicability, }); @@ -611,7 +611,7 @@ impl Diagnostic { pub fn span_suggestion( &mut self, sp: Span, - msg: impl Into, + msg: impl Into, suggestion: impl ToString, applicability: Applicability, ) -> &mut Self { @@ -629,7 +629,7 @@ impl Diagnostic { pub fn span_suggestion_with_style( &mut self, sp: Span, - msg: impl Into, + msg: impl Into, suggestion: impl ToString, applicability: Applicability, style: SuggestionStyle, @@ -638,7 +638,7 @@ impl Diagnostic { substitutions: vec![Substitution { parts: vec![SubstitutionPart { snippet: suggestion.to_string(), span: sp }], }], - msg: msg.into(), + msg: self.subdiagnostic_message_to_diagnostic_message(msg), style, applicability, }); @@ -649,7 +649,7 @@ impl Diagnostic { pub fn span_suggestion_verbose( &mut self, sp: Span, - msg: impl Into, + msg: impl Into, suggestion: impl ToString, applicability: Applicability, ) -> &mut Self { @@ -668,7 +668,7 @@ impl Diagnostic { pub fn span_suggestions( &mut self, sp: Span, - msg: impl Into, + msg: impl Into, suggestions: impl Iterator, applicability: Applicability, ) -> &mut Self { @@ -680,7 +680,7 @@ impl Diagnostic { .collect(); self.push_suggestion(CodeSuggestion { substitutions, - msg: msg.into(), + msg: self.subdiagnostic_message_to_diagnostic_message(msg), style: SuggestionStyle::ShowCode, applicability, }); @@ -691,7 +691,7 @@ impl Diagnostic { /// See also [`Diagnostic::span_suggestion()`]. pub fn multipart_suggestions( &mut self, - msg: impl Into, + msg: impl Into, suggestions: impl Iterator>, applicability: Applicability, ) -> &mut Self { @@ -704,7 +704,7 @@ impl Diagnostic { .collect(), }) .collect(), - msg: msg.into(), + msg: self.subdiagnostic_message_to_diagnostic_message(msg), style: SuggestionStyle::ShowCode, applicability, }); @@ -717,7 +717,7 @@ impl Diagnostic { pub fn span_suggestion_short( &mut self, sp: Span, - msg: impl Into, + msg: impl Into, suggestion: impl ToString, applicability: Applicability, ) -> &mut Self { @@ -740,7 +740,7 @@ impl Diagnostic { pub fn span_suggestion_hidden( &mut self, sp: Span, - msg: impl Into, + msg: impl Into, suggestion: impl ToString, applicability: Applicability, ) -> &mut Self { @@ -761,7 +761,7 @@ impl Diagnostic { pub fn tool_only_span_suggestion( &mut self, sp: Span, - msg: impl Into, + msg: impl Into, suggestion: impl ToString, applicability: Applicability, ) -> &mut Self { @@ -831,6 +831,18 @@ impl Diagnostic { &self.message } + /// Helper function that takes a `SubdiagnosticMessage` and returns a `DiagnosticMessage` by + /// combining it with the primary message of the diagnostic (if translatable, otherwise it just + /// passes the user's string along). + fn subdiagnostic_message_to_diagnostic_message( + &self, + attr: impl Into, + ) -> DiagnosticMessage { + let msg = + self.message.iter().map(|(msg, _)| msg).next().expect("diagnostic with no messages"); + msg.with_subdiagnostic_message(attr.into()) + } + /// Convenience function for internal use, clients should use one of the /// public methods above. /// @@ -838,13 +850,16 @@ impl Diagnostic { pub fn sub( &mut self, level: Level, - message: impl Into, + message: impl Into, span: MultiSpan, render_span: Option, ) { let sub = SubDiagnostic { level, - message: vec![(message.into(), Style::NoStyle)], + message: vec![( + self.subdiagnostic_message_to_diagnostic_message(message), + Style::NoStyle, + )], span, render_span, }; @@ -853,14 +868,17 @@ impl Diagnostic { /// Convenience function for internal use, clients should use one of the /// public methods above. - fn sub_with_highlights>( + fn sub_with_highlights>( &mut self, level: Level, mut message: Vec<(M, Style)>, span: MultiSpan, render_span: Option, ) { - let message = message.drain(..).map(|m| (m.0.into(), m.1)).collect(); + let message = message + .drain(..) + .map(|m| (self.subdiagnostic_message_to_diagnostic_message(m.0), m.1)) + .collect(); let sub = SubDiagnostic { level, message, span, render_span }; self.children.push(sub); } diff --git a/compiler/rustc_errors/src/diagnostic_builder.rs b/compiler/rustc_errors/src/diagnostic_builder.rs index 53ad6e5a0edea..9e0a99849a3f4 100644 --- a/compiler/rustc_errors/src/diagnostic_builder.rs +++ b/compiler/rustc_errors/src/diagnostic_builder.rs @@ -1,5 +1,8 @@ use crate::diagnostic::IntoDiagnosticArg; -use crate::{Diagnostic, DiagnosticId, DiagnosticMessage, DiagnosticStyledString, ErrorGuaranteed}; +use crate::{ + Diagnostic, DiagnosticId, DiagnosticMessage, DiagnosticStyledString, ErrorGuaranteed, + SubdiagnosticMessage, +}; use crate::{Handler, Level, MultiSpan, StashKey}; use rustc_lint_defs::Applicability; @@ -88,7 +91,7 @@ mod sealed_level_is_error { use crate::Level; /// Sealed helper trait for statically checking that a `Level` is an error. - crate trait IsError {} + pub(crate) trait IsError {} impl IsError<{ Level::Bug }> for () {} impl IsError<{ Level::DelayedBug }> for () {} @@ -101,7 +104,7 @@ mod sealed_level_is_error { impl<'a> DiagnosticBuilder<'a, ErrorGuaranteed> { /// Convenience function for internal use, clients should use one of the /// `struct_*` methods on [`Handler`]. - crate fn new_guaranteeing_error, const L: Level>( + pub(crate) fn new_guaranteeing_error, const L: Level>( handler: &'a Handler, message: M, ) -> Self @@ -168,7 +171,7 @@ impl EmissionGuarantee for ErrorGuaranteed { impl<'a> DiagnosticBuilder<'a, ()> { /// Convenience function for internal use, clients should use one of the /// `struct_*` methods on [`Handler`]. - crate fn new>( + pub(crate) fn new>( handler: &'a Handler, level: Level, message: M, @@ -179,7 +182,7 @@ impl<'a> DiagnosticBuilder<'a, ()> { /// Creates a new `DiagnosticBuilder` with an already constructed /// diagnostic. - crate fn new_diagnostic(handler: &'a Handler, diagnostic: Diagnostic) -> Self { + pub(crate) fn new_diagnostic(handler: &'a Handler, diagnostic: Diagnostic) -> Self { debug!("Created new diagnostic"); Self { inner: DiagnosticBuilderInner { @@ -210,14 +213,14 @@ impl EmissionGuarantee for () { impl<'a> DiagnosticBuilder<'a, !> { /// Convenience function for internal use, clients should use one of the /// `struct_*` methods on [`Handler`]. - crate fn new_fatal(handler: &'a Handler, message: impl Into) -> Self { + pub(crate) fn new_fatal(handler: &'a Handler, message: impl Into) -> Self { let diagnostic = Diagnostic::new_with_code(Level::Fatal, None, message); Self::new_diagnostic_fatal(handler, diagnostic) } /// Creates a new `DiagnosticBuilder` with an already constructed /// diagnostic. - crate fn new_diagnostic_fatal(handler: &'a Handler, diagnostic: Diagnostic) -> Self { + pub(crate) fn new_diagnostic_fatal(handler: &'a Handler, diagnostic: Diagnostic) -> Self { debug!("Created new diagnostic"); Self { inner: DiagnosticBuilderInner { @@ -395,7 +398,7 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> { /// the diagnostic was constructed. However, the label span is *not* considered a /// ["primary span"][`MultiSpan`]; only the `Span` supplied when creating the diagnostic is /// primary. - pub fn span_label(&mut self, span: Span, label: impl Into) -> &mut Self); + pub fn span_label(&mut self, span: Span, label: impl Into) -> &mut Self); forward!( /// Labels all the given spans with the provided label. @@ -430,25 +433,29 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> { found: DiagnosticStyledString, ) -> &mut Self); - forward!(pub fn note(&mut self, msg: impl Into) -> &mut Self); - forward!(pub fn note_once(&mut self, msg: impl Into) -> &mut Self); + forward!(pub fn note(&mut self, msg: impl Into) -> &mut Self); + forward!(pub fn note_once(&mut self, msg: impl Into) -> &mut Self); forward!(pub fn span_note( &mut self, sp: impl Into, - msg: impl Into, + msg: impl Into, ) -> &mut Self); forward!(pub fn span_note_once( &mut self, sp: impl Into, - msg: impl Into, + msg: impl Into, ) -> &mut Self); - forward!(pub fn warn(&mut self, msg: impl Into) -> &mut Self); - forward!(pub fn span_warn(&mut self, sp: impl Into, msg: &str) -> &mut Self); - forward!(pub fn help(&mut self, msg: impl Into) -> &mut Self); + forward!(pub fn warn(&mut self, msg: impl Into) -> &mut Self); + forward!(pub fn span_warn( + &mut self, + sp: impl Into, + msg: impl Into, + ) -> &mut Self); + forward!(pub fn help(&mut self, msg: impl Into) -> &mut Self); forward!(pub fn span_help( &mut self, sp: impl Into, - msg: impl Into, + msg: impl Into, ) -> &mut Self); forward!(pub fn help_use_latest_edition(&mut self,) -> &mut Self); forward!(pub fn set_is_lint(&mut self,) -> &mut Self); @@ -457,67 +464,67 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> { forward!(pub fn multipart_suggestion( &mut self, - msg: impl Into, + msg: impl Into, suggestion: Vec<(Span, String)>, applicability: Applicability, ) -> &mut Self); forward!(pub fn multipart_suggestion_verbose( &mut self, - msg: impl Into, + msg: impl Into, suggestion: Vec<(Span, String)>, applicability: Applicability, ) -> &mut Self); forward!(pub fn tool_only_multipart_suggestion( &mut self, - msg: impl Into, + msg: impl Into, suggestion: Vec<(Span, String)>, applicability: Applicability, ) -> &mut Self); forward!(pub fn span_suggestion( &mut self, sp: Span, - msg: impl Into, + msg: impl Into, suggestion: impl ToString, applicability: Applicability, ) -> &mut Self); forward!(pub fn span_suggestions( &mut self, sp: Span, - msg: impl Into, + msg: impl Into, suggestions: impl Iterator, applicability: Applicability, ) -> &mut Self); forward!(pub fn multipart_suggestions( &mut self, - msg: impl Into, + msg: impl Into, suggestions: impl Iterator>, applicability: Applicability, ) -> &mut Self); forward!(pub fn span_suggestion_short( &mut self, sp: Span, - msg: impl Into, + msg: impl Into, suggestion: impl ToString, applicability: Applicability, ) -> &mut Self); forward!(pub fn span_suggestion_verbose( &mut self, sp: Span, - msg: impl Into, + msg: impl Into, suggestion: impl ToString, applicability: Applicability, ) -> &mut Self); forward!(pub fn span_suggestion_hidden( &mut self, sp: Span, - msg: impl Into, + msg: impl Into, suggestion: impl ToString, applicability: Applicability, ) -> &mut Self); forward!(pub fn tool_only_span_suggestion( &mut self, sp: Span, - msg: impl Into, + msg: impl Into, suggestion: impl ToString, applicability: Applicability, ) -> &mut Self); diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 5dd743e8d0023..e9e7065ec03cc 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -1261,16 +1261,23 @@ impl EmitterWriter { return 0; }; + let will_be_emitted = |span: Span| { + !span.is_dummy() && { + let file = sm.lookup_source_file(span.hi()); + sm.ensure_source_file_source_present(file) + } + }; + let mut max = 0; for primary_span in msp.primary_spans() { - if !primary_span.is_dummy() { + if will_be_emitted(*primary_span) { let hi = sm.lookup_char_pos(primary_span.hi()); max = (hi.line).max(max); } } if !self.short_message { for span_label in msp.span_labels() { - if !span_label.span.is_dummy() { + if will_be_emitted(span_label.span) { let hi = sm.lookup_char_pos(span_label.span.hi()); max = (hi.line).max(max); } @@ -1708,6 +1715,7 @@ impl EmitterWriter { fn emit_suggestion_default( &mut self, + span: &MultiSpan, suggestion: &CodeSuggestion, args: &FluentArgs<'_>, level: &Level, @@ -1759,6 +1767,30 @@ impl EmitterWriter { None, } + if let Some(span) = span.primary_span() { + // Compare the primary span of the diagnostic with the span of the suggestion + // being emitted. If they belong to the same file, we don't *need* to show the + // file name, saving in verbosity, but if it *isn't* we do need it, otherwise we're + // telling users to make a change but not clarifying *where*. + let loc = sm.lookup_char_pos(parts[0].span.lo()); + if loc.file.name != sm.span_to_filename(span) && loc.file.name.is_real() { + buffer.puts(row_num - 1, 0, "--> ", Style::LineNumber); + buffer.append( + row_num - 1, + &format!( + "{}:{}:{}", + sm.filename_for_diagnostics(&loc.file.name), + sm.doctest_offset_line(&loc.file.name, loc.line), + loc.col.0 + 1, + ), + Style::LineAndColumn, + ); + for _ in 0..max_line_num_len { + buffer.prepend(row_num - 1, " ", Style::NoStyle); + } + row_num += 1; + } + } let show_code_change = if has_deletion && !is_multiline { DisplaySuggestion::Diff } else if (parts.len() != 1 || parts[0].snippet.trim() != complete.trim()) @@ -1780,7 +1812,7 @@ impl EmitterWriter { assert!(!file_lines.lines.is_empty() || parts[0].span.is_dummy()); let line_start = sm.lookup_char_pos(parts[0].span.lo()).line; - draw_col_separator_no_space(&mut buffer, 1, max_line_num_len + 1); + draw_col_separator_no_space(&mut buffer, row_num - 1, max_line_num_len + 1); let mut lines = complete.lines(); if lines.clone().next().is_none() { // Account for a suggestion to completely remove a line(s) with whitespace (#94192). @@ -2039,9 +2071,13 @@ impl EmitterWriter { ) { panic!("failed to emit error: {}", e); } - } else if let Err(e) = - self.emit_suggestion_default(sugg, args, &Level::Help, max_line_num_len) - { + } else if let Err(e) = self.emit_suggestion_default( + span, + sugg, + args, + &Level::Help, + max_line_num_len, + ) { panic!("failed to emit error: {}", e); }; } diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 29643eaad9924..fb02f1d68ebc9 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -3,7 +3,6 @@ //! This module contains the code for creating and emitting diagnostics. #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] -#![feature(crate_visibility_modifier)] #![feature(drain_filter)] #![feature(backtrace)] #![feature(if_let_guard)] @@ -32,8 +31,9 @@ use rustc_data_structures::stable_hasher::StableHasher; use rustc_data_structures::sync::{self, Lock, Lrc}; use rustc_data_structures::AtomicRef; pub use rustc_error_messages::{ - fallback_fluent_bundle, fluent_bundle, DiagnosticMessage, FluentBundle, LanguageIdentifier, - LazyFallbackBundle, MultiSpan, SpanLabel, DEFAULT_LOCALE_RESOURCES, + fallback_fluent_bundle, fluent, fluent_bundle, DiagnosticMessage, FluentBundle, + LanguageIdentifier, LazyFallbackBundle, MultiSpan, SpanLabel, SubdiagnosticMessage, + DEFAULT_LOCALE_RESOURCES, }; pub use rustc_lint_defs::{pluralize, Applicability}; use rustc_span::source_map::SourceMap; diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 9ea09f7d702ba..bb671b8705eb3 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -4,7 +4,7 @@ use crate::module::DirOwnership; use rustc_ast::attr::MarkedAttrs; use rustc_ast::ptr::P; use rustc_ast::token::{self, Nonterminal}; -use rustc_ast::tokenstream::{CanSynthesizeMissingTokens, TokenStream}; +use rustc_ast::tokenstream::TokenStream; use rustc_ast::visit::{AssocCtxt, Visitor}; use rustc_ast::{self as ast, Attribute, HasAttrs, Item, NodeId, PatKind}; use rustc_attr::{self as attr, Deprecation, Stability}; @@ -13,7 +13,7 @@ use rustc_data_structures::sync::{self, Lrc}; use rustc_errors::{Applicability, DiagnosticBuilder, ErrorGuaranteed, MultiSpan, PResult}; use rustc_lint_defs::builtin::PROC_MACRO_BACK_COMPAT; use rustc_lint_defs::BuiltinLintDiagnostics; -use rustc_parse::{self, parser, to_token_stream, MACRO_ARGUMENTS}; +use rustc_parse::{self, parser, MACRO_ARGUMENTS}; use rustc_session::{parse::ParseSess, Limit, Session}; use rustc_span::def_id::{CrateNum, DefId, LocalDefId}; use rustc_span::edition::Edition; @@ -28,7 +28,7 @@ use std::iter; use std::path::PathBuf; use std::rc::Rc; -crate use rustc_span::hygiene::MacroKind; +pub(crate) use rustc_span::hygiene::MacroKind; // When adding new variants, make sure to // adjust the `visit_*` / `flat_map_*` calls in `InvocationCollector` @@ -109,20 +109,18 @@ impl Annotatable { } } - pub fn to_tokens(&self, sess: &ParseSess) -> TokenStream { + pub fn to_tokens(&self) -> TokenStream { match self { - Annotatable::Item(node) => to_token_stream(node, sess, CanSynthesizeMissingTokens::No), + Annotatable::Item(node) => TokenStream::from_ast(node), Annotatable::TraitItem(node) | Annotatable::ImplItem(node) => { - to_token_stream(node, sess, CanSynthesizeMissingTokens::No) - } - Annotatable::ForeignItem(node) => { - to_token_stream(node, sess, CanSynthesizeMissingTokens::No) + TokenStream::from_ast(node) } + Annotatable::ForeignItem(node) => TokenStream::from_ast(node), Annotatable::Stmt(node) => { assert!(!matches!(node.kind, ast::StmtKind::Empty)); - to_token_stream(node, sess, CanSynthesizeMissingTokens::No) + TokenStream::from_ast(node) } - Annotatable::Expr(node) => to_token_stream(node, sess, CanSynthesizeMissingTokens::No), + Annotatable::Expr(node) => TokenStream::from_ast(node), Annotatable::Arm(..) | Annotatable::ExprField(..) | Annotatable::PatField(..) @@ -268,7 +266,7 @@ where } } -pub trait ProcMacro { +pub trait BangProcMacro { fn expand<'cx>( &self, ecx: &'cx mut ExtCtxt<'_>, @@ -277,7 +275,7 @@ pub trait ProcMacro { ) -> Result; } -impl ProcMacro for F +impl BangProcMacro for F where F: Fn(TokenStream) -> TokenStream, { @@ -642,7 +640,7 @@ pub enum SyntaxExtensionKind { /// A token-based function-like macro. Bang( /// An expander with signature TokenStream -> TokenStream. - Box, + Box, ), /// An AST-based function-like macro. diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs index 301c67f702645..56d0263269b53 100644 --- a/compiler/rustc_expand/src/build.rs +++ b/compiler/rustc_expand/src/build.rs @@ -514,7 +514,7 @@ impl<'a> ExtCtxt<'a> { } } - // FIXME: unused `self` + // `self` is unused but keep it as method for the convenience use. pub fn fn_decl(&self, inputs: Vec, output: ast::FnRetTy) -> P { P(ast::FnDecl { inputs, output }) } diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index 0b8cb07a64afc..3cada37257085 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -347,7 +347,7 @@ impl<'a> StripUnconfigured<'a> { /// Gives a compiler warning when the `cfg_attr` contains no attributes and /// is in the original source file. Gives a compiler error if the syntax of /// the attribute is incorrect. - crate fn expand_cfg_attr(&self, attr: Attribute, recursive: bool) -> Vec { + pub(crate) fn expand_cfg_attr(&self, attr: Attribute, recursive: bool) -> Vec { let Some((cfg_predicate, expanded_attrs)) = rustc_parse::parse_cfg_attr(&attr, &self.sess.parse_sess) else { return vec![]; @@ -400,7 +400,7 @@ impl<'a> StripUnconfigured<'a> { // Use the `#` in `#[cfg_attr(pred, attr)]` as the `#` token // for `attr` when we expand it to `#[attr]` - let mut orig_trees = orig_tokens.trees(); + let mut orig_trees = orig_tokens.into_trees(); let TokenTree::Token(pound_token @ Token { kind: TokenKind::Pound, .. }) = orig_trees.next().unwrap() else { panic!("Bad tokens for attribute {:?}", attr); }; @@ -451,7 +451,7 @@ impl<'a> StripUnconfigured<'a> { attrs.iter().all(|attr| !is_cfg(attr) || self.cfg_true(attr)) } - crate fn cfg_true(&self, attr: &Attribute) -> bool { + pub(crate) fn cfg_true(&self, attr: &Attribute) -> bool { let meta_item = match validate_attr::parse_meta(&self.sess.parse_sess, attr) { Ok(meta_item) => meta_item, Err(mut err) => { @@ -465,7 +465,7 @@ impl<'a> StripUnconfigured<'a> { } /// If attributes are not allowed on expressions, emit an error for `attr` - crate fn maybe_emit_expr_attr_err(&self, attr: &Attribute) { + pub(crate) fn maybe_emit_expr_attr_err(&self, attr: &Attribute) { if !self.features.map_or(true, |features| features.stmt_expr_attributes) { let mut err = feature_err( &self.sess.parse_sess, diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index a390e7a466dde..5af6b777abee1 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -214,7 +214,7 @@ pub enum SupportsMacroExpansion { } impl AstFragmentKind { - crate fn dummy(self, span: Span) -> AstFragment { + pub(crate) fn dummy(self, span: Span) -> AstFragment { self.make_from(DummyResult::any(span)).expect("couldn't create a dummy AST fragment") } @@ -679,9 +679,12 @@ impl<'a, 'b> MacroExpander<'a, 'b> { ) ) => { - rustc_parse::fake_token_stream(&self.cx.sess.parse_sess, item_inner) + rustc_parse::fake_token_stream_for_item( + &self.cx.sess.parse_sess, + item_inner, + ) } - _ => item.to_tokens(&self.cx.sess.parse_sess), + _ => item.to_tokens(), }; let attr_item = attr.unwrap_normal_item(); if let MacArgs::Eq(..) = attr_item.args { diff --git a/compiler/rustc_expand/src/lib.rs b/compiler/rustc_expand/src/lib.rs index dc181ecda5b05..7043ad5464530 100644 --- a/compiler/rustc_expand/src/lib.rs +++ b/compiler/rustc_expand/src/lib.rs @@ -1,7 +1,6 @@ #![allow(rustc::potential_query_instability)] #![feature(associated_type_bounds)] #![feature(associated_type_defaults)] -#![feature(crate_visibility_modifier)] #![feature(if_let_guard)] #![feature(let_chains)] #![feature(let_else)] @@ -21,7 +20,7 @@ mod placeholders; mod proc_macro_server; pub use mbe::macro_rules::compile_declarative_macro; -crate use rustc_span::hygiene; +pub(crate) use rustc_span::hygiene; pub mod base; pub mod build; #[macro_use] @@ -30,7 +29,7 @@ pub mod expand; pub mod module; pub mod proc_macro; -crate mod mbe; +pub(crate) mod mbe; // HACK(Centril, #64197): These shouldn't really be here. // Rather, they should be with their respective modules which are defined in other crates. diff --git a/compiler/rustc_expand/src/mbe.rs b/compiler/rustc_expand/src/mbe.rs index 36295da74adc5..f42576b16f520 100644 --- a/compiler/rustc_expand/src/mbe.rs +++ b/compiler/rustc_expand/src/mbe.rs @@ -3,12 +3,12 @@ //! why we call this module `mbe`. For external documentation, prefer the //! official terminology: "declarative macros". -crate mod macro_check; -crate mod macro_parser; -crate mod macro_rules; -crate mod metavar_expr; -crate mod quoted; -crate mod transcribe; +pub(crate) mod macro_check; +pub(crate) mod macro_parser; +pub(crate) mod macro_rules; +pub(crate) mod metavar_expr; +pub(crate) mod quoted; +pub(crate) mod transcribe; use metavar_expr::MetaVarExpr; use rustc_ast::token::{Delimiter, NonterminalKind, Token, TokenKind}; diff --git a/compiler/rustc_expand/src/mbe/macro_parser.rs b/compiler/rustc_expand/src/mbe/macro_parser.rs index ddfbef945efaa..0631a5e42c25d 100644 --- a/compiler/rustc_expand/src/mbe/macro_parser.rs +++ b/compiler/rustc_expand/src/mbe/macro_parser.rs @@ -70,8 +70,8 @@ //! eof: [a $( a )* a b ·] //! ``` -crate use NamedMatch::*; -crate use ParseResult::*; +pub(crate) use NamedMatch::*; +pub(crate) use ParseResult::*; use crate::mbe::{KleeneOp, TokenTree}; @@ -262,7 +262,7 @@ enum EofMatcherPositions { } /// Represents the possible results of an attempted parse. -crate enum ParseResult { +pub(crate) enum ParseResult { /// Parsed successfully. Success(T), /// Arm failed to match. If the second parameter is `token::Eof`, it indicates an unexpected @@ -276,7 +276,7 @@ crate enum ParseResult { /// A `ParseResult` where the `Success` variant contains a mapping of /// `MacroRulesNormalizedIdent`s to `NamedMatch`es. This represents the mapping /// of metavars to the token trees they bind to. -crate type NamedParseResult = ParseResult>; +pub(crate) type NamedParseResult = ParseResult>; /// Count how many metavars declarations are in `matcher`. pub(super) fn count_metavar_decls(matcher: &[TokenTree]) -> usize { @@ -340,7 +340,7 @@ pub(super) fn count_metavar_decls(matcher: &[TokenTree]) -> usize { /// ]) /// ``` #[derive(Debug, Clone)] -crate enum NamedMatch { +pub(crate) enum NamedMatch { MatchedSeq(Vec), // A metavar match of type `tt`. diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index 4cc3169180ea5..b86304ba6b1b1 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -33,7 +33,7 @@ use std::collections::hash_map::Entry; use std::{mem, slice}; use tracing::debug; -crate struct ParserAnyMacro<'a> { +pub(crate) struct ParserAnyMacro<'a> { parser: Parser<'a>, /// Span of the expansion site of the macro this parser is for @@ -47,7 +47,7 @@ crate struct ParserAnyMacro<'a> { is_local: bool, } -crate fn annotate_err_with_kind(err: &mut Diagnostic, kind: AstFragmentKind, span: Span) { +pub(crate) fn annotate_err_with_kind(err: &mut Diagnostic, kind: AstFragmentKind, span: Span) { match kind { AstFragmentKind::Ty => { err.span_label(span, "this macro call doesn't expand to a type"); @@ -113,7 +113,7 @@ fn emit_frag_parse_err( } impl<'a> ParserAnyMacro<'a> { - crate fn make(mut self: Box>, kind: AstFragmentKind) -> AstFragment { + pub(crate) fn make(mut self: Box>, kind: AstFragmentKind) -> AstFragment { let ParserAnyMacro { site_span, macro_ident, @@ -204,7 +204,7 @@ fn trace_macros_note(cx_expansions: &mut FxHashMap>, sp: Span, /// Expands the rules based macro defined by `lhses` and `rhses` for a given /// input `arg`. -fn expand_macro<'cx, 'tt>( +fn expand_macro<'cx>( cx: &'cx mut ExtCtxt<'_>, sp: Span, def_span: Span, @@ -212,8 +212,8 @@ fn expand_macro<'cx, 'tt>( name: Ident, transparency: Transparency, arg: TokenStream, - lhses: &'tt [Vec], - rhses: &'tt [mbe::TokenTree], + lhses: &[Vec], + rhses: &[mbe::TokenTree], ) -> Box { let sess = &cx.sess.parse_sess; // Macros defined in the current crate have a real node id, diff --git a/compiler/rustc_expand/src/mbe/metavar_expr.rs b/compiler/rustc_expand/src/mbe/metavar_expr.rs index cdc5e204236fb..ccc1c2b2ca05b 100644 --- a/compiler/rustc_expand/src/mbe/metavar_expr.rs +++ b/compiler/rustc_expand/src/mbe/metavar_expr.rs @@ -1,5 +1,5 @@ use rustc_ast::token::{self, Delimiter}; -use rustc_ast::tokenstream::{Cursor, TokenStream, TokenTree}; +use rustc_ast::tokenstream::{CursorRef, TokenStream, TokenTree}; use rustc_ast::{LitIntType, LitKind}; use rustc_ast_pretty::pprust; use rustc_errors::{Applicability, PResult}; @@ -9,7 +9,7 @@ use rustc_span::Span; /// A meta-variable expression, for expansions based on properties of meta-variables. #[derive(Debug, Clone, PartialEq, Encodable, Decodable)] -crate enum MetaVarExpr { +pub(crate) enum MetaVarExpr { /// The number of repetitions of an identifier, optionally limited to a number /// of outer-most repetition depths. If the depth limit is `None` then the depth is unlimited. Count(Ident, Option), @@ -28,7 +28,7 @@ crate enum MetaVarExpr { impl MetaVarExpr { /// Attempt to parse a meta-variable expression from a token stream. - crate fn parse<'sess>( + pub(crate) fn parse<'sess>( input: &TokenStream, outer_span: Span, sess: &'sess ParseSess, @@ -62,7 +62,7 @@ impl MetaVarExpr { Ok(rslt) } - crate fn ident(&self) -> Option { + pub(crate) fn ident(&self) -> Option { match *self { MetaVarExpr::Count(ident, _) | MetaVarExpr::Ignore(ident) => Some(ident), MetaVarExpr::Index(..) | MetaVarExpr::Length(..) => None, @@ -71,12 +71,14 @@ impl MetaVarExpr { } // Checks if there are any remaining tokens. For example, `${ignore(ident ... a b c ...)}` -fn check_trailing_token<'sess>(iter: &mut Cursor, sess: &'sess ParseSess) -> PResult<'sess, ()> { +fn check_trailing_token<'sess>( + iter: &mut CursorRef<'_>, + sess: &'sess ParseSess, +) -> PResult<'sess, ()> { if let Some(tt) = iter.next() { - let mut diag = sess.span_diagnostic.struct_span_err( - tt.span(), - &format!("unexpected token: {}", pprust::tt_to_string(&tt)), - ); + let mut diag = sess + .span_diagnostic + .struct_span_err(tt.span(), &format!("unexpected token: {}", pprust::tt_to_string(tt))); diag.span_note(tt.span(), "meta-variable expression must not have trailing tokens"); Err(diag) } else { @@ -86,7 +88,7 @@ fn check_trailing_token<'sess>(iter: &mut Cursor, sess: &'sess ParseSess) -> PRe /// Parse a meta-variable `count` expression: `count(ident[, depth])` fn parse_count<'sess>( - iter: &mut Cursor, + iter: &mut CursorRef<'_>, sess: &'sess ParseSess, span: Span, ) -> PResult<'sess, MetaVarExpr> { @@ -97,7 +99,7 @@ fn parse_count<'sess>( /// Parses the depth used by index(depth) and length(depth). fn parse_depth<'sess>( - iter: &mut Cursor, + iter: &mut CursorRef<'_>, sess: &'sess ParseSess, span: Span, ) -> PResult<'sess, usize> { @@ -110,7 +112,7 @@ fn parse_depth<'sess>( "meta-variable expression depth must be a literal" )); }; - if let Ok(lit_kind) = LitKind::from_lit_token(lit) + if let Ok(lit_kind) = LitKind::from_lit_token(*lit) && let LitKind::Int(n_u128, LitIntType::Unsuffixed) = lit_kind && let Ok(n_usize) = usize::try_from(n_u128) { @@ -124,7 +126,7 @@ fn parse_depth<'sess>( /// Parses an generic ident fn parse_ident<'sess>( - iter: &mut Cursor, + iter: &mut CursorRef<'_>, sess: &'sess ParseSess, span: Span, ) -> PResult<'sess, Ident> { @@ -132,7 +134,7 @@ fn parse_ident<'sess>( if let Some((elem, false)) = token.ident() { return Ok(elem); } - let token_str = pprust::token_to_string(&token); + let token_str = pprust::token_to_string(token); let mut err = sess.span_diagnostic.struct_span_err( span, &format!("expected identifier, found `{}`", &token_str) @@ -150,7 +152,7 @@ fn parse_ident<'sess>( /// Tries to move the iterator forward returning `true` if there is a comma. If not, then the /// iterator is not modified and the result is `false`. -fn try_eat_comma(iter: &mut Cursor) -> bool { +fn try_eat_comma(iter: &mut CursorRef<'_>) -> bool { if let Some(TokenTree::Token(token::Token { kind: token::Comma, .. })) = iter.look_ahead(0) { let _ = iter.next(); return true; diff --git a/compiler/rustc_expand/src/mbe/quoted.rs b/compiler/rustc_expand/src/mbe/quoted.rs index d52de24c393b7..707cb73f097f8 100644 --- a/compiler/rustc_expand/src/mbe/quoted.rs +++ b/compiler/rustc_expand/src/mbe/quoted.rs @@ -48,7 +48,7 @@ pub(super) fn parse( // For each token tree in `input`, parse the token into a `self::TokenTree`, consuming // additional trees if need be. - let mut trees = input.trees(); + let mut trees = input.into_trees(); while let Some(tree) = trees.next() { // Given the parsed tree, if there is a metavar and we are expecting matchers, actually // parse out the matcher (i.e., in `$id:ident` this would parse the `:` and `ident`). diff --git a/compiler/rustc_expand/src/module.rs b/compiler/rustc_expand/src/module.rs index 2a059f3519d1e..876faad33b678 100644 --- a/compiler/rustc_expand/src/module.rs +++ b/compiler/rustc_expand/src/module.rs @@ -26,7 +26,7 @@ pub struct ModulePathSuccess { pub dir_ownership: DirOwnership, } -crate struct ParsedExternalMod { +pub(crate) struct ParsedExternalMod { pub items: Vec>, pub spans: ModSpans, pub file_path: PathBuf, @@ -42,7 +42,7 @@ pub enum ModError<'a> { ParserError(DiagnosticBuilder<'a, ErrorGuaranteed>), } -crate fn parse_external_mod( +pub(crate) fn parse_external_mod( sess: &Session, ident: Ident, span: Span, // The span to blame on errors. @@ -78,7 +78,7 @@ crate fn parse_external_mod( ParsedExternalMod { items, spans, file_path, dir_path, dir_ownership } } -crate fn mod_dir_path( +pub(crate) fn mod_dir_path( sess: &Session, ident: Ident, attrs: &[Attribute], diff --git a/compiler/rustc_expand/src/parse/tests.rs b/compiler/rustc_expand/src/parse/tests.rs index 5d447d911e7f4..8da7879275895 100644 --- a/compiler/rustc_expand/src/parse/tests.rs +++ b/compiler/rustc_expand/src/parse/tests.rs @@ -61,7 +61,7 @@ fn bad_path_expr_1() { fn string_to_tts_macro() { create_default_session_globals_then(|| { let tts: Vec<_> = - string_to_stream("macro_rules! zip (($a)=>($a))".to_string()).trees().collect(); + string_to_stream("macro_rules! zip (($a)=>($a))".to_string()).into_trees().collect(); let tts: &[TokenTree] = &tts[..]; match tts { @@ -293,7 +293,7 @@ fn ttdelim_span() { .unwrap(); let tts: Vec<_> = match expr.kind { - ast::ExprKind::MacCall(ref mac) => mac.args.inner_tokens().trees().collect(), + ast::ExprKind::MacCall(ref mac) => mac.args.inner_tokens().into_trees().collect(), _ => panic!("not a macro"), }; diff --git a/compiler/rustc_expand/src/proc_macro.rs b/compiler/rustc_expand/src/proc_macro.rs index 6c74d462fb84c..9e1cd299fd60f 100644 --- a/compiler/rustc_expand/src/proc_macro.rs +++ b/compiler/rustc_expand/src/proc_macro.rs @@ -14,10 +14,10 @@ use rustc_span::{Span, DUMMY_SP}; const EXEC_STRATEGY: pm::bridge::server::SameThread = pm::bridge::server::SameThread; pub struct BangProcMacro { - pub client: pm::bridge::client::Client pm::TokenStream>, + pub client: pm::bridge::client::Client, } -impl base::ProcMacro for BangProcMacro { +impl base::BangProcMacro for BangProcMacro { fn expand<'cx>( &self, ecx: &'cx mut ExtCtxt<'_>, @@ -42,7 +42,7 @@ impl base::ProcMacro for BangProcMacro { } pub struct AttrProcMacro { - pub client: pm::bridge::client::Client pm::TokenStream>, + pub client: pm::bridge::client::Client<(pm::TokenStream, pm::TokenStream), pm::TokenStream>, } impl base::AttrProcMacro for AttrProcMacro { @@ -72,11 +72,11 @@ impl base::AttrProcMacro for AttrProcMacro { } } -pub struct ProcMacroDerive { - pub client: pm::bridge::client::Client pm::TokenStream>, +pub struct DeriveProcMacro { + pub client: pm::bridge::client::Client, } -impl MultiItemModifier for ProcMacroDerive { +impl MultiItemModifier for DeriveProcMacro { fn expand( &self, ecx: &mut ExtCtxt<'_>, @@ -96,7 +96,7 @@ impl MultiItemModifier for ProcMacroDerive { }; TokenTree::token(token::Interpolated(Lrc::new(nt)), DUMMY_SP).into() } else { - item.to_tokens(&ecx.sess.parse_sess) + item.to_tokens() }; let stream = { diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs index c0c786e4712e5..d4407c03d03f5 100644 --- a/compiler/rustc_expand/src/proc_macro_server.rs +++ b/compiler/rustc_expand/src/proc_macro_server.rs @@ -2,14 +2,13 @@ use crate::base::ExtCtxt; use rustc_ast as ast; use rustc_ast::token; -use rustc_ast::tokenstream::{self, CanSynthesizeMissingTokens}; -use rustc_ast::tokenstream::{DelimSpan, Spacing::*, TokenStream, TreeAndSpacing}; +use rustc_ast::tokenstream::{self, DelimSpan, Spacing::*, TokenStream, TreeAndSpacing}; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::Lrc; use rustc_errors::{Diagnostic, MultiSpan, PResult}; use rustc_parse::lexer::nfc_normalize; -use rustc_parse::{nt_to_tokenstream, parse_stream_from_source_str}; +use rustc_parse::parse_stream_from_source_str; use rustc_session::parse::ParseSess; use rustc_span::def_id::CrateNum; use rustc_span::symbol::{self, kw, sym, Symbol}; @@ -179,10 +178,9 @@ impl FromInternal<(TreeAndSpacing, &'_ mut Vec, &mut Rustc<'_, '_>)> TokenTree::Ident(Ident::new(rustc.sess(), ident.name, is_raw, ident.span)) } Interpolated(nt) => { - let stream = nt_to_tokenstream(&nt, rustc.sess(), CanSynthesizeMissingTokens::No); TokenTree::Group(Group { delimiter: pm::Delimiter::None, - stream, + stream: TokenStream::from_nonterminal_ast(&nt), span: DelimSpan::from_single(span), flatten: crate::base::nt_pretty_printing_compatibility_hack(&nt, rustc.sess()), }) @@ -454,7 +452,7 @@ impl server::TokenStream for Rustc<'_, '_> { // NOTE: For now, limit `expand_expr` to exclusively expand to literals. // This may be relaxed in the future. - // We don't use `nt_to_tokenstream` as the tokenstream currently cannot + // We don't use `TokenStream::from_ast` as the tokenstream currently cannot // be recovered in the general case. match &expr.kind { ast::ExprKind::Lit(l) => { @@ -484,7 +482,7 @@ impl server::TokenStream for Rustc<'_, '_> { tree.to_internal() } fn into_iter(&mut self, stream: Self::TokenStream) -> Self::TokenStreamIter { - TokenStreamIter { cursor: stream.trees(), stack: vec![] } + TokenStreamIter { cursor: stream.into_trees(), stack: vec![] } } } diff --git a/compiler/rustc_expand/src/tests.rs b/compiler/rustc_expand/src/tests.rs index 693159f9aec4a..8b7153776e4dc 100644 --- a/compiler/rustc_expand/src/tests.rs +++ b/compiler/rustc_expand/src/tests.rs @@ -22,7 +22,7 @@ fn string_to_parser(ps: &ParseSess, source_str: String) -> Parser<'_> { new_parser_from_source_str(ps, PathBuf::from("bogofile").into(), source_str) } -crate fn with_error_checking_parse<'a, T, F>(s: String, ps: &'a ParseSess, f: F) -> T +pub(crate) fn with_error_checking_parse<'a, T, F>(s: String, ps: &'a ParseSess, f: F) -> T where F: FnOnce(&mut Parser<'a>) -> PResult<'a, T>, { @@ -33,7 +33,7 @@ where } /// Maps a string to tts, using a made-up filename. -crate fn string_to_stream(source_str: String) -> TokenStream { +pub(crate) fn string_to_stream(source_str: String) -> TokenStream { let ps = ParseSess::new(FilePathMapping::empty()); source_file_to_stream( &ps, @@ -44,7 +44,7 @@ crate fn string_to_stream(source_str: String) -> TokenStream { } /// Parses a string, returns a crate. -crate fn string_to_crate(source_str: String) -> ast::Crate { +pub(crate) fn string_to_crate(source_str: String) -> ast::Crate { let ps = ParseSess::new(FilePathMapping::empty()); with_error_checking_parse(source_str, &ps, |p| p.parse_crate_mod()) } @@ -53,7 +53,7 @@ crate fn string_to_crate(source_str: String) -> ast::Crate { /// may be deleted or replaced with other whitespace to match the pattern. /// This function is relatively Unicode-ignorant; fortunately, the careful design /// of UTF-8 mitigates this ignorance. It doesn't do NKF-normalization(?). -crate fn matches_codepattern(a: &str, b: &str) -> bool { +pub(crate) fn matches_codepattern(a: &str, b: &str) -> bool { let mut a_iter = a.chars().peekable(); let mut b_iter = b.chars().peekable(); @@ -109,7 +109,7 @@ struct SpanLabel { label: &'static str, } -crate struct Shared { +pub(crate) struct Shared { pub data: Arc>, } diff --git a/compiler/rustc_expand/src/tokenstream/tests.rs b/compiler/rustc_expand/src/tokenstream/tests.rs index 31052bfb54ce8..270532f8edeec 100644 --- a/compiler/rustc_expand/src/tokenstream/tests.rs +++ b/compiler/rustc_expand/src/tokenstream/tests.rs @@ -35,7 +35,7 @@ fn test_concat() { fn test_to_from_bijection() { create_default_session_globals_then(|| { let test_start = string_to_ts("foo::bar(baz)"); - let test_end = test_start.trees().collect(); + let test_end = test_start.trees().cloned().collect(); assert_eq!(test_start, test_end) }) } diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index 520769d308e66..5a02661513ca7 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -319,6 +319,8 @@ declare_features! ( (active, cfg_sanitize, "1.41.0", Some(39699), None), /// Allows `cfg(target_abi = "...")`. (active, cfg_target_abi, "1.55.0", Some(80970), None), + /// Allows `cfg(target(abi = "..."))`. + (active, cfg_target_compact, "1.63.0", Some(96901), None), /// Allows `cfg(target_has_atomic_load_store = "...")`. (active, cfg_target_has_atomic, "1.60.0", Some(94039), None), /// Allows `cfg(target_has_atomic_equal_alignment = "...")`. @@ -351,8 +353,6 @@ declare_features! ( (active, const_trait_impl, "1.42.0", Some(67792), None), /// Allows the `?` operator in const contexts. (active, const_try, "1.56.0", Some(74935), None), - /// Allows using `crate` as visibility modifier, synonymous with `pub(crate)`. - (active, crate_visibility_modifier, "1.23.0", Some(53120), None), /// Allows non-builtin attributes in inner attribute position. (active, custom_inner_attributes, "1.30.0", Some(54726), None), /// Allows custom test frameworks with `#![test_runner]` and `#[test_case]`. diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 097493e8985fb..8155e65a6dbf5 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -399,7 +399,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ // RFC #3191: #[debugger_visualizer] support gated!( - debugger_visualizer, Normal, template!(List: r#"natvis_file = "...""#), + debugger_visualizer, Normal, template!(List: r#"natvis_file = "...", gdb_script_file = "...""#), DuplicatesOk, experimental!(debugger_visualizer) ), @@ -473,9 +473,10 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ ), // RFC 2632 gated!( - default_method_body_is_const, Normal, template!(Word), WarnFollowing, const_trait_impl, - "`default_method_body_is_const` is a temporary placeholder for declaring default bodies \ - as `const`, which may be removed or renamed in the future." + const_trait, Normal, template!(Word), WarnFollowing, const_trait_impl, + "`const` is a temporary placeholder for marking a trait that is suitable for `const` \ + `impls` and all default bodies as `const`, which may be removed or renamed in the \ + future." ), // lang-team MCP 147 gated!( diff --git a/compiler/rustc_feature/src/lib.rs b/compiler/rustc_feature/src/lib.rs index 26e0538b0eb4e..efb83052768bc 100644 --- a/compiler/rustc_feature/src/lib.rs +++ b/compiler/rustc_feature/src/lib.rs @@ -11,7 +11,6 @@ //! even if it is stabilized or removed, *do not remove it*. Instead, move the //! symbol to the `accepted` or `removed` modules respectively. -#![cfg_attr(bootstrap, feature(derive_default_enum))] #![feature(once_cell)] mod accepted; diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs index fae9bd633afff..b546662dc1496 100644 --- a/compiler/rustc_feature/src/removed.rs +++ b/compiler/rustc_feature/src/removed.rs @@ -72,6 +72,8 @@ declare_features! ( /// Allows `T: ?const Trait` syntax in bounds. (removed, const_trait_bound_opt_out, "1.42.0", Some(67794), None, Some("Removed in favor of `~const` bound in #![feature(const_trait_impl)]")), + /// Allows using `crate` as visibility modifier, synonymous with `pub(crate)`. + (removed, crate_visibility_modifier, "1.63.0", Some(53120), None, Some("removed in favor of `pub(crate)`")), /// Allows using custom attributes (RFC 572). (removed, custom_attribute, "1.0.0", Some(29642), None, Some("removed in favor of `#![register_tool]` and `#![register_attr]`")), diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs index a639df01a78d4..68876e89c4b1f 100644 --- a/compiler/rustc_hir/src/def.rs +++ b/compiler/rustc_hir/src/def.rs @@ -92,6 +92,7 @@ pub enum DefKind { /// [RFC 2593]: https://github.com/rust-lang/rfcs/pull/2593 Ctor(CtorOf, CtorKind), /// Associated function: `impl MyStruct { fn associated() {} }` + /// or `trait Foo { fn associated() {} }` AssocFn, /// Associated constant: `trait MyTrait { const ASSOC: usize; }` AssocConst, diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 4d4d4a28499af..bda7affe52983 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1,6 +1,6 @@ use crate::def::{CtorKind, DefKind, Res}; use crate::def_id::DefId; -crate use crate::hir_id::{HirId, ItemLocalId}; +pub(crate) use crate::hir_id::{HirId, ItemLocalId}; use crate::intravisit::FnKind; use crate::LangItem; @@ -343,12 +343,12 @@ pub struct GenericArgs<'hir> { pub span_ext: Span, } -impl GenericArgs<'_> { +impl<'hir> GenericArgs<'hir> { pub const fn none() -> Self { Self { args: &[], bindings: &[], parenthesized: false, span_ext: DUMMY_SP } } - pub fn inputs(&self) -> &[Ty<'_>] { + pub fn inputs(&self) -> &[Ty<'hir>] { if self.parenthesized { for arg in self.args { match arg { @@ -549,7 +549,7 @@ impl<'hir> Generics<'hir> { &NOPE } - pub fn get_named(&self, name: Symbol) -> Option<&GenericParam<'_>> { + pub fn get_named(&self, name: Symbol) -> Option<&GenericParam<'hir>> { for param in self.params { if name == param.name.ident().name { return Some(param); @@ -608,7 +608,7 @@ impl<'hir> Generics<'hir> { pub fn bounds_for_param( &self, param_def_id: LocalDefId, - ) -> impl Iterator> { + ) -> impl Iterator> { self.predicates.iter().filter_map(move |pred| match pred { WherePredicate::BoundPredicate(bp) if bp.is_param_bound(param_def_id.to_def_id()) => { Some(bp) @@ -796,7 +796,6 @@ impl<'tcx> AttributeMap<'tcx> { /// Map of all HIR nodes inside the current owner. /// These nodes are mapped by `ItemLocalId` alongside the index of their parent node. /// The HIR tree, including bodies, is pre-hashed. -#[derive(Debug)] pub struct OwnerNodes<'tcx> { /// Pre-computed hash of the full HIR. pub hash_including_bodies: Fingerprint, @@ -822,6 +821,18 @@ impl<'tcx> OwnerNodes<'tcx> { } } +impl fmt::Debug for OwnerNodes<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("OwnerNodes") + .field("node", &self.nodes[ItemLocalId::from_u32(0)]) + .field("bodies", &self.bodies) + .field("local_id_to_def_id", &self.local_id_to_def_id) + .field("hash_without_bodies", &self.hash_without_bodies) + .field("hash_including_bodies", &self.hash_including_bodies) + .finish() + } +} + /// Full information resulting from lowering an AST node. #[derive(Debug, HashStable_Generic)] pub struct OwnerInfo<'hir> { @@ -1320,8 +1331,21 @@ pub struct Let<'hir> { #[derive(Debug, HashStable_Generic)] pub enum Guard<'hir> { If(&'hir Expr<'hir>), - // FIXME use hir::Let for this. - IfLet(&'hir Pat<'hir>, &'hir Expr<'hir>), + IfLet(&'hir Let<'hir>), +} + +impl<'hir> Guard<'hir> { + /// Returns the body of the guard + /// + /// In other words, returns the e in either of the following: + /// + /// - `if e` + /// - `if let x = e` + pub fn body(&self) -> &'hir Expr<'hir> { + match self { + Guard::If(e) | Guard::IfLet(Let { init: e, .. }) => e, + } + } } #[derive(Debug, HashStable_Generic)] @@ -1346,7 +1370,7 @@ pub enum UnsafeSource { UserProvided, } -#[derive(Copy, Clone, PartialEq, Eq, Encodable, Hash, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Hash, Debug)] pub struct BodyId { pub hir_id: HirId, } @@ -2129,7 +2153,7 @@ pub struct FnSig<'hir> { // The bodies for items are stored "out of line", in a separate // hashmap in the `Crate`. Here we just record the hir-id of the item // so it can fetched later. -#[derive(Copy, Clone, PartialEq, Eq, Encodable, Debug, HashStable_Generic)] +#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug, HashStable_Generic)] pub struct TraitItemId { pub def_id: LocalDefId, } @@ -2192,7 +2216,7 @@ pub enum TraitItemKind<'hir> { // The bodies for items are stored "out of line", in a separate // hashmap in the `Crate`. Here we just record the hir-id of the item // so it can fetched later. -#[derive(Copy, Clone, PartialEq, Eq, Encodable, Debug, HashStable_Generic)] +#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug, HashStable_Generic)] pub struct ImplItemId { pub def_id: LocalDefId, } @@ -2787,7 +2811,7 @@ impl<'hir> VariantData<'hir> { // The bodies for items are stored "out of line", in a separate // hashmap in the `Crate`. Here we just record the hir-id of the item // so it can fetched later. -#[derive(Copy, Clone, PartialEq, Eq, Encodable, Debug, Hash, HashStable_Generic)] +#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug, Hash, HashStable_Generic)] pub struct ItemId { pub def_id: LocalDefId, } @@ -3034,7 +3058,7 @@ pub enum AssocItemKind { // The bodies for items are stored "out of line", in a separate // hashmap in the `Crate`. Here we just record the hir-id of the item // so it can fetched later. -#[derive(Copy, Clone, PartialEq, Eq, Encodable, Debug, HashStable_Generic)] +#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug, HashStable_Generic)] pub struct ForeignItemId { pub def_id: LocalDefId, } diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 977c0eb3cd2bc..5b83a29bb33c3 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -1,7 +1,40 @@ //! HIR walker for walking the contents of nodes. //! -//! **For an overview of the visitor strategy, see the docs on the -//! `super::itemlikevisit::ItemLikeVisitor` trait.** +//! Here are the three available patterns for the visitor strategy, +//! in roughly the order of desirability: +//! +//! 1. **Shallow visit**: Get a simple callback for every item (or item-like thing) in the HIR. +//! - Example: find all items with a `#[foo]` attribute on them. +//! - How: Use the `hir_crate_items` or `hir_module_items` query to traverse over item-like ids +//! (ItemId, TraitItemId, etc.) and use tcx.def_kind and `tcx.hir().item*(id)` to filter and +//! access actual item-like thing, respectively. +//! - Pro: Efficient; just walks the lists of item ids and gives users control whether to access +//! the hir_owners themselves or not. +//! - Con: Don't get information about nesting +//! - Con: Don't have methods for specific bits of HIR, like "on +//! every expr, do this". +//! 2. **Deep visit**: Want to scan for specific kinds of HIR nodes within +//! an item, but don't care about how item-like things are nested +//! within one another. +//! - Example: Examine each expression to look for its type and do some check or other. +//! - How: Implement `intravisit::Visitor` and override the `NestedFilter` type to +//! `nested_filter::OnlyBodies` (and implement `nested_visit_map`), and use +//! `tcx.hir().deep_visit_all_item_likes(&mut visitor)`. Within your +//! `intravisit::Visitor` impl, implement methods like `visit_expr()` (don't forget to invoke +//! `intravisit::walk_expr()` to keep walking the subparts). +//! - Pro: Visitor methods for any kind of HIR node, not just item-like things. +//! - Pro: Integrates well into dependency tracking. +//! - Con: Don't get information about nesting between items +//! 3. **Nested visit**: Want to visit the whole HIR and you care about the nesting between +//! item-like things. +//! - Example: Lifetime resolution, which wants to bring lifetimes declared on the +//! impl into scope while visiting the impl-items, and then back out again. +//! - How: Implement `intravisit::Visitor` and override the `NestedFilter` type to +//! `nested_filter::All` (and implement `nested_visit_map`). Walk your crate with +//! `tcx.hir().walk_toplevel_module(visitor)` invoked on `tcx.hir().krate()`. +//! - Pro: Visitor methods for any kind of HIR node, not just item-like things. +//! - Pro: Preserves nesting information +//! - Con: Does not integrate well into dependency tracking. //! //! If you have decided to use this visitor, here are some general //! notes on how to do so: @@ -32,43 +65,12 @@ //! example generator inference, and possibly also HIR borrowck. use crate::hir::*; -use crate::itemlikevisit::{ItemLikeVisitor, ParItemLikeVisitor}; +use crate::itemlikevisit::ParItemLikeVisitor; use rustc_ast::walk_list; use rustc_ast::{Attribute, Label}; use rustc_span::symbol::{Ident, Symbol}; use rustc_span::Span; -pub struct DeepVisitor<'v, V> { - visitor: &'v mut V, -} - -impl<'v, V> DeepVisitor<'v, V> { - pub fn new(base: &'v mut V) -> Self { - DeepVisitor { visitor: base } - } -} - -impl<'v, 'hir, V> ItemLikeVisitor<'hir> for DeepVisitor<'v, V> -where - V: Visitor<'hir>, -{ - fn visit_item(&mut self, item: &'hir Item<'hir>) { - self.visitor.visit_item(item); - } - - fn visit_trait_item(&mut self, trait_item: &'hir TraitItem<'hir>) { - self.visitor.visit_trait_item(trait_item); - } - - fn visit_impl_item(&mut self, impl_item: &'hir ImplItem<'hir>) { - self.visitor.visit_impl_item(impl_item); - } - - fn visit_foreign_item(&mut self, foreign_item: &'hir ForeignItem<'hir>) { - self.visitor.visit_foreign_item(foreign_item); - } -} - pub trait IntoVisitor<'hir> { type Visitor: Visitor<'hir>; fn into_visitor(&self) -> Self::Visitor; @@ -315,16 +317,6 @@ pub trait Visitor<'v>: Sized { walk_body(self, b); } - /// When invoking `visit_all_item_likes()`, you need to supply an - /// item-like visitor. This method converts an "intra-visit" - /// visitor into an item-like visitor that walks the entire tree. - /// If you use this, you probably don't want to process the - /// contents of nested item-like things, since the outer loop will - /// visit them as well. - fn as_deep_visitor(&mut self) -> DeepVisitor<'_, Self> { - DeepVisitor::new(self) - } - /////////////////////////////////////////////////////////////////////////// fn visit_id(&mut self, _hir_id: HirId) { @@ -1233,9 +1225,8 @@ pub fn walk_arm<'v, V: Visitor<'v>>(visitor: &mut V, arm: &'v Arm<'v>) { if let Some(ref g) = arm.guard { match g { Guard::If(ref e) => visitor.visit_expr(e), - Guard::IfLet(ref pat, ref e) => { - visitor.visit_pat(pat); - visitor.visit_expr(e); + Guard::IfLet(ref l) => { + visitor.visit_let_expr(l); } } } diff --git a/compiler/rustc_hir/src/itemlikevisit.rs b/compiler/rustc_hir/src/itemlikevisit.rs index b2c6ca1354f10..a490268dc9f94 100644 --- a/compiler/rustc_hir/src/itemlikevisit.rs +++ b/compiler/rustc_hir/src/itemlikevisit.rs @@ -1,55 +1,5 @@ use super::{ForeignItem, ImplItem, Item, TraitItem}; -/// The "item-like visitor" defines only the top-level methods -/// that can be invoked by `Crate::visit_all_item_likes()`. Whether -/// this trait is the right one to implement will depend on the -/// overall pattern you need. Here are the three available patterns, -/// in roughly the order of desirability: -/// -/// 1. **Shallow visit**: Get a simple callback for every item (or item-like thing) in the HIR. -/// - Example: find all items with a `#[foo]` attribute on them. -/// - How: Implement `ItemLikeVisitor` and call `tcx.hir().visit_all_item_likes()`. -/// - Pro: Efficient; just walks the lists of item-like things, not the nodes themselves. -/// - Con: Don't get information about nesting -/// - Con: Don't have methods for specific bits of HIR, like "on -/// every expr, do this". -/// 2. **Deep visit**: Want to scan for specific kinds of HIR nodes within -/// an item, but don't care about how item-like things are nested -/// within one another. -/// - Example: Examine each expression to look for its type and do some check or other. -/// - How: Implement `intravisit::Visitor` and override the `NestedFilter` type to -/// `nested_filter::OnlyBodies` (and implement `nested_visit_map`), and use -/// `tcx.hir().visit_all_item_likes(&mut visitor.as_deep_visitor())`. Within your -/// `intravisit::Visitor` impl, implement methods like `visit_expr()` (don't forget to invoke -/// `intravisit::walk_expr()` to keep walking the subparts). -/// - Pro: Visitor methods for any kind of HIR node, not just item-like things. -/// - Pro: Integrates well into dependency tracking. -/// - Con: Don't get information about nesting between items -/// 3. **Nested visit**: Want to visit the whole HIR and you care about the nesting between -/// item-like things. -/// - Example: Lifetime resolution, which wants to bring lifetimes declared on the -/// impl into scope while visiting the impl-items, and then back out again. -/// - How: Implement `intravisit::Visitor` and override the `NestedFilter` type to -/// `nested_filter::All` (and implement `nested_visit_map`). Walk your crate with -/// `tcx.hir().walk_toplevel_module(visitor)` invoked on `tcx.hir().krate()`. -/// - Pro: Visitor methods for any kind of HIR node, not just item-like things. -/// - Pro: Preserves nesting information -/// - Con: Does not integrate well into dependency tracking. -/// -/// Note: the methods of `ItemLikeVisitor` intentionally have no -/// defaults, so that as we expand the list of item-like things, we -/// revisit the various visitors to see if they need to change. This -/// is harder to do with `intravisit::Visitor`, so when you add a new -/// `visit_nested_foo()` method, it is recommended that you search for -/// existing `fn visit_nested` methods to see where changes are -/// needed. -pub trait ItemLikeVisitor<'hir> { - fn visit_item(&mut self, item: &'hir Item<'hir>); - fn visit_trait_item(&mut self, trait_item: &'hir TraitItem<'hir>); - fn visit_impl_item(&mut self, impl_item: &'hir ImplItem<'hir>); - fn visit_foreign_item(&mut self, foreign_item: &'hir ForeignItem<'hir>); -} - /// A parallel variant of `ItemLikeVisitor`. pub trait ParItemLikeVisitor<'hir> { fn visit_item(&self, item: &'hir Item<'hir>); diff --git a/compiler/rustc_hir/src/lib.rs b/compiler/rustc_hir/src/lib.rs index d56230e1dc57d..7833571f88d43 100644 --- a/compiler/rustc_hir/src/lib.rs +++ b/compiler/rustc_hir/src/lib.rs @@ -4,7 +4,6 @@ #![feature(associated_type_defaults)] #![feature(const_btree_new)] -#![feature(crate_visibility_modifier)] #![feature(let_else)] #![feature(once_cell)] #![feature(min_specialization)] diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 7af9622b2cf76..4558a3d10c4fb 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -1915,14 +1915,9 @@ impl<'a> State<'a> { self.print_expr(&e); self.space(); } - hir::Guard::IfLet(pat, e) => { + hir::Guard::IfLet(hir::Let { pat, ty, init, .. }) => { self.word_nbsp("if"); - self.word_nbsp("let"); - self.print_pat(&pat); - self.space(); - self.word_space("="); - self.print_expr(&e); - self.space(); + self.print_let(pat, *ty, init); } } } diff --git a/compiler/rustc_incremental/src/assert_dep_graph.rs b/compiler/rustc_incremental/src/assert_dep_graph.rs index f69ae8ebe410f..a89b9eafaa62d 100644 --- a/compiler/rustc_incremental/src/assert_dep_graph.rs +++ b/compiler/rustc_incremental/src/assert_dep_graph.rs @@ -75,7 +75,7 @@ pub fn assert_dep_graph(tcx: TyCtxt<'_>) { let mut visitor = IfThisChanged { tcx, if_this_changed: vec![], then_this_would_need: vec![] }; visitor.process_attrs(hir::CRATE_HIR_ID); - tcx.hir().visit_all_item_likes(&mut visitor.as_deep_visitor()); + tcx.hir().deep_visit_all_item_likes(&mut visitor); (visitor.if_this_changed, visitor.then_this_would_need) }; diff --git a/compiler/rustc_index/src/vec.rs b/compiler/rustc_index/src/vec.rs index 4656994ac0869..a8c611e18ff39 100644 --- a/compiler/rustc_index/src/vec.rs +++ b/compiler/rustc_index/src/vec.rs @@ -65,12 +65,6 @@ impl> Encodable for IndexVec { } } -impl> Encodable for &IndexVec { - fn encode(&self, s: &mut S) -> Result<(), S::Error> { - Encodable::encode(&self.raw, s) - } -} - impl> Decodable for IndexVec { fn decode(d: &mut D) -> Self { IndexVec { raw: Decodable::decode(d), _marker: PhantomData } diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs index aa3f0600cccc8..534106ac446cf 100644 --- a/compiler/rustc_infer/src/infer/combine.rs +++ b/compiler/rustc_infer/src/infer/combine.rs @@ -776,21 +776,6 @@ pub trait ConstEquateRelation<'tcx>: TypeRelation<'tcx> { fn const_equate_obligation(&mut self, a: ty::Const<'tcx>, b: ty::Const<'tcx>); } -pub trait RelateResultCompare<'tcx, T> { - fn compare(&self, t: T, f: F) -> RelateResult<'tcx, T> - where - F: FnOnce() -> TypeError<'tcx>; -} - -impl<'tcx, T: Clone + PartialEq> RelateResultCompare<'tcx, T> for RelateResult<'tcx, T> { - fn compare(&self, t: T, f: F) -> RelateResult<'tcx, T> - where - F: FnOnce() -> TypeError<'tcx>, - { - self.clone().and_then(|s| if s == t { self.clone() } else { Err(f()) }) - } -} - pub fn const_unification_error<'tcx>( a_is_expected: bool, (a, b): (ty::Const<'tcx>, ty::Const<'tcx>), diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 02caae7a90a91..e156930cc89fd 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -609,7 +609,14 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { if !matches!(ty.kind(), ty::Infer(ty::InferTy::TyVar(_) | ty::InferTy::FreshTy(_))) { // don't show type `_` - err.span_label(span, format!("this expression has type `{}`", ty)); + if span.desugaring_kind() == Some(DesugaringKind::ForLoop) + && let ty::Adt(def, substs) = ty.kind() + && Some(def.did()) == self.tcx.get_diagnostic_item(sym::Option) + { + err.span_label(span, format!("this is an iterator with items of type `{}`", substs.type_at(0))); + } else { + err.span_label(span, format!("this expression has type `{}`", ty)); + } } if let Some(ty::error::ExpectedFound { found, .. }) = exp_found && ty.is_box() && ty.boxed_ty() == found @@ -1442,6 +1449,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { /// the message in `secondary_span` as the primary label, and apply the message that would /// otherwise be used for the primary label on the `secondary_span` `Span`. This applies on /// E0271, like `src/test/ui/issues/issue-39970.stderr`. + #[tracing::instrument( + level = "debug", + skip(self, diag, secondary_span, swap_secondary_and_primary, force_label) + )] pub fn note_type_err( &self, diag: &mut Diagnostic, @@ -1453,7 +1464,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { force_label: bool, ) { let span = cause.span(self.tcx); - debug!("note_type_err cause={:?} values={:?}, terr={:?}", cause, values, terr); // For some types of errors, expected-found does not make // sense, so just ignore the values we were given. @@ -1621,9 +1631,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } }; - // Ignore msg for object safe coercion - // since E0038 message will be printed match terr { + // Ignore msg for object safe coercion + // since E0038 message will be printed TypeError::ObjectUnsafeCoercion(_) => {} _ => { let mut label_or_note = |span: Span, msg: &str| { @@ -1774,6 +1784,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // It reads better to have the error origin as the final // thing. self.note_error_origin(diag, cause, exp_found, terr); + + debug!(?diag); } fn suggest_tuple_pattern( diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs index 62edfc6495cf6..e1a2a237c2324 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs @@ -866,6 +866,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } } + self.report_ambiguous_type_parameter(&mut err, arg); err.span_label( span, arg_data.cannot_infer_msg(use_diag.filter(|d| d.applies_to(span))), @@ -933,6 +934,28 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } } + fn report_ambiguous_type_parameter(&self, err: &mut Diagnostic, arg: GenericArg<'tcx>) { + if let GenericArgKind::Type(ty) = arg.unpack() + && let ty::Infer(ty::TyVar(ty_vid)) = *ty.kind() + { + let mut inner = self.inner.borrow_mut(); + let ty_vars = &inner.type_variables(); + let var_origin = ty_vars.var_origin(ty_vid); + if let TypeVariableOriginKind::TypeParameterDefinition(_, Some(def_id)) = + var_origin.kind + && let Some(parent_def_id) = self.tcx.parent(def_id).as_local() + && let Some(node) = self.tcx.hir().find_by_def_id(parent_def_id) + { + match node { + hir::Node::Item(item) if matches!(item.kind, hir::ItemKind::Impl(_) | hir::ItemKind::Fn(..)) => (), + hir::Node::ImplItem(impl_item) if matches!(impl_item.kind, hir::ImplItemKind::Fn(..)) => (), + _ => return, + } + err.span_help(self.tcx.def_span(def_id), "type parameter declared here"); + } + } + } + pub fn need_type_info_err_in_generator( &self, kind: hir::GeneratorKind, diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs index 9948d15c43115..53d9acf7d2908 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs @@ -16,7 +16,7 @@ mod util; pub use different_lifetimes::suggest_adding_lifetime_params; pub use find_anon_type::find_anon_type; -pub use static_impl_trait::suggest_new_region_bound; +pub use static_impl_trait::{suggest_new_region_bound, HirTraitObjectVisitor, TraitObjectVisitor}; pub use util::find_param_with_region; impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs index a4c46d5cf0ba2..1081f888f7ff3 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -546,7 +546,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { } /// Collect all the trait objects in a type that could have received an implicit `'static` lifetime. -pub(super) struct TraitObjectVisitor(pub(super) FxHashSet); +pub struct TraitObjectVisitor(pub FxHashSet); impl<'tcx> TypeVisitor<'tcx> for TraitObjectVisitor { fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { @@ -563,7 +563,7 @@ impl<'tcx> TypeVisitor<'tcx> for TraitObjectVisitor { } /// Collect all `hir::Ty<'_>` `Span`s for trait objects with an implicit lifetime. -pub(super) struct HirTraitObjectVisitor<'a>(pub(super) &'a mut Vec, pub(super) DefId); +pub struct HirTraitObjectVisitor<'a>(pub &'a mut Vec, pub DefId); impl<'a, 'tcx> Visitor<'tcx> for HirTraitObjectVisitor<'a> { fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx>) { diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs index da03d944ceb77..96b57b6cd2055 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs @@ -34,6 +34,7 @@ pub struct AnonymousParamInfo<'tcx> { // i32, which is the type of y but with the anonymous region replaced // with 'a, the corresponding bound region and is_first which is true if // the hir::Param is the first parameter in the function declaration. +#[instrument(skip(tcx), level = "debug")] pub fn find_param_with_region<'tcx>( tcx: TyCtxt<'tcx>, anon_region: Region<'tcx>, @@ -51,9 +52,19 @@ pub fn find_param_with_region<'tcx>( let hir_id = hir.local_def_id_to_hir_id(id.as_local()?); let body_id = hir.maybe_body_owned_by(hir_id)?; let body = hir.body(body_id); + + // Don't perform this on closures + match hir.get(hir_id) { + hir::Node::Expr(&hir::Expr { kind: hir::ExprKind::Closure(..), .. }) => { + return None; + } + _ => {} + } + let owner_id = hir.body_owner(body_id); let fn_decl = hir.fn_decl_by_hir_id(owner_id).unwrap(); let poly_fn_sig = tcx.fn_sig(id); + let fn_sig = tcx.liberate_late_bound_regions(id, poly_fn_sig); body.params .iter() @@ -98,7 +109,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { &self, anon_region: Region<'tcx>, replace_region: Region<'tcx>, - ) -> Option> { + ) -> Option> { find_param_with_region(self.tcx(), anon_region, replace_region) } diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index c9121f7d348ce..4ef6f240c4808 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -181,7 +181,7 @@ pub struct InferCtxtInner<'tcx> { /// /// Before running `resolve_regions_and_report_errors`, the creator /// of the inference context is expected to invoke - /// `process_region_obligations` (defined in `self::region_obligations`) + /// [`InferCtxt::process_registered_region_obligations`] /// for each body-id in this map, which will process the /// obligations within. This is expected to be done 'late enough' /// that all type inference variables have been bound and so forth. diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs index 94a795f613e9d..6592e0ae8ec8f 100644 --- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs +++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs @@ -859,7 +859,7 @@ where delegate: &'me mut D, - /// After we generalize this type, we are going to relative it to + /// After we generalize this type, we are going to relate it to /// some other type. What will be the variance at this point? ambient_variance: ty::Variance, diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs index 19d03ffa6964a..80b3e00059581 100644 --- a/compiler/rustc_infer/src/infer/outlives/obligations.rs +++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs @@ -62,17 +62,22 @@ use crate::infer::outlives::components::{push_outlives_components, Component}; use crate::infer::outlives::env::RegionBoundPairs; use crate::infer::outlives::verify::VerifyBoundCx; +use crate::infer::traits::{Obligation, PredicateObligation}; +use crate::infer::LateBoundRegionConversionTime; use crate::infer::{ self, GenericKind, InferCtxt, RegionObligation, SubregionOrigin, UndoLog, VerifyBound, }; use crate::traits::{ObligationCause, ObligationCauseCode}; use rustc_middle::ty::subst::GenericArgKind; +use rustc_middle::ty::subst::InternalSubsts; +use rustc_middle::ty::ToPredicate; use rustc_middle::ty::{self, Region, Ty, TyCtxt, TypeFoldable}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::undo_log::UndoLogs; use rustc_hir as hir; use smallvec::smallvec; +use std::iter; impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { /// Registers that the given region obligation must be resolved @@ -136,7 +141,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { /// /// # Parameters /// - /// - `region_bound_pairs`: the set of region bounds implied by + /// - `region_bound_pairs_map`: the set of region bounds implied by /// the parameters and where-clauses. In particular, each pair /// `('a, K)` in this list tells us that the bounds in scope /// indicate that `K: 'a`, where `K` is either a generic @@ -147,12 +152,6 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { /// - `param_env` is the parameter environment for the enclosing function. /// - `body_id` is the body-id whose region obligations are being /// processed. - /// - /// # Returns - /// - /// This function may have to perform normalizations, and hence it - /// returns an `InferOk` with subobligations that must be - /// processed. #[instrument(level = "debug", skip(self, region_bound_pairs_map))] pub fn process_registered_region_obligations( &self, @@ -192,6 +191,150 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { } } } + + pub fn nested_outlives_obligations( + &self, + cause: &ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, + ty: Ty<'tcx>, + region: ty::Region<'tcx>, + ) -> Vec> { + let to_obligation = |pred: ty::Binder<'tcx, ty::PredicateKind<'tcx>>| { + Obligation::new(cause.clone(), param_env, pred.to_predicate(self.tcx)) + }; + let ty_outlives = |ty| { + to_obligation(ty::Binder::dummy(ty::PredicateKind::TypeOutlives( + ty::OutlivesPredicate(ty, region), + ))) + }; + let reg_outlives = |reg| { + to_obligation(ty::Binder::dummy(ty::PredicateKind::RegionOutlives( + ty::OutlivesPredicate(reg, region), + ))) + }; + match ty.kind() { + ty::Infer(..) | ty::Bound(..) => bug!("unexpected type: {:?}", ty), + ty::FnDef(_, substs) => { + substs + .iter() + .filter_map(|arg| match arg.unpack() { + GenericArgKind::Type(ty) => Some(ty_outlives(ty)), + GenericArgKind::Lifetime(_) => { + // HACK(eddyb) ignore lifetimes found shallowly in `substs`. + // This is inconsistent with `ty::Adt` (including all substs) + // and with `ty::Closure` (ignoring all substs other than + // upvars, of which a `ty::FnDef` doesn't have any), but + // consistent with previous (accidental) behavior. + // See https://github.com/rust-lang/rust/issues/70917 + // for further background and discussion. + None + } + GenericArgKind::Const(_) => None, + }) + .collect() + } + + &ty::Ref(re, ty, _) => { + vec![reg_outlives(re), ty_outlives(ty)] + } + + &ty::RawPtr(ty::TypeAndMut { ty, mutbl: _ }) | &ty::Slice(ty) | &ty::Array(ty, _) => { + vec![ty_outlives(ty)] + } + + ty::Closure(_, substs) => { + let tupled_ty = substs.as_closure().tupled_upvars_ty(); + vec![ty_outlives(tupled_ty)] + } + + ty::Generator(_, substs, _) => { + let tupled_ty = substs.as_generator().tupled_upvars_ty(); + vec![ty_outlives(tupled_ty)] + } + + // All regions are bound inside a witness + ty::GeneratorWitness(..) => vec![], + + // FIXME: These two should ideally happen eagerly here, but + // require some kind of `Any` bound which we don't have yet. + ty::Param(_) | ty::Projection(_) => { + self.register_region_obligation_with_cause(ty, region, cause); + vec![] + } + &ty::Projection(_) => { + self.register_region_obligation_with_cause(ty, region, cause); + vec![] + } + + // Trivial types + ty::Bool + | ty::Char + | ty::Int(..) + | ty::Uint(..) + | ty::Float(..) + | ty::Never + | ty::Str + | ty::Foreign(..) => vec![], + + ty::Adt(_, substs) | ty::Opaque(_, substs) => substs + .iter() + .filter_map(|arg| match arg.unpack() { + GenericArgKind::Lifetime(re) => Some(reg_outlives(re)), + GenericArgKind::Type(ty) => Some(ty_outlives(ty)), + GenericArgKind::Const(_) => None, + }) + .collect(), + + ty::Tuple(fields) => fields.iter().map(|ty| ty_outlives(ty)).collect(), + + &ty::FnPtr(data) => { + let (data, _) = self.replace_bound_vars_with_fresh_vars( + cause.span, + LateBoundRegionConversionTime::HigherRankedType, + data, + ); + data.inputs_and_output.iter().map(|ty| ty_outlives(ty)).collect() + } + + &ty::Dynamic(traits, region) => traits + .iter() + .flat_map(|predicate| { + let (predicate, _) = self.replace_bound_vars_with_fresh_vars( + cause.span, + LateBoundRegionConversionTime::HigherRankedType, + predicate, + ); + let (substs, opt_ty) = match predicate { + ty::ExistentialPredicate::Trait(tr) => (tr.substs, None), + ty::ExistentialPredicate::Projection(p) => (p.substs, Some(p.term)), + ty::ExistentialPredicate::AutoTrait(_) => (InternalSubsts::empty(), None), + }; + + substs + .iter() + .rev() + .chain(opt_ty.map(|term| match term { + ty::Term::Ty(ty) => ty.into(), + ty::Term::Const(ct) => ct.into(), + })) + .map(move |arg| arg) + }) + .filter_map(|arg| match arg.unpack() { + GenericArgKind::Lifetime(re) => Some(reg_outlives(re)), + GenericArgKind::Type(ty) => Some(ty_outlives(ty)), + GenericArgKind::Const(_) => None, + }) + .chain(iter::once(reg_outlives(region))) + .collect(), + + // FIXME: The way we deal with placeholders is wrong for now. + // + // Have to check for bounds in the `param_env`. + ty::Placeholder(..) => vec![], + + ty::Error(_) => vec![], + } + } } /// The `TypeOutlives` struct has the job of "lowering" a `T: 'a` diff --git a/compiler/rustc_infer/src/lib.rs b/compiler/rustc_infer/src/lib.rs index 4c691c25189d9..0f13a9b138800 100644 --- a/compiler/rustc_infer/src/lib.rs +++ b/compiler/rustc_infer/src/lib.rs @@ -16,7 +16,6 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(box_patterns)] #![feature(control_flow_enum)] -#![cfg_attr(bootstrap, feature(derive_default_enum))] #![feature(extend_one)] #![feature(label_break_value)] #![feature(let_chains)] diff --git a/compiler/rustc_infer/src/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs index 85bb727a6c804..4df4de21a0f07 100644 --- a/compiler/rustc_infer/src/traits/mod.rs +++ b/compiler/rustc_infer/src/traits/mod.rs @@ -69,7 +69,7 @@ impl<'tcx> PredicateObligation<'tcx> { } } -impl TraitObligation<'_> { +impl<'tcx> TraitObligation<'tcx> { /// Returns `true` if the trait predicate is considered `const` in its ParamEnv. pub fn is_const(&self) -> bool { match (self.predicate.skip_binder().constness, self.param_env.constness()) { @@ -77,6 +77,13 @@ impl TraitObligation<'_> { _ => false, } } + + pub fn derived_cause( + &self, + variant: impl FnOnce(DerivedObligationCause<'tcx>) -> ObligationCauseCode<'tcx>, + ) -> ObligationCause<'tcx> { + self.cause.clone().derived_cause(self.predicate, variant) + } } // `PredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger. diff --git a/compiler/rustc_interface/Cargo.toml b/compiler/rustc_interface/Cargo.toml index 29d1cd0e05467..47dc5f2ef8670 100644 --- a/compiler/rustc_interface/Cargo.toml +++ b/compiler/rustc_interface/Cargo.toml @@ -10,8 +10,8 @@ doctest = false libc = "0.2" libloading = "0.7.1" tracing = "0.1" -rustc-rayon-core = { version = "0.3.2", optional = true } -rayon = { version = "0.3.2", package = "rustc-rayon", optional = true } +rustc-rayon-core = { version = "0.4.0", optional = true } +rayon = { version = "0.4.0", package = "rustc-rayon", optional = true } smallvec = { version = "1.6.1", features = ["union", "may_dangle"] } rustc_ast = { path = "../rustc_ast" } rustc_attr = { path = "../rustc_attr" } diff --git a/compiler/rustc_interface/src/callbacks.rs b/compiler/rustc_interface/src/callbacks.rs index a18e2d1d63887..76442de69d351 100644 --- a/compiler/rustc_interface/src/callbacks.rs +++ b/compiler/rustc_interface/src/callbacks.rs @@ -24,7 +24,7 @@ fn track_span_parent(def_id: rustc_span::def_id::LocalDefId) { } /// This is a callback from `rustc_ast` as it cannot access the implicit state -/// in `rustc_middle` otherwise. It is used to when diagnostic messages are +/// in `rustc_middle` otherwise. It is used when diagnostic messages are /// emitted and stores them in the current query, if there is one. fn track_diagnostic(diagnostic: &Diagnostic) { tls::with_context_opt(|icx| { diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 00119267e8561..e6c9c6693c5ab 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -494,13 +494,7 @@ pub fn lower_to_hir<'res, 'tcx>( arena: &'tcx rustc_ast_lowering::Arena<'tcx>, ) -> &'tcx Crate<'tcx> { // Lower AST to HIR. - let hir_crate = rustc_ast_lowering::lower_crate( - sess, - &*krate, - resolver, - rustc_parse::nt_to_tokenstream, - arena, - ); + let hir_crate = rustc_ast_lowering::lower_crate(sess, &*krate, resolver, arena); // Drop AST to free memory sess.time("drop_ast", || std::mem::drop(krate)); @@ -943,7 +937,6 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> { // // maybe move the check to a MIR pass? tcx.ensure().check_mod_liveness(module); - tcx.ensure().check_mod_intrinsics(module); }); }); } diff --git a/compiler/rustc_lint/Cargo.toml b/compiler/rustc_lint/Cargo.toml index 02f747eeccc3e..fab60b6f6096c 100644 --- a/compiler/rustc_lint/Cargo.toml +++ b/compiler/rustc_lint/Cargo.toml @@ -21,3 +21,4 @@ rustc_session = { path = "../rustc_session" } rustc_trait_selection = { path = "../rustc_trait_selection" } rustc_parse_format = { path = "../rustc_parse_format" } rustc_infer = { path = "../rustc_infer" } +rustc_type_ir = { path = "../rustc_type_ir" } diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index a87083a082b3f..6be78c52f99e3 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -1252,7 +1252,6 @@ declare_lint_pass!(MutableTransmutes => [MUTABLE_TRANSMUTES]); impl<'tcx> LateLintPass<'tcx> for MutableTransmutes { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) { - use rustc_target::spec::abi::Abi::RustIntrinsic; if let Some((&ty::Ref(_, _, from_mt), &ty::Ref(_, _, to_mt))) = get_transmute_from_to(cx, expr).map(|(ty1, ty2)| (ty1.kind(), ty2.kind())) { @@ -1287,8 +1286,7 @@ impl<'tcx> LateLintPass<'tcx> for MutableTransmutes { } fn def_id_is_transmute(cx: &LateContext<'_>, def_id: DefId) -> bool { - cx.tcx.fn_sig(def_id).abi() == RustIntrinsic - && cx.tcx.item_name(def_id) == sym::transmute + cx.tcx.is_intrinsic(def_id) && cx.tcx.item_name(def_id) == sym::transmute } } } @@ -1374,17 +1372,11 @@ impl UnreachablePub { let def_span = cx.tcx.sess.source_map().guess_head_span(span); cx.struct_span_lint(UNREACHABLE_PUB, def_span, |lint| { let mut err = lint.build(&format!("unreachable `pub` {}", what)); - let replacement = if cx.tcx.features().crate_visibility_modifier { - "crate" - } else { - "pub(crate)" - } - .to_owned(); err.span_suggestion( vis_span, "consider restricting its visibility", - replacement, + "pub(crate)".to_owned(), applicability, ); if exportable { @@ -2497,7 +2489,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue { ty: Ty<'tcx>, init: InitKind, ) -> Option { - use rustc_middle::ty::TyKind::*; + use rustc_type_ir::sty::TyKind::*; match ty.kind() { // Primitive types that don't like 0 as a value. Ref(..) => Some(("references must be non-null".to_string(), None)), @@ -2707,7 +2699,7 @@ impl SymbolName { } impl ClashingExternDeclarations { - crate fn new() -> Self { + pub(crate) fn new() -> Self { ClashingExternDeclarations { seen_decls: FxHashMap::default() } } /// Insert a new foreign item into the seen set. If a symbol with the same name already exists @@ -2809,7 +2801,7 @@ impl ClashingExternDeclarations { true } else { // Do a full, depth-first comparison between the two. - use rustc_middle::ty::TyKind::*; + use rustc_type_ir::sty::TyKind::*; let a_kind = a.kind(); let b_kind = b.kind(); diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index d7cd5ec04f323..2c6bdef361aab 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -819,6 +819,43 @@ pub trait LintContext: Sized { "see issue #89122 for more information", ); }, + BuiltinLintDiagnostics::SingleUseLifetime { + param_span, + use_span: Some((use_span, elide)), + deletion_span, + } => { + debug!(?param_span, ?use_span, ?deletion_span); + db.span_label(param_span, "this lifetime..."); + db.span_label(use_span, "...is used only here"); + let msg = "elide the single-use lifetime"; + let (use_span, replace_lt) = if elide { + let use_span = sess.source_map().span_extend_while( + use_span, + char::is_whitespace, + ).unwrap_or(use_span); + (use_span, String::new()) + } else { + (use_span, "'_".to_owned()) + }; + db.multipart_suggestion( + msg, + vec![(deletion_span, String::new()), (use_span, replace_lt)], + Applicability::MachineApplicable, + ); + }, + BuiltinLintDiagnostics::SingleUseLifetime { + param_span: _, + use_span: None, + deletion_span, + } => { + debug!(?deletion_span); + db.span_suggestion( + deletion_span, + "elide the unused lifetime", + String::new(), + Applicability::MachineApplicable, + ); + }, } // Rewrap `db`, and pass control to the user. decorate(LintDiagnosticBuilder::new(db)); diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs index 3ea68aea3cb5d..2ab948958d047 100644 --- a/compiler/rustc_lint/src/early.rs +++ b/compiler/rustc_lint/src/early.rs @@ -239,6 +239,7 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T> fn visit_generic_param(&mut self, param: &'a ast::GenericParam) { run_early_pass!(self, check_generic_param, param); + self.check_id(param.id); ast_visit::walk_generic_param(self, param); } @@ -272,7 +273,7 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T> }); } - fn visit_lifetime(&mut self, lt: &'a ast::Lifetime) { + fn visit_lifetime(&mut self, lt: &'a ast::Lifetime, _: ast_visit::LifetimeCtxt) { run_early_pass!(self, check_lifetime, lt); self.check_id(lt.id); } @@ -423,10 +424,25 @@ pub fn check_ast_node<'a>( let mut passes: Vec<_> = passes.iter().map(|p| (p)()).collect(); let mut buffered = lint_buffer.unwrap_or_default(); - if !sess.opts.debugging_opts.no_interleave_lints { + if sess.opts.debugging_opts.no_interleave_lints { + for (i, pass) in passes.iter_mut().enumerate() { + buffered = + sess.prof.extra_verbose_generic_activity("run_lint", pass.name()).run(|| { + early_lint_node( + sess, + !pre_expansion && i == 0, + lint_store, + registered_tools, + buffered, + EarlyLintPassObjects { lints: slice::from_mut(pass) }, + check_node, + ) + }); + } + } else { buffered = early_lint_node( sess, - pre_expansion, + !pre_expansion, lint_store, registered_tools, buffered, @@ -445,21 +461,6 @@ pub fn check_ast_node<'a>( check_node, ); } - } else { - for (i, pass) in passes.iter_mut().enumerate() { - buffered = - sess.prof.extra_verbose_generic_activity("run_lint", pass.name()).run(|| { - early_lint_node( - sess, - pre_expansion && i == 0, - lint_store, - registered_tools, - buffered, - EarlyLintPassObjects { lints: slice::from_mut(pass) }, - check_node, - ) - }); - } } // All of the buffered lints should have been emitted at this point. diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs index 27d44da6dfc38..b83d63e0da086 100644 --- a/compiler/rustc_lint/src/internal.rs +++ b/compiler/rustc_lint/src/internal.rs @@ -5,8 +5,8 @@ use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext} use rustc_ast as ast; use rustc_errors::Applicability; use rustc_hir::def::Res; -use rustc_hir::{Expr, ExprKind, GenericArg, Path, PathSegment, QPath}; -use rustc_hir::{HirId, Item, ItemKind, Node, Ty, TyKind}; +use rustc_hir::{Expr, ExprKind, GenericArg, PatKind, Path, PathSegment, QPath}; +use rustc_hir::{HirId, Item, ItemKind, Node, Pat, Ty, TyKind}; use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::hygiene::{ExpnKind, MacroKind}; @@ -123,55 +123,115 @@ declare_lint_pass!(TyTyKind => [ ]); impl<'tcx> LateLintPass<'tcx> for TyTyKind { - fn check_path(&mut self, cx: &LateContext<'_>, path: &'tcx Path<'tcx>, _: HirId) { - let segments = path.segments.iter().rev().skip(1).rev(); - - if let Some(last) = segments.last() { - let span = path.span.with_hi(last.ident.span.hi()); - if lint_ty_kind_usage(cx, last) { - cx.struct_span_lint(USAGE_OF_TY_TYKIND, span, |lint| { - lint.build("usage of `ty::TyKind::`") - .span_suggestion( - span, - "try using ty:: directly", - "ty".to_string(), - Applicability::MaybeIncorrect, // ty maybe needs an import - ) - .emit(); - }) - } + fn check_path( + &mut self, + cx: &LateContext<'tcx>, + path: &'tcx rustc_hir::Path<'tcx>, + _: rustc_hir::HirId, + ) { + if let Some(segment) = path.segments.iter().nth_back(1) + && let Some(res) = &segment.res + && lint_ty_kind_usage(cx, res) + { + let span = path.span.with_hi( + segment.args.map_or(segment.ident.span, |a| a.span_ext).hi() + ); + cx.struct_span_lint(USAGE_OF_TY_TYKIND, path.span, |lint| { + lint.build("usage of `ty::TyKind::`") + .span_suggestion( + span, + "try using `ty::` directly", + "ty".to_string(), + Applicability::MaybeIncorrect, // ty maybe needs an import + ) + .emit(); + }); } } fn check_ty(&mut self, cx: &LateContext<'_>, ty: &'tcx Ty<'tcx>) { match &ty.kind { TyKind::Path(QPath::Resolved(_, path)) => { - if let Some(last) = path.segments.iter().last() { - if lint_ty_kind_usage(cx, last) { - cx.struct_span_lint(USAGE_OF_TY_TYKIND, path.span, |lint| { - lint.build("usage of `ty::TyKind`") - .help("try using `Ty` instead") - .emit(); - }) - } else { - if ty.span.from_expansion() { - return; - } - if let Some(t) = is_ty_or_ty_ctxt(cx, ty) { - if path.segments.len() > 1 { - cx.struct_span_lint(USAGE_OF_QUALIFIED_TY, path.span, |lint| { - lint.build(&format!("usage of qualified `ty::{}`", t)) + if lint_ty_kind_usage(cx, &path.res) { + cx.struct_span_lint(USAGE_OF_TY_TYKIND, path.span, |lint| { + let hir = cx.tcx.hir(); + match hir.find(hir.get_parent_node(ty.hir_id)) { + Some(Node::Pat(Pat { + kind: + PatKind::Path(qpath) + | PatKind::TupleStruct(qpath, ..) + | PatKind::Struct(qpath, ..), + .. + })) => { + if let QPath::TypeRelative(qpath_ty, ..) = qpath + && qpath_ty.hir_id == ty.hir_id + { + lint.build("usage of `ty::TyKind::`") + .span_suggestion( + path.span, + "try using `ty::` directly", + "ty".to_string(), + Applicability::MaybeIncorrect, // ty maybe needs an import + ) + .emit(); + return; + } + } + Some(Node::Expr(Expr { + kind: ExprKind::Path(qpath), + .. + })) => { + if let QPath::TypeRelative(qpath_ty, ..) = qpath + && qpath_ty.hir_id == ty.hir_id + { + lint.build("usage of `ty::TyKind::`") .span_suggestion( path.span, - "try importing it and using it unqualified", - t, - // The import probably needs to be changed - Applicability::MaybeIncorrect, + "try using `ty::` directly", + "ty".to_string(), + Applicability::MaybeIncorrect, // ty maybe needs an import ) .emit(); - }) + return; + } } + // Can't unify these two branches because qpath below is `&&` and above is `&` + // and `A | B` paths don't play well together with adjustments, apparently. + Some(Node::Expr(Expr { + kind: ExprKind::Struct(qpath, ..), + .. + })) => { + if let QPath::TypeRelative(qpath_ty, ..) = qpath + && qpath_ty.hir_id == ty.hir_id + { + lint.build("usage of `ty::TyKind::`") + .span_suggestion( + path.span, + "try using `ty::` directly", + "ty".to_string(), + Applicability::MaybeIncorrect, // ty maybe needs an import + ) + .emit(); + return; + } + } + _ => {} } + lint.build("usage of `ty::TyKind`").help("try using `Ty` instead").emit(); + }) + } else if !ty.span.from_expansion() && let Some(t) = is_ty_or_ty_ctxt(cx, &path) { + if path.segments.len() > 1 { + cx.struct_span_lint(USAGE_OF_QUALIFIED_TY, path.span, |lint| { + lint.build(&format!("usage of qualified `ty::{}`", t)) + .span_suggestion( + path.span, + "try importing it and using it unqualified", + t, + // The import probably needs to be changed + Applicability::MaybeIncorrect, + ) + .emit(); + }) } } } @@ -180,42 +240,37 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind { } } -fn lint_ty_kind_usage(cx: &LateContext<'_>, segment: &PathSegment<'_>) -> bool { - if let Some(res) = segment.res { - if let Some(did) = res.opt_def_id() { - return cx.tcx.is_diagnostic_item(sym::TyKind, did); - } +fn lint_ty_kind_usage(cx: &LateContext<'_>, res: &Res) -> bool { + if let Some(did) = res.opt_def_id() { + cx.tcx.is_diagnostic_item(sym::TyKind, did) || cx.tcx.is_diagnostic_item(sym::IrTyKind, did) + } else { + false } - - false } -fn is_ty_or_ty_ctxt(cx: &LateContext<'_>, ty: &Ty<'_>) -> Option { - if let TyKind::Path(QPath::Resolved(_, path)) = &ty.kind { - match path.res { - Res::Def(_, def_id) => { - if let Some(name @ (sym::Ty | sym::TyCtxt)) = cx.tcx.get_diagnostic_name(def_id) { - return Some(format!("{}{}", name, gen_args(path.segments.last().unwrap()))); - } +fn is_ty_or_ty_ctxt(cx: &LateContext<'_>, path: &Path<'_>) -> Option { + match &path.res { + Res::Def(_, def_id) => { + if let Some(name @ (sym::Ty | sym::TyCtxt)) = cx.tcx.get_diagnostic_name(*def_id) { + return Some(format!("{}{}", name, gen_args(path.segments.last().unwrap()))); } - // Only lint on `&Ty` and `&TyCtxt` if it is used outside of a trait. - Res::SelfTy { trait_: None, alias_to: Some((did, _)) } => { - if let ty::Adt(adt, substs) = cx.tcx.type_of(did).kind() { - if let Some(name @ (sym::Ty | sym::TyCtxt)) = - cx.tcx.get_diagnostic_name(adt.did()) - { - // NOTE: This path is currently unreachable as `Ty<'tcx>` is - // defined as a type alias meaning that `impl<'tcx> Ty<'tcx>` - // is not actually allowed. - // - // I(@lcnr) still kept this branch in so we don't miss this - // if we ever change it in the future. - return Some(format!("{}<{}>", name, substs[0])); - } + } + // Only lint on `&Ty` and `&TyCtxt` if it is used outside of a trait. + Res::SelfTy { trait_: None, alias_to: Some((did, _)) } => { + if let ty::Adt(adt, substs) = cx.tcx.type_of(did).kind() { + if let Some(name @ (sym::Ty | sym::TyCtxt)) = cx.tcx.get_diagnostic_name(adt.did()) + { + // NOTE: This path is currently unreachable as `Ty<'tcx>` is + // defined as a type alias meaning that `impl<'tcx> Ty<'tcx>` + // is not actually allowed. + // + // I(@lcnr) still kept this branch in so we don't miss this + // if we ever change it in the future. + return Some(format!("{}<{}>", name, substs[0])); } } - _ => (), } + _ => (), } None diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs index 0ce760b64d9ca..772ab7fe22608 100644 --- a/compiler/rustc_lint/src/late.rs +++ b/compiler/rustc_lint/src/late.rs @@ -34,7 +34,7 @@ use tracing::debug; /// Extract the `LintStore` from the query context. /// This function exists because we've erased `LintStore` as `dyn Any` in the context. -crate fn unerased_lint_store(tcx: TyCtxt<'_>) -> &LintStore { +pub(crate) fn unerased_lint_store(tcx: TyCtxt<'_>) -> &LintStore { let store: &dyn Any = &*tcx.lint_store; store.downcast_ref().unwrap() } diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index 257549bf1a1a4..54f2c72527924 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -14,7 +14,7 @@ use rustc_middle::lint::{ use rustc_middle::ty::query::Providers; use rustc_middle::ty::{RegisteredTools, TyCtxt}; use rustc_session::lint::{ - builtin::{self, FORBIDDEN_LINT_GROUPS, UNFULFILLED_LINT_EXPECTATIONS}, + builtin::{self, FORBIDDEN_LINT_GROUPS, SINGLE_USE_LIFETIMES, UNFULFILLED_LINT_EXPECTATIONS}, Level, Lint, LintExpectationId, LintId, }; use rustc_session::parse::{add_feature_diagnostics, feature_err}; @@ -259,6 +259,14 @@ impl<'s> LintLevelsBuilder<'s> { let sess = self.sess; let bad_attr = |span| struct_span_err!(sess, span, E0452, "malformed lint attribute input"); for (attr_index, attr) in attrs.iter().enumerate() { + if attr.has_name(sym::automatically_derived) { + self.current_specs_mut().insert( + LintId::of(SINGLE_USE_LIFETIMES), + (Level::Allow, LintLevelSource::Default), + ); + continue; + } + let level = match Level::from_attr(attr) { None => continue, Some(Level::Expect(unstable_id)) if let Some(hir_id) = source_hir_id => { diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 0a0f292fe7a4d..7c68429e1e902 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -30,7 +30,6 @@ #![feature(array_windows)] #![feature(box_patterns)] #![feature(control_flow_enum)] -#![feature(crate_visibility_modifier)] #![feature(if_let_guard)] #![feature(iter_intersperse)] #![feature(iter_order_by)] diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 62d427fcd0238..55b1ba9cd964a 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -651,7 +651,7 @@ declare_lint! { declare_lint_pass!(ImproperCTypesDefinitions => [IMPROPER_CTYPES_DEFINITIONS]); #[derive(Clone, Copy)] -crate enum CItemKind { +pub(crate) enum CItemKind { Declaration, Definition, } @@ -667,7 +667,10 @@ enum FfiResult<'tcx> { FfiUnsafe { ty: Ty<'tcx>, reason: String, help: Option }, } -crate fn nonnull_optimization_guaranteed<'tcx>(tcx: TyCtxt<'tcx>, def: ty::AdtDef<'tcx>) -> bool { +pub(crate) fn nonnull_optimization_guaranteed<'tcx>( + tcx: TyCtxt<'tcx>, + def: ty::AdtDef<'tcx>, +) -> bool { tcx.has_attr(def.did(), sym::rustc_nonnull_optimization_guaranteed) } @@ -766,7 +769,7 @@ fn get_nullable_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option( +pub(crate) fn repr_nullable_ptr<'tcx>( cx: &LateContext<'tcx>, ty: Ty<'tcx>, ckind: CItemKind, diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index f942970278399..a067534b18938 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -474,7 +474,7 @@ declare_lint! { } declare_lint! { - /// The `unknown_lints` lint detects unrecognized lint attribute. + /// The `unknown_lints` lint detects unrecognized lint attributes. /// /// ### Example /// diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 57b4f96dc100d..e50abf6cf2559 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -423,7 +423,11 @@ pub enum BuiltinLintDiagnostics { DeprecatedMacro(Option, Span), MissingAbi(Span, Abi), UnusedDocComment(Span), - UnusedBuiltinAttribute { attr_name: Symbol, macro_name: String, invoc_span: Span }, + UnusedBuiltinAttribute { + attr_name: Symbol, + macro_name: String, + invoc_span: Span, + }, PatternsInFnsWithoutBody(Span, Ident), LegacyDeriveHelpers(Span), ProcMacroBackCompat(String), @@ -435,6 +439,16 @@ pub enum BuiltinLintDiagnostics { UnicodeTextFlow(Span, String), UnexpectedCfg((Symbol, Span), Option<(Symbol, Span)>), DeprecatedWhereclauseLocation(Span, String), + SingleUseLifetime { + /// Span of the parameter which declares this lifetime. + param_span: Span, + /// Span of the code that should be removed when eliding this lifetime. + /// This span should include leading or trailing comma. + deletion_span: Span, + /// Span of the single use, or None if the lifetime is never used. + /// If true, the lifetime will be fully elided. + use_span: Option<(Span, bool)>, + }, } /// Lints that are buffered up early on in the `Session` before the diff --git a/compiler/rustc_log/src/lib.rs b/compiler/rustc_log/src/lib.rs index c152815eeca68..f2ec80b0c1b63 100644 --- a/compiler/rustc_log/src/lib.rs +++ b/compiler/rustc_log/src/lib.rs @@ -69,13 +69,7 @@ pub fn init_env_logger(env: &str) -> Result<(), Error> { let verbose_entry_exit = match env::var_os(String::from(env) + "_ENTRY_EXIT") { None => false, - Some(v) => { - if &v == "0" { - false - } else { - true - } - } + Some(v) => &v != "0", }; let layer = tracing_tree::HierarchicalLayer::default() diff --git a/compiler/rustc_macros/Cargo.toml b/compiler/rustc_macros/Cargo.toml index a9192be4d6ef4..25b3aadc1c527 100644 --- a/compiler/rustc_macros/Cargo.toml +++ b/compiler/rustc_macros/Cargo.toml @@ -7,7 +7,11 @@ edition = "2021" proc-macro = true [dependencies] +annotate-snippets = "0.8.0" +fluent-bundle = "0.15.2" +fluent-syntax = "0.11" synstructure = "0.12.1" syn = { version = "1", features = ["full"] } proc-macro2 = "1" quote = "1" +unic-langid = { version = "0.9.0", features = ["macros"] } diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic.rs b/compiler/rustc_macros/src/diagnostics/diagnostic.rs index dac3e986e7ad4..95ee0d4a060d2 100644 --- a/compiler/rustc_macros/src/diagnostics/diagnostic.rs +++ b/compiler/rustc_macros/src/diagnostics/diagnostic.rs @@ -13,7 +13,7 @@ use quote::{format_ident, quote}; use std::collections::HashMap; use std::str::FromStr; use syn::{spanned::Spanned, Attribute, Meta, MetaList, MetaNameValue, Type}; -use synstructure::Structure; +use synstructure::{BindingInfo, Structure}; /// The central struct for constructing the `into_diagnostic` method from an annotated struct. pub(crate) struct SessionDiagnosticDerive<'a> { @@ -71,55 +71,42 @@ impl<'a> SessionDiagnosticDerive<'a> { } }; + // Keep track of which fields are subdiagnostics or have no attributes. + let mut subdiagnostics_or_empty = std::collections::HashSet::new(); + // Generates calls to `span_label` and similar functions based on the attributes // on fields. Code for suggestions uses formatting machinery and the value of // other fields - because any given field can be referenced multiple times, it - // should be accessed through a borrow. When passing fields to `set_arg` (which - // happens below) for Fluent, we want to move the data, so that has to happen - // in a separate pass over the fields. - let attrs = structure.each(|field_binding| { - let field = field_binding.ast(); - let result = field.attrs.iter().map(|attr| { - builder - .generate_field_attr_code( - attr, - FieldInfo { - vis: &field.vis, - binding: field_binding, - ty: &field.ty, - span: &field.span(), - }, - ) - .unwrap_or_else(|v| v.to_compile_error()) - }); - - quote! { #(#result);* } - }); + // should be accessed through a borrow. When passing fields to `add_subdiagnostic` + // or `set_arg` (which happens below) for Fluent, we want to move the data, so that + // has to happen in a separate pass over the fields. + let attrs = structure + .clone() + .filter(|field_binding| { + let attrs = &field_binding.ast().attrs; + + (!attrs.is_empty() + && attrs.iter().all(|attr| { + "subdiagnostic" + != attr.path.segments.last().unwrap().ident.to_string() + })) + || { + subdiagnostics_or_empty.insert(field_binding.binding.clone()); + false + } + }) + .each(|field_binding| builder.generate_field_attrs_code(field_binding)); - // When generating `set_arg` calls, move data rather than borrow it to avoid - // requiring clones - this must therefore be the last use of each field (for - // example, any formatting machinery that might refer to a field should be - // generated already). structure.bind_with(|_| synstructure::BindStyle::Move); - let args = structure.each(|field_binding| { - let field = field_binding.ast(); - // When a field has attributes like `#[label]` or `#[note]` then it doesn't - // need to be passed as an argument to the diagnostic. But when a field has no - // attributes then it must be passed as an argument to the diagnostic so that - // it can be referred to by Fluent messages. - if field.attrs.is_empty() { - let diag = &builder.diag; - let ident = field_binding.ast().ident.as_ref().unwrap(); - quote! { - #diag.set_arg( - stringify!(#ident), - #field_binding - ); - } - } else { - quote! {} - } - }); + // When a field has attributes like `#[label]` or `#[note]` then it doesn't + // need to be passed as an argument to the diagnostic. But when a field has no + // attributes or a `#[subdiagnostic]` attribute then it must be passed as an + // argument to the diagnostic so that it can be referred to by Fluent messages. + let args = structure + .filter(|field_binding| { + subdiagnostics_or_empty.contains(&field_binding.binding) + }) + .each(|field_binding| builder.generate_field_attrs_code(field_binding)); let span = ast.span().unwrap(); let (diag, sess) = (&builder.diag, &builder.sess); @@ -139,14 +126,14 @@ impl<'a> SessionDiagnosticDerive<'a> { (Some((SessionDiagnosticKind::Error, _)), Some((slug, _))) => { quote! { let mut #diag = #sess.struct_err( - rustc_errors::DiagnosticMessage::fluent(#slug), + rustc_errors::DiagnosticMessage::new(#slug), ); } } (Some((SessionDiagnosticKind::Warn, _)), Some((slug, _))) => { quote! { let mut #diag = #sess.struct_warn( - rustc_errors::DiagnosticMessage::fluent(#slug), + rustc_errors::DiagnosticMessage::new(#slug), ); } } @@ -267,21 +254,6 @@ impl SessionDiagnosticDeriveBuilder { if matches!(name, "help" | "note") && matches!(meta, Meta::Path(_) | Meta::NameValue(_)) { let diag = &self.diag; - let slug = match &self.slug { - Some((slug, _)) => slug.as_str(), - None => throw_span_err!( - span, - &format!( - "`#[{}{}]` must come after `#[error(..)]` or `#[warn(..)]`", - name, - match meta { - Meta::Path(_) => "", - Meta::NameValue(_) => " = ...", - _ => unreachable!(), - } - ) - ), - }; let id = match meta { Meta::Path(..) => quote! { #name }, Meta::NameValue(MetaNameValue { lit: syn::Lit::Str(s), .. }) => { @@ -292,7 +264,7 @@ impl SessionDiagnosticDeriveBuilder { let fn_name = proc_macro2::Ident::new(name, attr.span()); return Ok(quote! { - #diag.#fn_name(rustc_errors::DiagnosticMessage::fluent_attr(#slug, #id)); + #diag.#fn_name(rustc_errors::SubdiagnosticMessage::attr(#id)); }); } @@ -347,36 +319,60 @@ impl SessionDiagnosticDeriveBuilder { Ok(tokens.drain(..).collect()) } - fn generate_field_attr_code( - &mut self, - attr: &syn::Attribute, - info: FieldInfo<'_>, - ) -> Result { - let field_binding = &info.binding.binding; - - let inner_ty = FieldInnerTy::from_type(&info.ty); - let name = attr.path.segments.last().unwrap().ident.to_string(); - let (binding, needs_destructure) = match (name.as_str(), &inner_ty) { - // `primary_span` can accept a `Vec` so don't destructure that. - ("primary_span", FieldInnerTy::Vec(_)) => (quote! { #field_binding.clone() }, false), - _ => (quote! { *#field_binding }, true), - }; + fn generate_field_attrs_code(&mut self, binding_info: &BindingInfo<'_>) -> TokenStream { + let field = binding_info.ast(); + let field_binding = &binding_info.binding; - let generated_code = self.generate_inner_field_code( - attr, - FieldInfo { - vis: info.vis, - binding: info.binding, - ty: inner_ty.inner_type().unwrap_or(&info.ty), - span: info.span, - }, - binding, - )?; + let inner_ty = FieldInnerTy::from_type(&field.ty); - if needs_destructure { - Ok(inner_ty.with(field_binding, generated_code)) + // When generating `set_arg` or `add_subdiagnostic` calls, move data rather than + // borrow it to avoid requiring clones - this must therefore be the last use of + // each field (for example, any formatting machinery that might refer to a field + // should be generated already). + if field.attrs.is_empty() { + let diag = &self.diag; + let ident = field.ident.as_ref().unwrap(); + quote! { + #diag.set_arg( + stringify!(#ident), + #field_binding + ); + } } else { - Ok(generated_code) + field + .attrs + .iter() + .map(move |attr| { + let name = attr.path.segments.last().unwrap().ident.to_string(); + let (binding, needs_destructure) = match (name.as_str(), &inner_ty) { + // `primary_span` can accept a `Vec` so don't destructure that. + ("primary_span", FieldInnerTy::Vec(_)) => { + (quote! { #field_binding.clone() }, false) + } + // `subdiagnostics` are not derefed because they are bound by value. + ("subdiagnostic", _) => (quote! { #field_binding }, true), + _ => (quote! { *#field_binding }, true), + }; + + let generated_code = self + .generate_inner_field_code( + attr, + FieldInfo { + binding: binding_info, + ty: inner_ty.inner_type().unwrap_or(&field.ty), + span: &field.span(), + }, + binding, + ) + .unwrap_or_else(|v| v.to_compile_error()); + + if needs_destructure { + inner_ty.with(field_binding, generated_code) + } else { + generated_code + } + }) + .collect() } } @@ -514,13 +510,8 @@ impl SessionDiagnosticDeriveBuilder { let method = format_ident!("span_{}", name); - let slug = self - .slug - .as_ref() - .map(|(slug, _)| slug.as_str()) - .unwrap_or_else(|| "missing-slug"); let msg = msg.as_deref().unwrap_or("suggestion"); - let msg = quote! { rustc_errors::DiagnosticMessage::fluent_attr(#slug, #msg) }; + let msg = quote! { rustc_errors::SubdiagnosticMessage::attr(#msg) }; let code = code.unwrap_or_else(|| quote! { String::new() }); Ok(quote! { #diag.#method(#span_field, #msg, #code, #applicability); }) @@ -538,14 +529,11 @@ impl SessionDiagnosticDeriveBuilder { fluent_attr_identifier: &str, ) -> TokenStream { let diag = &self.diag; - - let slug = - self.slug.as_ref().map(|(slug, _)| slug.as_str()).unwrap_or_else(|| "missing-slug"); let fn_name = format_ident!("span_{}", kind); quote! { #diag.#fn_name( #field_binding, - rustc_errors::DiagnosticMessage::fluent_attr(#slug, #fluent_attr_identifier) + rustc_errors::SubdiagnosticMessage::attr(#fluent_attr_identifier) ); } } @@ -554,9 +542,8 @@ impl SessionDiagnosticDeriveBuilder { /// and `fluent_attr_identifier`. fn add_subdiagnostic(&self, kind: &Ident, fluent_attr_identifier: &str) -> TokenStream { let diag = &self.diag; - let slug = self.slug.as_ref().map(|(slug, _)| slug.as_str()).unwrap_or("missing-slug"); quote! { - #diag.#kind(rustc_errors::DiagnosticMessage::fluent_attr(#slug, #fluent_attr_identifier)); + #diag.#kind(rustc_errors::SubdiagnosticMessage::attr(#fluent_attr_identifier)); } } diff --git a/compiler/rustc_macros/src/diagnostics/fluent.rs b/compiler/rustc_macros/src/diagnostics/fluent.rs new file mode 100644 index 0000000000000..42a9bf477a41c --- /dev/null +++ b/compiler/rustc_macros/src/diagnostics/fluent.rs @@ -0,0 +1,260 @@ +use annotate_snippets::{ + display_list::DisplayList, + snippet::{Annotation, AnnotationType, Slice, Snippet, SourceAnnotation}, +}; +use fluent_bundle::{FluentBundle, FluentError, FluentResource}; +use fluent_syntax::{ + ast::{Attribute, Entry, Identifier, Message}, + parser::ParserError, +}; +use proc_macro::{Diagnostic, Level, Span}; +use proc_macro2::TokenStream; +use quote::quote; +use std::{ + collections::{HashMap, HashSet}, + fs::File, + io::Read, + path::{Path, PathBuf}, +}; +use syn::{ + parse::{Parse, ParseStream}, + parse_macro_input, + punctuated::Punctuated, + token, Ident, LitStr, Result, +}; +use unic_langid::langid; + +struct Resource { + ident: Ident, + #[allow(dead_code)] + fat_arrow_token: token::FatArrow, + resource: LitStr, +} + +impl Parse for Resource { + fn parse(input: ParseStream<'_>) -> Result { + Ok(Resource { + ident: input.parse()?, + fat_arrow_token: input.parse()?, + resource: input.parse()?, + }) + } +} + +struct Resources(Punctuated); + +impl Parse for Resources { + fn parse(input: ParseStream<'_>) -> Result { + let mut resources = Punctuated::new(); + loop { + if input.is_empty() || input.peek(token::Brace) { + break; + } + let value = input.parse()?; + resources.push_value(value); + if !input.peek(token::Comma) { + break; + } + let punct = input.parse()?; + resources.push_punct(punct); + } + Ok(Resources(resources)) + } +} + +/// Helper function for returning an absolute path for macro-invocation relative file paths. +/// +/// If the input is already absolute, then the input is returned. If the input is not absolute, +/// then it is appended to the directory containing the source file with this macro invocation. +fn invocation_relative_path_to_absolute(span: Span, path: &str) -> PathBuf { + let path = Path::new(path); + if path.is_absolute() { + path.to_path_buf() + } else { + // `/a/b/c/foo/bar.rs` contains the current macro invocation + let mut source_file_path = span.source_file().path(); + // `/a/b/c/foo/` + source_file_path.pop(); + // `/a/b/c/foo/../locales/en-US/example.ftl` + source_file_path.push(path); + source_file_path + } +} + +/// See [rustc_macros::fluent_messages]. +pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + let resources = parse_macro_input!(input as Resources); + + // Cannot iterate over individual messages in a bundle, so do that using the + // `FluentResource` instead. Construct a bundle anyway to find out if there are conflicting + // messages in the resources. + let mut bundle = FluentBundle::new(vec![langid!("en-US")]); + + // Map of Fluent identifiers to the `Span` of the resource that defined them, used for better + // diagnostics. + let mut previous_defns = HashMap::new(); + + let mut includes = TokenStream::new(); + let mut generated = TokenStream::new(); + for res in resources.0 { + let ident_span = res.ident.span().unwrap(); + let path_span = res.resource.span().unwrap(); + + // Set of Fluent attribute names already output, to avoid duplicate type errors - any given + // constant created for a given attribute is the same. + let mut previous_attrs = HashSet::new(); + + let relative_ftl_path = res.resource.value(); + let absolute_ftl_path = + invocation_relative_path_to_absolute(ident_span, &relative_ftl_path); + // As this macro also outputs an `include_str!` for this file, the macro will always be + // re-executed when the file changes. + let mut resource_file = match File::open(absolute_ftl_path) { + Ok(resource_file) => resource_file, + Err(e) => { + Diagnostic::spanned(path_span, Level::Error, "could not open Fluent resource") + .note(e.to_string()) + .emit(); + continue; + } + }; + let mut resource_contents = String::new(); + if let Err(e) = resource_file.read_to_string(&mut resource_contents) { + Diagnostic::spanned(path_span, Level::Error, "could not read Fluent resource") + .note(e.to_string()) + .emit(); + continue; + } + let resource = match FluentResource::try_new(resource_contents) { + Ok(resource) => resource, + Err((this, errs)) => { + Diagnostic::spanned(path_span, Level::Error, "could not parse Fluent resource") + .help("see additional errors emitted") + .emit(); + for ParserError { pos, slice: _, kind } in errs { + let mut err = kind.to_string(); + // Entirely unnecessary string modification so that the error message starts + // with a lowercase as rustc errors do. + err.replace_range( + 0..1, + &err.chars().next().unwrap().to_lowercase().to_string(), + ); + + let line_starts: Vec = std::iter::once(0) + .chain( + this.source() + .char_indices() + .filter_map(|(i, c)| Some(i + 1).filter(|_| c == '\n')), + ) + .collect(); + let line_start = line_starts + .iter() + .enumerate() + .map(|(line, idx)| (line + 1, idx)) + .filter(|(_, idx)| **idx <= pos.start) + .last() + .unwrap() + .0; + + let snippet = Snippet { + title: Some(Annotation { + label: Some(&err), + id: None, + annotation_type: AnnotationType::Error, + }), + footer: vec![], + slices: vec![Slice { + source: this.source(), + line_start, + origin: Some(&relative_ftl_path), + fold: true, + annotations: vec![SourceAnnotation { + label: "", + annotation_type: AnnotationType::Error, + range: (pos.start, pos.end - 1), + }], + }], + opt: Default::default(), + }; + let dl = DisplayList::from(snippet); + eprintln!("{}\n", dl); + } + continue; + } + }; + + let mut constants = TokenStream::new(); + for entry in resource.entries() { + let span = res.ident.span(); + if let Entry::Message(Message { id: Identifier { name }, attributes, .. }) = entry { + let _ = previous_defns.entry(name.to_string()).or_insert(ident_span); + + // `typeck-foo-bar` => `foo_bar` + let snake_name = Ident::new( + &name.replace(&format!("{}-", res.ident), "").replace("-", "_"), + span, + ); + constants.extend(quote! { + pub const #snake_name: crate::DiagnosticMessage = + crate::DiagnosticMessage::FluentIdentifier( + std::borrow::Cow::Borrowed(#name), + None + ); + }); + + for Attribute { id: Identifier { name: attr_name }, .. } in attributes { + let snake_name = Ident::new(&attr_name.replace("-", "_"), span); + if !previous_attrs.insert(snake_name.clone()) { + continue; + } + + constants.extend(quote! { + pub const #snake_name: crate::SubdiagnosticMessage = + crate::SubdiagnosticMessage::FluentAttr( + std::borrow::Cow::Borrowed(#attr_name) + ); + }); + } + } + } + + if let Err(errs) = bundle.add_resource(resource) { + for e in errs { + match e { + FluentError::Overriding { kind, id } => { + Diagnostic::spanned( + ident_span, + Level::Error, + format!("overrides existing {}: `{}`", kind, id), + ) + .span_help(previous_defns[&id], "previously defined in this resource") + .emit(); + } + FluentError::ResolverError(_) | FluentError::ParserError(_) => unreachable!(), + } + } + } + + includes.extend(quote! { include_str!(#relative_ftl_path), }); + + let ident = res.ident; + generated.extend(quote! { + pub mod #ident { + #constants + } + }); + } + + quote! { + #[allow(non_upper_case_globals)] + #[doc(hidden)] + pub mod fluent_generated { + pub static DEFAULT_LOCALE_RESOURCES: &'static [&'static str] = &[ + #includes + ]; + + #generated + } + } + .into() +} diff --git a/compiler/rustc_macros/src/diagnostics/mod.rs b/compiler/rustc_macros/src/diagnostics/mod.rs index 73ad415d6c355..69573d904d4a9 100644 --- a/compiler/rustc_macros/src/diagnostics/mod.rs +++ b/compiler/rustc_macros/src/diagnostics/mod.rs @@ -1,9 +1,11 @@ mod diagnostic; mod error; +mod fluent; mod subdiagnostic; mod utils; use diagnostic::SessionDiagnosticDerive; +pub(crate) use fluent::fluent_messages; use proc_macro2::TokenStream; use quote::format_ident; use subdiagnostic::SessionSubdiagnosticDerive; @@ -12,7 +14,7 @@ use synstructure::Structure; /// Implements `#[derive(SessionDiagnostic)]`, which allows for errors to be specified as a struct, /// independent from the actual diagnostics emitting code. /// -/// ```ignore (pseudo-rust) +/// ```ignore (rust) /// # extern crate rustc_errors; /// # use rustc_errors::Applicability; /// # extern crate rustc_span; @@ -43,7 +45,7 @@ use synstructure::Structure; /// /// Then, later, to emit the error: /// -/// ```ignore (pseudo-rust) +/// ```ignore (rust) /// sess.emit_err(MoveOutOfBorrowError { /// expected, /// actual, @@ -67,7 +69,7 @@ pub fn session_diagnostic_derive(s: Structure<'_>) -> TokenStream { /// suggestions to be specified as a structs or enums, independent from the actual diagnostics /// emitting code or diagnostic derives. /// -/// ```ignore (pseudo-rust) +/// ```ignore (rust) /// #[derive(SessionSubdiagnostic)] /// pub enum ExpectedIdentifierLabel<'tcx> { /// #[label(slug = "parser-expected-identifier")] @@ -104,7 +106,7 @@ pub fn session_diagnostic_derive(s: Structure<'_>) -> TokenStream { /// /// Then, later, to add the subdiagnostic: /// -/// ```ignore (pseudo-rust) +/// ```ignore (rust) /// diag.subdiagnostic(ExpectedIdentifierLabel::WithoutFound { span }); /// /// diag.subdiagnostic(RawIdentifierSuggestion { span, applicability, ident }); diff --git a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs index ae5b9dbd9ba1c..9aeb484bfd52d 100644 --- a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs +++ b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs @@ -303,7 +303,6 @@ impl<'a> SessionSubdiagnosticDeriveBuilder<'a> { let inner_ty = FieldInnerTy::from_type(&ast.ty); let info = FieldInfo { - vis: &ast.vis, binding: binding, ty: inner_ty.inner_type().unwrap_or(&ast.ty), span: &ast.span(), @@ -398,7 +397,7 @@ impl<'a> SessionSubdiagnosticDeriveBuilder<'a> { let diag = &self.diag; let name = format_ident!("{}{}", if span_field.is_some() { "span_" } else { "" }, kind); - let message = quote! { rustc_errors::DiagnosticMessage::fluent(#slug) }; + let message = quote! { rustc_errors::SubdiagnosticMessage::message(#slug) }; let call = if matches!(kind, SubdiagnosticKind::Suggestion(..)) { if let Some(span) = span_field { quote! { #diag.#name(#span, #message, #code, #applicability); } diff --git a/compiler/rustc_macros/src/diagnostics/utils.rs b/compiler/rustc_macros/src/diagnostics/utils.rs index af5a30880e05f..636bcf1f7b1d9 100644 --- a/compiler/rustc_macros/src/diagnostics/utils.rs +++ b/compiler/rustc_macros/src/diagnostics/utils.rs @@ -4,7 +4,7 @@ use proc_macro2::TokenStream; use quote::{format_ident, quote, ToTokens}; use std::collections::BTreeSet; use std::str::FromStr; -use syn::{spanned::Spanned, Attribute, Meta, Type, TypeTuple, Visibility}; +use syn::{spanned::Spanned, Attribute, Meta, Type, TypeTuple}; use synstructure::BindingInfo; /// Checks whether the type name of `ty` matches `name`. @@ -158,7 +158,6 @@ impl<'ty> FieldInnerTy<'ty> { /// Field information passed to the builder. Deliberately omits attrs to discourage the /// `generate_*` methods from walking the attributes themselves. pub(crate) struct FieldInfo<'a> { - pub(crate) vis: &'a Visibility, pub(crate) binding: &'a BindingInfo<'a>, pub(crate) ty: &'a Type, pub(crate) span: &'a proc_macro2::Span, diff --git a/compiler/rustc_macros/src/lib.rs b/compiler/rustc_macros/src/lib.rs index 0baebdb713062..7c8e3c6d14024 100644 --- a/compiler/rustc_macros/src/lib.rs +++ b/compiler/rustc_macros/src/lib.rs @@ -2,6 +2,7 @@ #![feature(let_else)] #![feature(never_type)] #![feature(proc_macro_diagnostic)] +#![feature(proc_macro_span)] #![allow(rustc::default_hash_types)] #![recursion_limit = "128"] @@ -49,6 +50,64 @@ pub fn newtype_index(input: TokenStream) -> TokenStream { newtype::newtype(input) } +/// Implements the `fluent_messages` macro, which performs compile-time validation of the +/// compiler's Fluent resources (i.e. that the resources parse and don't multiply define the same +/// messages) and generates constants that make using those messages in diagnostics more ergonomic. +/// +/// For example, given the following invocation of the macro.. +/// +/// ```ignore (rust) +/// fluent_messages! { +/// typeck => "./typeck.ftl", +/// } +/// ``` +/// ..where `typeck.ftl` has the following contents.. +/// +/// ```fluent +/// typeck-field-multiply-specified-in-initializer = +/// field `{$ident}` specified more than once +/// .label = used more than once +/// .label-previous-use = first use of `{$ident}` +/// ``` +/// ...then the macro parse the Fluent resource, emitting a diagnostic if it fails to do so, and +/// will generate the following code: +/// +/// ```ignore (rust) +/// pub static DEFAULT_LOCALE_RESOURCES: &'static [&'static str] = &[ +/// include_str!("./typeck.ftl"), +/// ]; +/// +/// mod fluent_generated { +/// mod typeck { +/// pub const field_multiply_specified_in_initializer: DiagnosticMessage = +/// DiagnosticMessage::fluent("typeck-field-multiply-specified-in-initializer"); +/// pub const field_multiply_specified_in_initializer_label_previous_use: DiagnosticMessage = +/// DiagnosticMessage::fluent_attr( +/// "typeck-field-multiply-specified-in-initializer", +/// "previous-use-label" +/// ); +/// } +/// } +/// ``` +/// When emitting a diagnostic, the generated constants can be used as follows: +/// +/// ```ignore (rust) +/// let mut err = sess.struct_span_err( +/// span, +/// fluent::typeck::field_multiply_specified_in_initializer +/// ); +/// err.span_default_label(span); +/// err.span_label( +/// previous_use_span, +/// fluent::typeck::field_multiply_specified_in_initializer_label_previous_use +/// ); +/// err.emit(); +/// ``` +#[proc_macro] +pub fn fluent_messages(input: TokenStream) -> TokenStream { + diagnostics::fluent_messages(input) +} + decl_derive!([HashStable, attributes(stable_hasher)] => hash_stable::hash_stable_derive); decl_derive!( [HashStable_Generic, attributes(stable_hasher)] => diff --git a/compiler/rustc_macros/src/serialize.rs b/compiler/rustc_macros/src/serialize.rs index 535158ffd8d84..a39b44139811e 100644 --- a/compiler/rustc_macros/src/serialize.rs +++ b/compiler/rustc_macros/src/serialize.rs @@ -8,7 +8,7 @@ pub fn type_decodable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2: if !s.ast().generics.lifetimes().any(|lt| lt.lifetime.ident == "tcx") { s.add_impl_generic(parse_quote! { 'tcx }); } - s.add_impl_generic(parse_quote! {#decoder_ty: ::rustc_middle::ty::codec::TyDecoder<'tcx>}); + s.add_impl_generic(parse_quote! {#decoder_ty: ::rustc_type_ir::codec::TyDecoder>}); s.add_bounds(synstructure::AddBounds::Generics); decodable_body(s, decoder_ty) @@ -95,7 +95,7 @@ pub fn type_encodable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2: s.add_impl_generic(parse_quote! {'tcx}); } let encoder_ty = quote! { __E }; - s.add_impl_generic(parse_quote! {#encoder_ty: ::rustc_middle::ty::codec::TyEncoder<'tcx>}); + s.add_impl_generic(parse_quote! {#encoder_ty: ::rustc_type_ir::codec::TyEncoder>}); s.add_bounds(synstructure::AddBounds::Generics); encodable_body(s, encoder_ty, false) diff --git a/compiler/rustc_metadata/Cargo.toml b/compiler/rustc_metadata/Cargo.toml index 59796dd652943..41224e3346177 100644 --- a/compiler/rustc_metadata/Cargo.toml +++ b/compiler/rustc_metadata/Cargo.toml @@ -27,3 +27,4 @@ rustc_ast = { path = "../rustc_ast" } rustc_expand = { path = "../rustc_expand" } rustc_span = { path = "../rustc_span" } rustc_session = { path = "../rustc_session" } +rustc_type_ir = { path = "../rustc_type_ir" } diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index 3c545e6a0d240..947d563ae3cd1 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -70,7 +70,7 @@ pub enum LoadedMacro { ProcMacro(SyntaxExtension), } -crate struct Library { +pub(crate) struct Library { pub source: CrateSource, pub metadata: MetadataBlob, } @@ -82,7 +82,7 @@ enum LoadResult { /// A reference to `CrateMetadata` that can also give access to whole crate store when necessary. #[derive(Clone, Copy)] -crate struct CrateMetadataRef<'a> { +pub(crate) struct CrateMetadataRef<'a> { pub cdata: &'a CrateMetadata, pub cstore: &'a CStore, } @@ -133,7 +133,7 @@ impl CStore { CrateNum::new(self.metas.len() - 1) } - crate fn get_crate_data(&self, cnum: CrateNum) -> CrateMetadataRef<'_> { + pub(crate) fn get_crate_data(&self, cnum: CrateNum) -> CrateMetadataRef<'_> { let cdata = self.metas[cnum] .as_ref() .unwrap_or_else(|| panic!("Failed to get crate data for {:?}", cnum)); @@ -145,7 +145,7 @@ impl CStore { self.metas[cnum] = Some(Lrc::new(data)); } - crate fn iter_crate_data(&self) -> impl Iterator { + pub(crate) fn iter_crate_data(&self) -> impl Iterator { self.metas .iter_enumerated() .filter_map(|(cnum, data)| data.as_ref().map(|data| (cnum, &**data))) @@ -164,7 +164,7 @@ impl CStore { } } - crate fn crate_dependencies_in_postorder(&self, cnum: CrateNum) -> Vec { + pub(crate) fn crate_dependencies_in_postorder(&self, cnum: CrateNum) -> Vec { let mut deps = Vec::new(); if cnum == LOCAL_CRATE { for (cnum, _) in self.iter_crate_data() { @@ -182,15 +182,15 @@ impl CStore { deps } - crate fn injected_panic_runtime(&self) -> Option { + pub(crate) fn injected_panic_runtime(&self) -> Option { self.injected_panic_runtime } - crate fn allocator_kind(&self) -> Option { + pub(crate) fn allocator_kind(&self) -> Option { self.allocator_kind } - crate fn has_global_allocator(&self) -> bool { + pub(crate) fn has_global_allocator(&self) -> bool { self.has_global_allocator } @@ -323,7 +323,7 @@ impl<'a> CrateLoader<'a> { None } - fn verify_no_symbol_conflicts(&self, root: &CrateRoot<'_>) -> Result<(), CrateError> { + fn verify_no_symbol_conflicts(&self, root: &CrateRoot) -> Result<(), CrateError> { // Check for (potential) conflicts with the local crate if self.sess.local_stable_crate_id() == root.stable_crate_id() { return Err(CrateError::SymbolConflictsCurrent(root.name())); @@ -342,7 +342,7 @@ impl<'a> CrateLoader<'a> { fn verify_no_stable_crate_id_hash_conflicts( &mut self, - root: &CrateRoot<'_>, + root: &CrateRoot, cnum: CrateNum, ) -> Result<(), CrateError> { if let Some(existing) = self.cstore.stable_crate_ids.insert(root.stable_crate_id(), cnum) { @@ -623,7 +623,7 @@ impl<'a> CrateLoader<'a> { fn resolve_crate_deps( &mut self, root: &CratePaths, - crate_root: &CrateRoot<'_>, + crate_root: &CrateRoot, metadata: &MetadataBlob, krate: CrateNum, dep_kind: CrateDepKind, diff --git a/compiler/rustc_metadata/src/dependency_format.rs b/compiler/rustc_metadata/src/dependency_format.rs index ddc3e10fa484f..245b2076ebca9 100644 --- a/compiler/rustc_metadata/src/dependency_format.rs +++ b/compiler/rustc_metadata/src/dependency_format.rs @@ -62,7 +62,7 @@ use rustc_session::cstore::CrateDepKind; use rustc_session::cstore::LinkagePreference::{self, RequireDynamic, RequireStatic}; use rustc_target::spec::PanicStrategy; -crate fn calculate(tcx: TyCtxt<'_>) -> Dependencies { +pub(crate) fn calculate(tcx: TyCtxt<'_>) -> Dependencies { tcx.sess .crate_types() .iter() diff --git a/compiler/rustc_metadata/src/foreign_modules.rs b/compiler/rustc_metadata/src/foreign_modules.rs index 70da96154b013..2ca4cd17fdf09 100644 --- a/compiler/rustc_metadata/src/foreign_modules.rs +++ b/compiler/rustc_metadata/src/foreign_modules.rs @@ -3,7 +3,7 @@ use rustc_hir::def::DefKind; use rustc_middle::ty::TyCtxt; use rustc_session::cstore::ForeignModule; -crate fn collect(tcx: TyCtxt<'_>) -> Vec { +pub(crate) fn collect(tcx: TyCtxt<'_>) -> Vec { let mut modules = Vec::new(); for id in tcx.hir().items() { if !matches!(tcx.def_kind(id.def_id), DefKind::ForeignMod) { diff --git a/compiler/rustc_metadata/src/lib.rs b/compiler/rustc_metadata/src/lib.rs index 2d13675e61550..eb008fd2693ba 100644 --- a/compiler/rustc_metadata/src/lib.rs +++ b/compiler/rustc_metadata/src/lib.rs @@ -1,8 +1,9 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] -#![feature(crate_visibility_modifier)] #![feature(decl_macro)] #![feature(drain_filter)] #![feature(generators)] +#![feature(generic_associated_types)] +#![feature(iter_from_generator)] #![feature(let_chains)] #![feature(let_else)] #![feature(nll)] @@ -11,6 +12,7 @@ #![feature(macro_metavar_expr)] #![feature(min_specialization)] #![feature(slice_as_chunks)] +#![feature(trusted_len)] #![feature(try_blocks)] #![feature(never_type)] #![recursion_limit = "256"] diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs index 43bda7c0734eb..dbe53224e2aaa 100644 --- a/compiler/rustc_metadata/src/locator.rs +++ b/compiler/rustc_metadata/src/locator.rs @@ -239,7 +239,7 @@ use std::{cmp, fmt, fs}; use tracing::{debug, info}; #[derive(Clone)] -crate struct CrateLocator<'a> { +pub(crate) struct CrateLocator<'a> { // Immutable per-session configuration. only_needs_metadata: bool, sysroot: &'a Path, @@ -260,19 +260,19 @@ crate struct CrateLocator<'a> { } #[derive(Clone)] -crate struct CratePaths { +pub(crate) struct CratePaths { name: Symbol, source: CrateSource, } impl CratePaths { - crate fn new(name: Symbol, source: CrateSource) -> CratePaths { + pub(crate) fn new(name: Symbol, source: CrateSource) -> CratePaths { CratePaths { name, source } } } #[derive(Copy, Clone, PartialEq)] -crate enum CrateFlavor { +pub(crate) enum CrateFlavor { Rlib, Rmeta, Dylib, @@ -289,7 +289,7 @@ impl fmt::Display for CrateFlavor { } impl<'a> CrateLocator<'a> { - crate fn new( + pub(crate) fn new( sess: &'a Session, metadata_loader: &'a dyn MetadataLoader, crate_name: Symbol, @@ -344,7 +344,7 @@ impl<'a> CrateLocator<'a> { } } - crate fn reset(&mut self) { + pub(crate) fn reset(&mut self) { self.crate_rejections.via_hash.clear(); self.crate_rejections.via_triple.clear(); self.crate_rejections.via_kind.clear(); @@ -353,7 +353,7 @@ impl<'a> CrateLocator<'a> { self.crate_rejections.via_invalid.clear(); } - crate fn maybe_load_library_crate(&mut self) -> Result, CrateError> { + pub(crate) fn maybe_load_library_crate(&mut self) -> Result, CrateError> { if !self.exact_paths.is_empty() { return self.find_commandline_library(); } @@ -728,7 +728,7 @@ impl<'a> CrateLocator<'a> { Ok(self.extract_lib(rlibs, rmetas, dylibs)?.map(|(_, lib)| lib)) } - crate fn into_error(self, root: Option) -> CrateError { + pub(crate) fn into_error(self, root: Option) -> CrateError { CrateError::LocatorCombined(CombinedLocatorError { crate_name: self.crate_name, root, @@ -894,7 +894,7 @@ struct CrateRejections { /// Candidate rejection reasons collected during crate search. /// If no candidate is accepted, then these reasons are presented to the user, /// otherwise they are ignored. -crate struct CombinedLocatorError { +pub(crate) struct CombinedLocatorError { crate_name: Symbol, root: Option, triple: TargetTriple, @@ -903,7 +903,7 @@ crate struct CombinedLocatorError { crate_rejections: CrateRejections, } -crate enum CrateError { +pub(crate) enum CrateError { NonAsciiName(Symbol), ExternLocationNotExist(Symbol, PathBuf), ExternLocationNotFile(Symbol, PathBuf), @@ -937,7 +937,7 @@ impl fmt::Display for MetadataError<'_> { } impl CrateError { - crate fn report(self, sess: &Session, span: Span, missing_core: bool) { + pub(crate) fn report(self, sess: &Session, span: Span, missing_core: bool) { let mut diag = match self { CrateError::NonAsciiName(crate_name) => sess.struct_span_err( span, diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs index 628516fa13827..95892d8341479 100644 --- a/compiler/rustc_metadata/src/native_libs.rs +++ b/compiler/rustc_metadata/src/native_libs.rs @@ -12,7 +12,7 @@ use rustc_session::Session; use rustc_span::symbol::{sym, Symbol}; use rustc_target::spec::abi::Abi; -crate fn collect(tcx: TyCtxt<'_>) -> Vec { +pub(crate) fn collect(tcx: TyCtxt<'_>) -> Vec { let mut collector = Collector { tcx, libs: Vec::new() }; for id in tcx.hir().items() { collector.process_item(id); @@ -21,7 +21,7 @@ crate fn collect(tcx: TyCtxt<'_>) -> Vec { collector.libs } -crate fn relevant_lib(sess: &Session, lib: &NativeLib) -> bool { +pub(crate) fn relevant_lib(sess: &Session, lib: &NativeLib) -> bool { match lib.cfg { Some(ref cfg) => attr::cfg_matches(cfg, &sess.parse_sess, CRATE_NODE_ID, None), None => true, @@ -418,10 +418,11 @@ impl<'tcx> Collector<'tcx> { // involved or not, library reordering and kind overriding without // explicit `:rename` in particular. if lib.has_modifiers() || passed_lib.has_modifiers() { - self.tcx.sess.span_err( - self.tcx.def_span(lib.foreign_module.unwrap()), - "overriding linking modifiers from command line is not supported" - ); + let msg = "overriding linking modifiers from command line is not supported"; + match lib.foreign_module { + Some(def_id) => self.tcx.sess.span_err(self.tcx.def_span(def_id), msg), + None => self.tcx.sess.err(msg), + }; } if passed_lib.kind != NativeLibKind::Unspecified { lib.kind = passed_lib.kind; diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index b25522cfd96a8..775ebb48402aa 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -1,35 +1,31 @@ // Decoding metadata from a single crate's metadata use crate::creader::{CStore, CrateMetadataRef}; -use crate::rmeta::table::{FixedSizeEncoding, Table}; use crate::rmeta::*; use rustc_ast as ast; use rustc_ast::ptr::P; -use rustc_attr as attr; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::svh::Svh; use rustc_data_structures::sync::{Lock, LockGuard, Lrc, OnceCell}; use rustc_data_structures::unhash::UnhashMap; use rustc_expand::base::{SyntaxExtension, SyntaxExtensionKind}; -use rustc_expand::proc_macro::{AttrProcMacro, BangProcMacro, ProcMacroDerive}; +use rustc_expand::proc_macro::{AttrProcMacro, BangProcMacro, DeriveProcMacro}; use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; use rustc_hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE}; use rustc_hir::definitions::{DefKey, DefPath, DefPathData, DefPathHash}; use rustc_hir::diagnostic_items::DiagnosticItems; use rustc_hir::lang_items; use rustc_index::vec::{Idx, IndexVec}; -use rustc_middle::arena::ArenaAllocatable; use rustc_middle::metadata::ModChild; use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo}; -use rustc_middle::middle::stability::DeprecationEntry; use rustc_middle::mir::interpret::{AllocDecodingSession, AllocDecodingState}; use rustc_middle::thir; use rustc_middle::ty::codec::TyDecoder; use rustc_middle::ty::fast_reject::SimplifiedType; use rustc_middle::ty::GeneratorDiagnosticData; -use rustc_middle::ty::{self, Ty, TyCtxt, Visibility}; +use rustc_middle::ty::{self, ParameterizedOverTcx, Ty, TyCtxt, Visibility}; use rustc_serialize::{opaque, Decodable, Decoder}; use rustc_session::cstore::{ CrateSource, ExternCrate, ForeignModule, LinkagePreference, NativeLib, @@ -42,6 +38,7 @@ use rustc_span::{self, BytePos, ExpnId, Pos, Span, SyntaxContext, DUMMY_SP}; use proc_macro::bridge::client::ProcMacro; use std::io; +use std::iter::TrustedLen; use std::mem; use std::num::NonZeroUsize; use std::path::Path; @@ -57,7 +54,7 @@ mod cstore_impl; /// A `MetadataBlob` internally is just a reference counted pointer to /// the actual data, so cloning it is cheap. #[derive(Clone)] -crate struct MetadataBlob(Lrc); +pub(crate) struct MetadataBlob(Lrc); // This is needed so we can create an OwningRef into the blob. // The data behind a `MetadataBlob` has a stable address because it is @@ -78,28 +75,27 @@ impl std::ops::Deref for MetadataBlob { // local crate numbers (as generated during this session). Each external // crate may refer to types in other external crates, and each has their // own crate numbers. -crate type CrateNumMap = IndexVec; +pub(crate) type CrateNumMap = IndexVec; -crate struct CrateMetadata { +pub(crate) struct CrateMetadata { /// The primary crate data - binary metadata blob. blob: MetadataBlob, // --- Some data pre-decoded from the metadata blob, usually for performance --- - /// Properties of the whole crate. /// NOTE(eddyb) we pass `'static` to a `'tcx` parameter because this /// lifetime is only used behind `Lazy`, and therefore acts like a /// universal (`for<'tcx>`), that is paired up with whichever `TyCtxt` /// is being used to decode those values. - root: CrateRoot<'static>, + root: CrateRoot, /// Trait impl data. /// FIXME: Used only from queries and can use query cache, /// so pre-decoding can probably be avoided. - trait_impls: FxHashMap<(u32, DefIndex), Lazy<[(DefIndex, Option)]>>, + trait_impls: FxHashMap<(u32, DefIndex), LazyArray<(DefIndex, Option)>>, /// Inherent impls which do not follow the normal coherence rules. /// /// These can be introduced using either `#![rustc_coherence_is_core]` /// or `#[rustc_allow_incoherent_impl]`. - incoherent_impls: FxHashMap>, + incoherent_impls: FxHashMap>, /// Proc macro descriptions for this crate, if it's a proc macro crate. raw_proc_macros: Option<&'static [ProcMacro]>, /// Source maps for code from the crate. @@ -265,138 +261,61 @@ impl<'a, 'tcx> Metadata<'a, 'tcx> for (CrateMetadataRef<'a>, TyCtxt<'tcx>) { } } -impl<'a, 'tcx, T: Decodable>> Lazy { - fn decode>(self, metadata: M) -> T { +impl LazyValue { + fn decode<'a, 'tcx, M: Metadata<'a, 'tcx>>(self, metadata: M) -> T::Value<'tcx> + where + T::Value<'tcx>: Decodable>, + { let mut dcx = metadata.decoder(self.position.get()); dcx.lazy_state = LazyState::NodeStart(self.position); - T::decode(&mut dcx) + T::Value::decode(&mut dcx) } } -impl<'a: 'x, 'tcx: 'x, 'x, T: Decodable>> Lazy<[T]> { - fn decode>( - self, - metadata: M, - ) -> impl ExactSizeIterator + Captures<'a> + Captures<'tcx> + 'x { - let mut dcx = metadata.decoder(self.position.get()); - dcx.lazy_state = LazyState::NodeStart(self.position); - (0..self.meta).map(move |_| T::decode(&mut dcx)) - } +struct DecodeIterator<'a, 'tcx, T> { + elem_counter: std::ops::Range, + dcx: DecodeContext<'a, 'tcx>, + _phantom: PhantomData T>, } -trait LazyQueryDecodable<'a, 'tcx, T> { - fn decode_query( - self, - cdata: CrateMetadataRef<'a>, - tcx: TyCtxt<'tcx>, - err: impl FnOnce() -> !, - ) -> T; -} +impl<'a, 'tcx, T: Decodable>> Iterator for DecodeIterator<'a, 'tcx, T> { + type Item = T; -impl<'a, 'tcx, T> LazyQueryDecodable<'a, 'tcx, T> for T { - fn decode_query(self, _: CrateMetadataRef<'a>, _: TyCtxt<'tcx>, _: impl FnOnce() -> !) -> T { - self + #[inline(always)] + fn next(&mut self) -> Option { + self.elem_counter.next().map(|_| T::decode(&mut self.dcx)) } -} -impl<'a, 'tcx, T> LazyQueryDecodable<'a, 'tcx, T> for Option { - fn decode_query(self, _: CrateMetadataRef<'a>, _: TyCtxt<'tcx>, err: impl FnOnce() -> !) -> T { - if let Some(l) = self { l } else { err() } + #[inline(always)] + fn size_hint(&self) -> (usize, Option) { + self.elem_counter.size_hint() } } -impl<'a, 'tcx, T> LazyQueryDecodable<'a, 'tcx, T> for Option> -where - T: Decodable>, +impl<'a, 'tcx, T: Decodable>> ExactSizeIterator + for DecodeIterator<'a, 'tcx, T> { - fn decode_query( - self, - cdata: CrateMetadataRef<'a>, - tcx: TyCtxt<'tcx>, - err: impl FnOnce() -> !, - ) -> T { - if let Some(l) = self { l.decode((cdata, tcx)) } else { err() } + fn len(&self) -> usize { + self.elem_counter.len() } } -impl<'a, 'tcx, T> LazyQueryDecodable<'a, 'tcx, &'tcx T> for Option> -where - T: Decodable>, - T: ArenaAllocatable<'tcx>, +unsafe impl<'a, 'tcx, T: Decodable>> TrustedLen + for DecodeIterator<'a, 'tcx, T> { - fn decode_query( - self, - cdata: CrateMetadataRef<'a>, - tcx: TyCtxt<'tcx>, - err: impl FnOnce() -> !, - ) -> &'tcx T { - if let Some(l) = self { tcx.arena.alloc(l.decode((cdata, tcx))) } else { err() } - } } -impl<'a, 'tcx, T> LazyQueryDecodable<'a, 'tcx, Option> for Option> -where - T: Decodable>, -{ - fn decode_query( +impl LazyArray { + fn decode<'a, 'tcx, M: Metadata<'a, 'tcx>>( self, - cdata: CrateMetadataRef<'a>, - tcx: TyCtxt<'tcx>, - _err: impl FnOnce() -> !, - ) -> Option { - self.map(|l| l.decode((cdata, tcx))) - } -} - -impl<'a, 'tcx, T, E> LazyQueryDecodable<'a, 'tcx, Result, E>> for Option> -where - T: Decodable>, -{ - fn decode_query( - self, - cdata: CrateMetadataRef<'a>, - tcx: TyCtxt<'tcx>, - _err: impl FnOnce() -> !, - ) -> Result, E> { - Ok(self.map(|l| l.decode((cdata, tcx)))) - } -} - -impl<'a, 'tcx, T> LazyQueryDecodable<'a, 'tcx, &'tcx [T]> for Option> -where - T: Decodable> + Copy, -{ - fn decode_query( - self, - cdata: CrateMetadataRef<'a>, - tcx: TyCtxt<'tcx>, - _err: impl FnOnce() -> !, - ) -> &'tcx [T] { - if let Some(l) = self { tcx.arena.alloc_from_iter(l.decode((cdata, tcx))) } else { &[] } - } -} - -impl<'a, 'tcx> LazyQueryDecodable<'a, 'tcx, Option> - for Option> -{ - fn decode_query( - self, - cdata: CrateMetadataRef<'a>, - tcx: TyCtxt<'tcx>, - _err: impl FnOnce() -> !, - ) -> Option { - self.map(|l| l.decode((cdata, tcx))).map(DeprecationEntry::external) - } -} - -impl<'a, 'tcx> LazyQueryDecodable<'a, 'tcx, Option> for Option { - fn decode_query( - self, - cdata: CrateMetadataRef<'a>, - _: TyCtxt<'tcx>, - _: impl FnOnce() -> !, - ) -> Option { - self.map(|raw_def_id| raw_def_id.decode(cdata)) + metadata: M, + ) -> DecodeIterator<'a, 'tcx, T::Value<'tcx>> + where + T::Value<'tcx>: Decodable>, + { + let mut dcx = metadata.decoder(self.position.get()); + dcx.lazy_state = LazyState::NodeStart(self.position); + DecodeIterator { elem_counter: (0..self.num_elems), dcx, _phantom: PhantomData } } } @@ -423,7 +342,8 @@ impl<'a, 'tcx> DecodeContext<'a, 'tcx> { self.cdata().map_encoded_cnum_to_current(cnum) } - fn read_lazy_with_meta(&mut self, meta: T::Meta) -> Lazy { + #[inline] + fn read_lazy_offset_then(&mut self, f: impl Fn(NonZeroUsize) -> T) -> T { let distance = self.read_usize(); let position = match self.lazy_state { LazyState::NoNode => bug!("read_lazy_with_meta: outside of a metadata node"), @@ -434,8 +354,21 @@ impl<'a, 'tcx> DecodeContext<'a, 'tcx> { } LazyState::Previous(last_pos) => last_pos.get() + distance, }; - self.lazy_state = LazyState::Previous(NonZeroUsize::new(position).unwrap()); - Lazy::from_position_and_meta(NonZeroUsize::new(position).unwrap(), meta) + let position = NonZeroUsize::new(position).unwrap(); + self.lazy_state = LazyState::Previous(position); + f(position) + } + + fn read_lazy(&mut self) -> LazyValue { + self.read_lazy_offset_then(|pos| LazyValue::from_position(pos)) + } + + fn read_lazy_array(&mut self, len: usize) -> LazyArray { + self.read_lazy_offset_then(|pos| LazyArray::from_position_and_num_elems(pos, len)) + } + + fn read_lazy_table(&mut self, len: usize) -> LazyTable { + self.read_lazy_offset_then(|pos| LazyTable::from_position_and_encoded_size(pos, len)) } #[inline] @@ -444,12 +377,14 @@ impl<'a, 'tcx> DecodeContext<'a, 'tcx> { } } -impl<'a, 'tcx> TyDecoder<'tcx> for DecodeContext<'a, 'tcx> { +impl<'a, 'tcx> TyDecoder for DecodeContext<'a, 'tcx> { const CLEAR_CROSS_CRATE: bool = true; + type I = TyCtxt<'tcx>; + #[inline] - fn tcx(&self) -> TyCtxt<'tcx> { - self.tcx.expect("missing TyCtxt in DecodeContext") + fn interner(&self) -> Self::I { + self.tcx() } #[inline] @@ -714,60 +649,53 @@ impl<'a, 'tcx> Decodable> for &'tcx [(ty::Predicate<'tcx } } -impl<'a, 'tcx, T: Decodable>> Decodable> - for Lazy -{ +impl<'a, 'tcx, T> Decodable> for LazyValue { fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> Self { - decoder.read_lazy_with_meta(()) + decoder.read_lazy() } } -impl<'a, 'tcx, T: Decodable>> Decodable> - for Lazy<[T]> -{ +impl<'a, 'tcx, T> Decodable> for LazyArray { fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> Self { let len = decoder.read_usize(); - if len == 0 { Lazy::empty() } else { decoder.read_lazy_with_meta(len) } + if len == 0 { LazyArray::empty() } else { decoder.read_lazy_array(len) } } } -impl<'a, 'tcx, I: Idx, T> Decodable> for Lazy> -where - Option: FixedSizeEncoding, -{ +impl<'a, 'tcx, I: Idx, T> Decodable> for LazyTable { fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> Self { let len = decoder.read_usize(); - decoder.read_lazy_with_meta(len) + decoder.read_lazy_table(len) } } implement_ty_decoder!(DecodeContext<'a, 'tcx>); -impl<'tcx> MetadataBlob { - crate fn new(metadata_ref: MetadataRef) -> MetadataBlob { +impl MetadataBlob { + pub(crate) fn new(metadata_ref: MetadataRef) -> MetadataBlob { MetadataBlob(Lrc::new(metadata_ref)) } - crate fn is_compatible(&self) -> bool { + pub(crate) fn is_compatible(&self) -> bool { self.blob().starts_with(METADATA_HEADER) } - crate fn get_rustc_version(&self) -> String { - Lazy::::from_position(NonZeroUsize::new(METADATA_HEADER.len() + 4).unwrap()) + pub(crate) fn get_rustc_version(&self) -> String { + LazyValue::::from_position(NonZeroUsize::new(METADATA_HEADER.len() + 4).unwrap()) .decode(self) } - crate fn get_root(&self) -> CrateRoot<'tcx> { + pub(crate) fn get_root(&self) -> CrateRoot { let slice = &self.blob()[..]; let offset = METADATA_HEADER.len(); let pos = (((slice[offset + 0] as u32) << 24) | ((slice[offset + 1] as u32) << 16) | ((slice[offset + 2] as u32) << 8) | ((slice[offset + 3] as u32) << 0)) as usize; - Lazy::>::from_position(NonZeroUsize::new(pos).unwrap()).decode(self) + LazyValue::::from_position(NonZeroUsize::new(pos).unwrap()).decode(self) } - crate fn list_crate_metadata(&self, out: &mut dyn io::Write) -> io::Result<()> { + pub(crate) fn list_crate_metadata(&self, out: &mut dyn io::Write) -> io::Result<()> { let root = self.get_root(); writeln!(out, "Crate info:")?; writeln!(out, "name {}{}", root.name, root.extra_filename)?; @@ -791,28 +719,28 @@ impl<'tcx> MetadataBlob { } } -impl CrateRoot<'_> { - crate fn is_proc_macro_crate(&self) -> bool { +impl CrateRoot { + pub(crate) fn is_proc_macro_crate(&self) -> bool { self.proc_macro_data.is_some() } - crate fn name(&self) -> Symbol { + pub(crate) fn name(&self) -> Symbol { self.name } - crate fn hash(&self) -> Svh { + pub(crate) fn hash(&self) -> Svh { self.hash } - crate fn stable_crate_id(&self) -> StableCrateId { + pub(crate) fn stable_crate_id(&self) -> StableCrateId { self.stable_crate_id } - crate fn triple(&self) -> &TargetTriple { + pub(crate) fn triple(&self) -> &TargetTriple { &self.triple } - crate fn decode_crate_deps<'a>( + pub(crate) fn decode_crate_deps<'a>( &self, metadata: &'a MetadataBlob, ) -> impl ExactSizeIterator + Captures<'a> { @@ -911,7 +839,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { attributes.iter().cloned().map(Symbol::intern).collect::>(); ( trait_name, - SyntaxExtensionKind::Derive(Box::new(ProcMacroDerive { client })), + SyntaxExtensionKind::Derive(Box::new(DeriveProcMacro { client })), helper_attrs, ) } @@ -963,7 +891,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { .tables .children .get(self, index) - .unwrap_or_else(Lazy::empty) + .unwrap_or_else(LazyArray::empty) .decode(self) .map(|index| ty::FieldDef { did: self.local_def_id(index), @@ -996,7 +924,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { .tables .children .get(self, item_id) - .unwrap_or_else(Lazy::empty) + .unwrap_or_else(LazyArray::empty) .decode(self) .map(|index| self.get_variant(&self.kind(index), index, did)) .collect() @@ -1016,7 +944,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } fn get_trait_item_def_id(self, id: DefIndex) -> Option { - self.root.tables.trait_item_def_id.get(self, id).map(|d| d.decode(self)) + self.root.tables.trait_item_def_id.get(self, id).map(|d| d.decode_from_cdata(self)) } fn get_expn_that_defined(self, id: DefIndex, sess: &Session) -> ExpnId { @@ -1202,7 +1130,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { .tables .children .get(self, id) - .unwrap_or_else(Lazy::empty) + .unwrap_or_else(LazyArray::empty) .decode((self, sess)) .map(move |child_index| self.local_def_id(child_index)) } @@ -1278,7 +1206,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { .tables .children .get(self, id) - .unwrap_or_else(Lazy::empty) + .unwrap_or_else(LazyArray::empty) .decode(self) .map(move |index| respan(self.get_span(index, sess), self.item_name(index))) } @@ -1288,7 +1216,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { .tables .children .get(self, id) - .unwrap_or_else(Lazy::empty) + .unwrap_or_else(LazyArray::empty) .decode(self) .map(move |field_index| self.get_visibility(field_index)) } @@ -1303,7 +1231,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { .tables .inherent_impls .get(self, id) - .unwrap_or_else(Lazy::empty) + .unwrap_or_else(LazyArray::empty) .decode(self) .map(|index| self.local_def_id(index)), ) @@ -1318,7 +1246,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { .tables .inherent_impls .get(self, ty_index) - .unwrap_or_else(Lazy::empty) + .unwrap_or_else(LazyArray::empty) .decode(self) .map(move |impl_index| (ty_def_id, self.local_def_id(impl_index))) }) @@ -1639,10 +1567,10 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { src_hash, start_pos, end_pos, - mut lines, - mut multibyte_chars, - mut non_narrow_chars, - mut normalized_pos, + lines, + multibyte_chars, + non_narrow_chars, + normalized_pos, name_hash, .. } = source_file_to_import; @@ -1679,24 +1607,6 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { let source_length = (end_pos - start_pos).to_usize(); - // Translate line-start positions and multibyte character - // position into frame of reference local to file. - // `SourceMap::new_imported_source_file()` will then translate those - // coordinates to their new global frame of reference when the - // offset of the SourceFile is known. - for pos in &mut lines { - *pos = *pos - start_pos; - } - for mbc in &mut multibyte_chars { - mbc.pos = mbc.pos - start_pos; - } - for swc in &mut non_narrow_chars { - *swc = *swc - start_pos; - } - for np in &mut normalized_pos { - np.pos = np.pos - start_pos; - } - let local_version = sess.source_map().new_imported_source_file( name, src_hash, @@ -1752,14 +1662,18 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { fn get_may_have_doc_links(self, index: DefIndex) -> bool { self.root.tables.may_have_doc_links.get(self, index).is_some() } + + fn get_is_intrinsic(self, index: DefIndex) -> bool { + self.root.tables.is_intrinsic.get(self, index).is_some() + } } impl CrateMetadata { - crate fn new( + pub(crate) fn new( sess: &Session, cstore: &CStore, blob: MetadataBlob, - root: CrateRoot<'static>, + root: CrateRoot, raw_proc_macros: Option<&'static [ProcMacro]>, cnum: CrateNum, cnum_map: CrateNumMap, @@ -1815,15 +1729,15 @@ impl CrateMetadata { cdata } - crate fn dependencies(&self) -> LockGuard<'_, Vec> { + pub(crate) fn dependencies(&self) -> LockGuard<'_, Vec> { self.dependencies.borrow() } - crate fn add_dependency(&self, cnum: CrateNum) { + pub(crate) fn add_dependency(&self, cnum: CrateNum) { self.dependencies.borrow_mut().push(cnum); } - crate fn update_extern_crate(&self, new_extern_crate: ExternCrate) -> bool { + pub(crate) fn update_extern_crate(&self, new_extern_crate: ExternCrate) -> bool { let mut extern_crate = self.extern_crate.borrow_mut(); let update = Some(new_extern_crate.rank()) > extern_crate.as_ref().map(ExternCrate::rank); if update { @@ -1832,59 +1746,59 @@ impl CrateMetadata { update } - crate fn source(&self) -> &CrateSource { + pub(crate) fn source(&self) -> &CrateSource { &*self.source } - crate fn dep_kind(&self) -> CrateDepKind { + pub(crate) fn dep_kind(&self) -> CrateDepKind { *self.dep_kind.lock() } - crate fn update_dep_kind(&self, f: impl FnOnce(CrateDepKind) -> CrateDepKind) { + pub(crate) fn update_dep_kind(&self, f: impl FnOnce(CrateDepKind) -> CrateDepKind) { self.dep_kind.with_lock(|dep_kind| *dep_kind = f(*dep_kind)) } - crate fn panic_strategy(&self) -> PanicStrategy { + pub(crate) fn panic_strategy(&self) -> PanicStrategy { self.root.panic_strategy } - crate fn needs_panic_runtime(&self) -> bool { + pub(crate) fn needs_panic_runtime(&self) -> bool { self.root.needs_panic_runtime } - crate fn is_panic_runtime(&self) -> bool { + pub(crate) fn is_panic_runtime(&self) -> bool { self.root.panic_runtime } - crate fn is_profiler_runtime(&self) -> bool { + pub(crate) fn is_profiler_runtime(&self) -> bool { self.root.profiler_runtime } - crate fn needs_allocator(&self) -> bool { + pub(crate) fn needs_allocator(&self) -> bool { self.root.needs_allocator } - crate fn has_global_allocator(&self) -> bool { + pub(crate) fn has_global_allocator(&self) -> bool { self.root.has_global_allocator } - crate fn has_default_lib_allocator(&self) -> bool { + pub(crate) fn has_default_lib_allocator(&self) -> bool { self.root.has_default_lib_allocator } - crate fn is_proc_macro_crate(&self) -> bool { + pub(crate) fn is_proc_macro_crate(&self) -> bool { self.root.is_proc_macro_crate() } - crate fn name(&self) -> Symbol { + pub(crate) fn name(&self) -> Symbol { self.root.name } - crate fn stable_crate_id(&self) -> StableCrateId { + pub(crate) fn stable_crate_id(&self) -> StableCrateId { self.root.stable_crate_id } - crate fn hash(&self) -> Svh { + pub(crate) fn hash(&self) -> Svh { self.root.hash } diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 9f7ef3981c75b..e3581a7607fb8 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -1,14 +1,16 @@ -use super::LazyQueryDecodable; use crate::creader::{CStore, LoadedMacro}; use crate::foreign_modules; use crate::native_libs; use rustc_ast as ast; +use rustc_attr::Deprecation; use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LOCAL_CRATE}; use rustc_hir::definitions::{DefKey, DefPath, DefPathHash}; +use rustc_middle::arena::ArenaAllocatable; use rustc_middle::metadata::ModChild; use rustc_middle::middle::exported_symbols::ExportedSymbol; +use rustc_middle::middle::stability::DeprecationEntry; use rustc_middle::ty::fast_reject::SimplifiedType; use rustc_middle::ty::query::{ExternProviders, Providers}; use rustc_middle::ty::{self, TyCtxt, Visibility}; @@ -23,15 +25,80 @@ use rustc_data_structures::sync::Lrc; use smallvec::SmallVec; use std::any::Any; +use super::{Decodable, DecodeContext, DecodeIterator}; + +trait ProcessQueryValue<'tcx, T> { + fn process_decoded(self, _tcx: TyCtxt<'tcx>, _err: impl Fn() -> !) -> T; +} + +impl ProcessQueryValue<'_, Option> for Option { + #[inline(always)] + fn process_decoded(self, _tcx: TyCtxt<'_>, _err: impl Fn() -> !) -> Option { + self + } +} + +impl ProcessQueryValue<'_, T> for Option { + #[inline(always)] + fn process_decoded(self, _tcx: TyCtxt<'_>, err: impl Fn() -> !) -> T { + if let Some(value) = self { value } else { err() } + } +} + +impl<'tcx, T: ArenaAllocatable<'tcx>> ProcessQueryValue<'tcx, &'tcx T> for Option { + #[inline(always)] + fn process_decoded(self, tcx: TyCtxt<'tcx>, err: impl Fn() -> !) -> &'tcx T { + if let Some(value) = self { tcx.arena.alloc(value) } else { err() } + } +} + +impl ProcessQueryValue<'_, Result, E>> for Option { + #[inline(always)] + fn process_decoded(self, _tcx: TyCtxt<'_>, _err: impl Fn() -> !) -> Result, E> { + Ok(self) + } +} + +impl<'a, 'tcx, T: Copy + Decodable>> ProcessQueryValue<'tcx, &'tcx [T]> + for Option> +{ + #[inline(always)] + fn process_decoded(self, tcx: TyCtxt<'tcx>, _err: impl Fn() -> !) -> &'tcx [T] { + if let Some(iter) = self { tcx.arena.alloc_from_iter(iter) } else { &[] } + } +} + +impl ProcessQueryValue<'_, Option> for Option { + #[inline(always)] + fn process_decoded(self, _tcx: TyCtxt<'_>, _err: impl Fn() -> !) -> Option { + self.map(DeprecationEntry::external) + } +} + macro_rules! provide_one { (<$lt:tt> $tcx:ident, $def_id:ident, $other:ident, $cdata:ident, $name:ident => { table }) => { provide_one! { <$lt> $tcx, $def_id, $other, $cdata, $name => { - $cdata.root.tables.$name.get($cdata, $def_id.index).decode_query( - $cdata, - $tcx, - || panic!("{:?} does not have a {:?}", $def_id, stringify!($name)), - ) + $cdata + .root + .tables + .$name + .get($cdata, $def_id.index) + .map(|lazy| lazy.decode(($cdata, $tcx))) + .process_decoded($tcx, || panic!("{:?} does not have a {:?}", $def_id, stringify!($name))) + } + } + }; + (<$lt:tt> $tcx:ident, $def_id:ident, $other:ident, $cdata:ident, $name:ident => { table_direct }) => { + provide_one! { + <$lt> $tcx, $def_id, $other, $cdata, $name => { + // We don't decode `table_direct`, since it's not a Lazy, but an actual value + $cdata + .root + .tables + .$name + .get($cdata, $def_id.index) + .process_decoded($tcx, || panic!("{:?} does not have a {:?}", $def_id, stringify!($name))) } } }; @@ -143,15 +210,15 @@ provide! { <'tcx> tcx, def_id, other, cdata, lookup_deprecation_entry => { table } visibility => { table } unused_generic_params => { table } - opt_def_kind => { table } + opt_def_kind => { table_direct } impl_parent => { table } - impl_polarity => { table } - impl_defaultness => { table } - impl_constness => { table } + impl_polarity => { table_direct } + impl_defaultness => { table_direct } + impl_constness => { table_direct } coerce_unsized_info => { table } mir_const_qualif => { table } rendered_const => { table } - asyncness => { table } + asyncness => { table_direct } fn_arg_names => { table } generator_kind => { table } trait_def => { table } @@ -224,6 +291,7 @@ provide! { <'tcx> tcx, def_id, other, cdata, tcx.arena.alloc_slice(&result) } defined_lib_features => { cdata.get_lib_features(tcx) } + is_intrinsic => { cdata.get_is_intrinsic(def_id.index) } defined_lang_items => { cdata.get_lang_items(tcx) } diagnostic_items => { cdata.get_diagnostic_items() } missing_lang_items => { cdata.get_missing_lang_items(tcx) } diff --git a/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs b/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs index d66f2b031a893..15fd190b0492a 100644 --- a/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs +++ b/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs @@ -3,14 +3,19 @@ use crate::rmeta::EncodeContext; use crate::rmeta::MetadataBlob; use rustc_data_structures::owning_ref::OwningRef; use rustc_hir::def_path_hash_map::{Config as HashMapConfig, DefPathHashMap}; +use rustc_middle::parameterized_over_tcx; use rustc_serialize::{opaque, Decodable, Decoder, Encodable, Encoder}; use rustc_span::def_id::{DefIndex, DefPathHash}; -crate enum DefPathHashMapRef<'tcx> { +pub(crate) enum DefPathHashMapRef<'tcx> { OwnedFromMetadata(odht::HashTable>), BorrowedFromTcx(&'tcx DefPathHashMap), } +parameterized_over_tcx! { + DefPathHashMapRef, +} + impl DefPathHashMapRef<'_> { #[inline] pub fn def_path_hash_to_def_index(&self, def_path_hash: &DefPathHash) -> DefIndex { diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 1de7dae3c25cb..f67e1cab16d9c 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1,10 +1,9 @@ use crate::rmeta::def_path_hash_map::DefPathHashMapRef; -use crate::rmeta::table::{FixedSizeEncoding, TableBuilder}; +use crate::rmeta::table::TableBuilder; use crate::rmeta::*; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; -use rustc_data_structures::iter_from_generator; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::sync::{join, par_iter, Lrc, ParallelIterator}; use rustc_hir as hir; @@ -14,18 +13,15 @@ use rustc_hir::def_id::{ }; use rustc_hir::definitions::DefPathData; use rustc_hir::intravisit::{self, Visitor}; -use rustc_hir::itemlikevisit::ItemLikeVisitor; use rustc_hir::lang_items; use rustc_hir::{AnonConst, GenericParamKind}; use rustc_index::bit_set::GrowableBitSet; -use rustc_index::vec::Idx; use rustc_middle::hir::nested_filter; use rustc_middle::middle::dependency_format::Linkage; use rustc_middle::middle::exported_symbols::{ metadata_symbol_name, ExportedSymbol, SymbolExportInfo, }; use rustc_middle::mir::interpret; -use rustc_middle::thir; use rustc_middle::traits::specialization_graph; use rustc_middle::ty::codec::TyEncoder; use rustc_middle::ty::fast_reject::{self, SimplifiedType, TreatParams}; @@ -34,18 +30,16 @@ use rustc_middle::ty::{self, SymbolName, Ty, TyCtxt}; use rustc_serialize::{opaque, Encodable, Encoder}; use rustc_session::config::CrateType; use rustc_session::cstore::{ForeignModule, LinkagePreference, NativeLib}; +use rustc_span::hygiene::{ExpnIndex, HygieneEncodeContext, MacroKind}; use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::{ self, DebuggerVisualizerFile, ExternalSource, FileName, SourceFile, Span, SyntaxContext, }; -use rustc_span::{ - hygiene::{ExpnIndex, HygieneEncodeContext, MacroKind}, - RealFileName, -}; use rustc_target::abi::VariantIdx; +use std::borrow::Borrow; use std::hash::Hash; +use std::iter; use std::num::NonZeroUsize; -use std::path::Path; use tracing::{debug, trace}; pub(super) struct EncodeContext<'a, 'tcx> { @@ -53,7 +47,7 @@ pub(super) struct EncodeContext<'a, 'tcx> { tcx: TyCtxt<'tcx>, feat: &'tcx rustc_feature::Features, - tables: TableBuilders<'tcx>, + tables: TableBuilders, lazy_state: LazyState, type_shorthands: FxHashMap, usize>, @@ -85,7 +79,7 @@ pub(super) struct EncodeContext<'a, 'tcx> { macro_rules! empty_proc_macro { ($self:ident) => { if $self.is_proc_macro { - return Lazy::empty(); + return LazyArray::empty(); } }; } @@ -130,33 +124,26 @@ impl<'a, 'tcx> Encoder for EncodeContext<'a, 'tcx> { } } -impl<'a, 'tcx, T: Encodable>> Encodable> - for Lazy -{ +impl<'a, 'tcx, T> Encodable> for LazyValue { fn encode(&self, e: &mut EncodeContext<'a, 'tcx>) -> opaque::EncodeResult { - e.emit_lazy_distance(*self) + e.emit_lazy_distance(self.position) } } -impl<'a, 'tcx, T: Encodable>> Encodable> - for Lazy<[T]> -{ +impl<'a, 'tcx, T> Encodable> for LazyArray { fn encode(&self, e: &mut EncodeContext<'a, 'tcx>) -> opaque::EncodeResult { - e.emit_usize(self.meta)?; - if self.meta == 0 { + e.emit_usize(self.num_elems)?; + if self.num_elems == 0 { return Ok(()); } - e.emit_lazy_distance(*self) + e.emit_lazy_distance(self.position) } } -impl<'a, 'tcx, I: Idx, T> Encodable> for Lazy> -where - Option: FixedSizeEncoding, -{ +impl<'a, 'tcx, I, T> Encodable> for LazyTable { fn encode(&self, e: &mut EncodeContext<'a, 'tcx>) -> opaque::EncodeResult { - e.emit_usize(self.meta)?; - e.emit_lazy_distance(*self) + e.emit_usize(self.encoded_size)?; + e.emit_lazy_distance(self.position) } } @@ -326,9 +313,11 @@ impl<'a, 'tcx> Encodable> for Span { } } -impl<'a, 'tcx> TyEncoder<'tcx> for EncodeContext<'a, 'tcx> { +impl<'a, 'tcx> TyEncoder for EncodeContext<'a, 'tcx> { const CLEAR_CROSS_CRATE: bool = true; + type I = TyCtxt<'tcx>; + fn position(&self) -> usize { self.opaque.position() } @@ -351,46 +340,7 @@ impl<'a, 'tcx> TyEncoder<'tcx> for EncodeContext<'a, 'tcx> { } } -impl<'a, 'tcx> Encodable> for &'tcx [thir::abstract_const::Node<'tcx>] { - fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) -> opaque::EncodeResult { - (**self).encode(s) - } -} - -impl<'a, 'tcx> Encodable> for &'tcx [(ty::Predicate<'tcx>, Span)] { - fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) -> opaque::EncodeResult { - (**self).encode(s) - } -} - -/// Helper trait to allow overloading `EncodeContext::lazy` for iterators. -trait EncodeContentsForLazy<'a, 'tcx, T: ?Sized + LazyMeta> { - fn encode_contents_for_lazy(self, ecx: &mut EncodeContext<'a, 'tcx>) -> T::Meta; -} - -impl<'a, 'tcx, T: Encodable>> EncodeContentsForLazy<'a, 'tcx, T> for &T { - fn encode_contents_for_lazy(self, ecx: &mut EncodeContext<'a, 'tcx>) { - self.encode(ecx).unwrap() - } -} - -impl<'a, 'tcx, T: Encodable>> EncodeContentsForLazy<'a, 'tcx, T> for T { - fn encode_contents_for_lazy(self, ecx: &mut EncodeContext<'a, 'tcx>) { - self.encode(ecx).unwrap() - } -} - -impl<'a, 'tcx, I, T: Encodable>> EncodeContentsForLazy<'a, 'tcx, [T]> for I -where - I: IntoIterator, - I::Item: EncodeContentsForLazy<'a, 'tcx, T>, -{ - fn encode_contents_for_lazy(self, ecx: &mut EncodeContext<'a, 'tcx>) -> usize { - self.into_iter().map(|value| value.encode_contents_for_lazy(ecx)).count() - } -} - -// Shorthand for `$self.$tables.$table.set($def_id.index, $self.lazy($value))`, which would +// Shorthand for `$self.$tables.$table.set($def_id.index, $self.lazy_value($value))`, which would // normally need extra variables to avoid errors about multiple mutable borrows. macro_rules! record { ($self:ident.$tables:ident.$table:ident[$def_id:expr] <- $value:expr) => {{ @@ -402,12 +352,24 @@ macro_rules! record { }}; } +// Shorthand for `$self.$tables.$table.set($def_id.index, $self.lazy_value($value))`, which would +// normally need extra variables to avoid errors about multiple mutable borrows. +macro_rules! record_array { + ($self:ident.$tables:ident.$table:ident[$def_id:expr] <- $value:expr) => {{ + { + let value = $value; + let lazy = $self.lazy_array(value); + $self.$tables.$table.set($def_id.index, lazy); + } + }}; +} + impl<'a, 'tcx> EncodeContext<'a, 'tcx> { - fn emit_lazy_distance( + fn emit_lazy_distance( &mut self, - lazy: Lazy, + position: NonZeroUsize, ) -> Result<(), ::Error> { - let pos = lazy.position.get(); + let pos = position.get(); let distance = match self.lazy_state { LazyState::NoNode => bug!("emit_lazy_distance: outside of a metadata node"), LazyState::NodeStart(start) => { @@ -417,31 +379,50 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } LazyState::Previous(last_pos) => { assert!( - last_pos <= lazy.position, + last_pos <= position, "make sure that the calls to `lazy*` \ are in the same order as the metadata fields", ); - lazy.position.get() - last_pos.get() + position.get() - last_pos.get() } }; self.lazy_state = LazyState::Previous(NonZeroUsize::new(pos).unwrap()); self.emit_usize(distance) } - fn lazy( + fn lazy>>(&mut self, value: B) -> LazyValue + where + T::Value<'tcx>: Encodable>, + { + let pos = NonZeroUsize::new(self.position()).unwrap(); + + assert_eq!(self.lazy_state, LazyState::NoNode); + self.lazy_state = LazyState::NodeStart(pos); + value.borrow().encode(self).unwrap(); + self.lazy_state = LazyState::NoNode; + + assert!(pos.get() <= self.position()); + + LazyValue::from_position(pos) + } + + fn lazy_array, B: Borrow>>( &mut self, - value: impl EncodeContentsForLazy<'a, 'tcx, T>, - ) -> Lazy { + values: I, + ) -> LazyArray + where + T::Value<'tcx>: Encodable>, + { let pos = NonZeroUsize::new(self.position()).unwrap(); assert_eq!(self.lazy_state, LazyState::NoNode); self.lazy_state = LazyState::NodeStart(pos); - let meta = value.encode_contents_for_lazy(self); + let len = values.into_iter().map(|value| value.borrow().encode(self).unwrap()).count(); self.lazy_state = LazyState::NoNode; assert!(pos.get() <= self.position()); - Lazy::from_position_and_meta(pos, meta) + LazyArray::from_position_and_num_elems(pos, len) } fn encode_info_for_items(&mut self) { @@ -453,7 +434,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { return; } - self.tcx.hir().visit_all_item_likes(&mut self.as_deep_visitor()); + self.tcx.hir().deep_visit_all_item_likes(self); } fn encode_def_path_table(&mut self) { @@ -476,13 +457,13 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } } - fn encode_def_path_hash_map(&mut self) -> Lazy> { + fn encode_def_path_hash_map(&mut self) -> LazyValue> { self.lazy(DefPathHashMapRef::BorrowedFromTcx( self.tcx.resolutions(()).definitions.def_path_hash_to_def_index_map(), )) } - fn encode_source_map(&mut self) -> Lazy<[rustc_span::SourceFile]> { + fn encode_source_map(&mut self) -> LazyArray { let source_map = self.tcx.sess.source_map(); let all_source_files = source_map.files(); @@ -491,6 +472,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { // is done. let required_source_files = self.required_source_files.take().unwrap(); + let working_directory = &self.tcx.sess.opts.working_dir; + let adapted = all_source_files .iter() .enumerate() @@ -503,66 +486,40 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { (!source_file.is_imported() || self.is_proc_macro) }) .map(|(_, source_file)| { - let mut adapted = match source_file.name { - FileName::Real(ref realname) => { - let mut adapted = (**source_file).clone(); - adapted.name = FileName::Real(match realname { - RealFileName::LocalPath(path_to_file) => { - // Prepend path of working directory onto potentially - // relative paths, because they could become relative - // to a wrong directory. - // We include `working_dir` as part of the crate hash, - // so it's okay for us to use it as part of the encoded - // metadata. - let working_dir = &self.tcx.sess.opts.working_dir; - match working_dir { - RealFileName::LocalPath(absolute) => { - // Although neither working_dir or the file name were subject - // to path remapping, the concatenation between the two may - // be. Hence we need to do a remapping here. - let joined = Path::new(absolute).join(path_to_file); - let (joined, remapped) = - source_map.path_mapping().map_prefix(joined); - if remapped { - RealFileName::Remapped { - local_path: None, - virtual_name: joined, - } - } else { - RealFileName::LocalPath(joined) - } - } - RealFileName::Remapped { local_path: _, virtual_name } => { - // If working_dir has been remapped, then we emit - // Remapped variant as the expanded path won't be valid - RealFileName::Remapped { - local_path: None, - virtual_name: Path::new(virtual_name) - .join(path_to_file), - } - } - } - } - RealFileName::Remapped { local_path: _, virtual_name } => { - RealFileName::Remapped { - // We do not want any local path to be exported into metadata - local_path: None, - virtual_name: virtual_name.clone(), - } - } - }); - adapted.name_hash = { - let mut hasher: StableHasher = StableHasher::new(); - adapted.name.hash(&mut hasher); - hasher.finish::() - }; - Lrc::new(adapted) + // At export time we expand all source file paths to absolute paths because + // downstream compilation sessions can have a different compiler working + // directory, so relative paths from this or any other upstream crate + // won't be valid anymore. + // + // At this point we also erase the actual on-disk path and only keep + // the remapped version -- as is necessary for reproducible builds. + match source_file.name { + FileName::Real(ref original_file_name) => { + let adapted_file_name = + source_map.path_mapping().to_embeddable_absolute_path( + original_file_name.clone(), + working_directory, + ); + + if adapted_file_name != *original_file_name { + let mut adapted: SourceFile = (**source_file).clone(); + adapted.name = FileName::Real(adapted_file_name); + adapted.name_hash = { + let mut hasher: StableHasher = StableHasher::new(); + adapted.name.hash(&mut hasher); + hasher.finish::() + }; + Lrc::new(adapted) + } else { + // Nothing to adapt + source_file.clone() + } } - // expanded code, not from a file _ => source_file.clone(), - }; - + } + }) + .map(|mut source_file| { // We're serializing this `SourceFile` into our crate metadata, // so mark it as coming from this crate. // This also ensures that we don't try to deserialize the @@ -570,20 +527,22 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { // dependencies aren't loaded when we deserialize a proc-macro, // trying to remap the `CrateNum` would fail. if self.is_proc_macro { - Lrc::make_mut(&mut adapted).cnum = LOCAL_CRATE; + Lrc::make_mut(&mut source_file).cnum = LOCAL_CRATE; } - adapted + source_file }) .collect::>(); - self.lazy(adapted.iter().map(|rc| &**rc)) + self.lazy_array(adapted.iter().map(|rc| &**rc)) } - fn encode_crate_root(&mut self) -> Lazy> { + fn encode_crate_root(&mut self) -> LazyValue { let tcx = self.tcx; - let mut i = self.position(); + let mut i = 0; + let preamble_bytes = self.position() - i; // Encode the crate deps + i = self.position(); let crate_deps = self.encode_crate_deps(); let dylib_dependency_formats = self.encode_dylib_dependency_formats(); let dep_bytes = self.position() - i; @@ -609,7 +568,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let native_libraries = self.encode_native_libraries(); let native_lib_bytes = self.position() - i; + i = self.position(); let foreign_modules = self.encode_foreign_modules(); + let foreign_modules_bytes = self.position() - i; // Encode DefPathTable i = self.position(); @@ -629,6 +590,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { i = self.position(); let incoherent_impls = self.encode_incoherent_impls(); let incoherent_impls_bytes = self.position() - i; + // Encode MIR. i = self.position(); self.encode_mir(); @@ -641,6 +603,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let item_bytes = self.position() - i; // Encode the allocation index + i = self.position(); let interpret_alloc_index = { let mut interpret_alloc_index = Vec::new(); let mut n = 0; @@ -661,8 +624,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } n = new_n; } - self.lazy(interpret_alloc_index) + self.lazy_array(interpret_alloc_index) }; + let interpret_alloc_index_bytes = self.position() - i; // Encode the proc macro data. This affects 'tables', // so we need to do this before we encode the tables @@ -707,9 +671,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let source_map = self.encode_source_map(); let source_map_bytes = self.position() - i; + i = self.position(); let attrs = tcx.hir().krate_attrs(); let has_default_lib_allocator = tcx.sess.contains_name(&attrs, sym::default_lib_allocator); - let root = self.lazy(CrateRoot { name: tcx.crate_name(LOCAL_CRATE), extra_filename: tcx.sess.opts.cg.extra_filename.clone(), @@ -752,9 +716,34 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { expn_hashes, def_path_hash_map, }); + let final_bytes = self.position() - i; let total_bytes = self.position(); + let computed_total_bytes = preamble_bytes + + dep_bytes + + lib_feature_bytes + + lang_item_bytes + + diagnostic_item_bytes + + native_lib_bytes + + foreign_modules_bytes + + def_path_table_bytes + + traits_bytes + + impls_bytes + + incoherent_impls_bytes + + mir_bytes + + item_bytes + + interpret_alloc_index_bytes + + proc_macro_data_bytes + + tables_bytes + + debugger_visualizers_bytes + + exported_symbols_bytes + + hygiene_bytes + + def_path_hash_map_bytes + + source_map_bytes + + final_bytes; + assert_eq!(total_bytes, computed_total_bytes); + if tcx.sess.meta_stats() { let mut zero_bytes = 0; for e in self.opaque.data.iter() { @@ -763,27 +752,41 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } } - eprintln!("metadata stats:"); - eprintln!(" dep bytes: {}", dep_bytes); - eprintln!(" lib feature bytes: {}", lib_feature_bytes); - eprintln!(" lang item bytes: {}", lang_item_bytes); - eprintln!(" diagnostic item bytes: {}", diagnostic_item_bytes); - eprintln!(" native bytes: {}", native_lib_bytes); - eprintln!(" debugger visualizers bytes: {}", debugger_visualizers_bytes); - eprintln!(" source_map bytes: {}", source_map_bytes); - eprintln!(" traits bytes: {}", traits_bytes); - eprintln!(" impls bytes: {}", impls_bytes); - eprintln!(" incoherent_impls bytes: {}", incoherent_impls_bytes); - eprintln!(" exp. symbols bytes: {}", exported_symbols_bytes); - eprintln!(" def-path table bytes: {}", def_path_table_bytes); - eprintln!(" def-path hashes bytes: {}", def_path_hash_map_bytes); - eprintln!(" proc-macro-data-bytes: {}", proc_macro_data_bytes); - eprintln!(" mir bytes: {}", mir_bytes); - eprintln!(" item bytes: {}", item_bytes); - eprintln!(" table bytes: {}", tables_bytes); - eprintln!(" hygiene bytes: {}", hygiene_bytes); - eprintln!(" zero bytes: {}", zero_bytes); - eprintln!(" total bytes: {}", total_bytes); + let perc = |bytes| (bytes * 100) as f64 / total_bytes as f64; + let p = |label, bytes| { + eprintln!("{:>21}: {:>8} bytes ({:4.1}%)", label, bytes, perc(bytes)); + }; + + eprintln!(""); + eprintln!( + "{} metadata bytes, of which {} bytes ({:.1}%) are zero", + total_bytes, + zero_bytes, + perc(zero_bytes) + ); + p("preamble", preamble_bytes); + p("dep", dep_bytes); + p("lib feature", lib_feature_bytes); + p("lang item", lang_item_bytes); + p("diagnostic item", diagnostic_item_bytes); + p("native lib", native_lib_bytes); + p("foreign modules", foreign_modules_bytes); + p("def-path table", def_path_table_bytes); + p("traits", traits_bytes); + p("impls", impls_bytes); + p("incoherent_impls", incoherent_impls_bytes); + p("mir", mir_bytes); + p("item", item_bytes); + p("interpret_alloc_index", interpret_alloc_index_bytes); + p("proc-macro-data", proc_macro_data_bytes); + p("tables", tables_bytes); + p("debugger visualizers", debugger_visualizers_bytes); + p("exported symbols", exported_symbols_bytes); + p("hygiene", hygiene_bytes); + p("def-path hashes", def_path_hash_map_bytes); + p("source_map", source_map_bytes); + p("final", final_bytes); + eprintln!(""); } root @@ -890,9 +893,9 @@ fn should_encode_mir(tcx: TyCtxt<'_>, def_id: LocalDefId) -> (bool, bool) { let needs_inline = (generics.requires_monomorphization(tcx) || tcx.codegen_fn_attrs(def_id).requests_inline()) && tcx.sess.opts.output_types.should_codegen(); - // The function has a `const` modifier or is annotated with `default_method_body_is_const`. + // The function has a `const` modifier or is in a `#[const_trait]`. let is_const_fn = tcx.is_const_fn_raw(def_id.to_def_id()) - || tcx.has_attr(def_id.to_def_id(), sym::default_method_body_is_const); + || tcx.is_const_default_method(def_id.to_def_id()); let always_encode_mir = tcx.sess.opts.debugging_opts.always_encode_mir; (is_const_fn, needs_inline || always_encode_mir) } @@ -993,7 +996,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { .iter() .filter(|attr| !rustc_feature::is_builtin_only_local(attr.name_or_empty())); - record!(self.tables.attributes[def_id.to_def_id()] <- attrs.clone()); + record_array!(self.tables.attributes[def_id.to_def_id()] <- attrs.clone()); if attrs.any(|attr| attr.may_have_doc_links()) { self.tables.may_have_doc_links.set(def_id.local_def_index, ()); } @@ -1026,7 +1029,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } if should_encode_variances(def_kind) { let v = self.tcx.variances_of(def_id); - record!(self.tables.variances_of[def_id] <- v); + record_array!(self.tables.variances_of[def_id] <- v); } if should_encode_generics(def_kind) { let g = tcx.generics_of(def_id); @@ -1034,7 +1037,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { record!(self.tables.explicit_predicates_of[def_id] <- self.tcx.explicit_predicates_of(def_id)); let inferred_outlives = self.tcx.inferred_outlives_of(def_id); if !inferred_outlives.is_empty() { - record!(self.tables.inferred_outlives_of[def_id] <- inferred_outlives); + record_array!(self.tables.inferred_outlives_of[def_id] <- inferred_outlives); } } if let DefKind::Trait | DefKind::TraitAlias = def_kind { @@ -1046,7 +1049,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { if implementations.is_empty() { continue; } - record!(self.tables.inherent_impls[def_id.to_def_id()] <- implementations.iter().map(|&def_id| { + record_array!(self.tables.inherent_impls[def_id.to_def_id()] <- implementations.iter().map(|&def_id| { assert!(def_id.is_local()); def_id.index })); @@ -1073,7 +1076,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { record!(self.tables.kind[def_id] <- EntryKind::Variant(self.lazy(data))); self.tables.impl_constness.set(def_id.index, hir::Constness::Const); - record!(self.tables.children[def_id] <- variant.fields.iter().map(|f| { + record_array!(self.tables.children[def_id] <- variant.fields.iter().map(|f| { assert!(f.did.is_local()); f.did.index })); @@ -1121,11 +1124,11 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { // items - we encode information about proc-macros later on. let reexports = if !self.is_proc_macro { match tcx.module_reexports(local_def_id) { - Some(exports) => self.lazy(exports), - _ => Lazy::empty(), + Some(exports) => self.lazy_array(exports), + _ => LazyArray::empty(), } } else { - Lazy::empty() + LazyArray::empty() }; record!(self.tables.kind[def_id] <- EntryKind::Mod(reexports)); @@ -1133,7 +1136,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { // Encode this here because we don't do it in encode_def_ids. record!(self.tables.expn_that_defined[def_id] <- tcx.expn_that_defined(local_def_id)); } else { - record!(self.tables.children[def_id] <- iter_from_generator(|| { + record_array!(self.tables.children[def_id] <- iter::from_generator(|| { for item_id in md.item_ids { match tcx.hir().item(*item_id).kind { // Foreign items are planted into their parent modules @@ -1198,7 +1201,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { debug!("EncodeContext::encode_explicit_item_bounds({:?})", def_id); let bounds = self.tcx.explicit_item_bounds(def_id); if !bounds.is_empty() { - record!(self.tables.explicit_item_bounds[def_id] <- bounds); + record_array!(self.tables.explicit_item_bounds[def_id] <- bounds); } } @@ -1230,10 +1233,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let hir::TraitItemKind::Fn(m_sig, m) = &ast_item.kind else { bug!() }; match *m { hir::TraitFn::Required(ref names) => { - record!(self.tables.fn_arg_names[def_id] <- *names) + record_array!(self.tables.fn_arg_names[def_id] <- *names) } hir::TraitFn::Provided(body) => { - record!(self.tables.fn_arg_names[def_id] <- self.tcx.hir().body_param_names(body)) + record_array!(self.tables.fn_arg_names[def_id] <- self.tcx.hir().body_param_names(body)) } }; self.tables.asyncness.set(def_id.index, m_sig.header.asyncness); @@ -1295,7 +1298,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { ty::AssocKind::Fn => { let hir::ImplItemKind::Fn(ref sig, body) = ast_item.kind else { bug!() }; self.tables.asyncness.set(def_id.index, sig.header.asyncness); - record!(self.tables.fn_arg_names[def_id] <- self.tcx.hir().body_param_names(body)); + record_array!(self.tables.fn_arg_names[def_id] <- self.tcx.hir().body_param_names(body)); // Can be inside `impl const Trait`, so using sig.header.constness is not reliable let constness = if self.tcx.is_const_fn_raw(def_id) { hir::Constness::Const @@ -1319,6 +1322,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } if impl_item.kind == ty::AssocKind::Fn { record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id)); + if tcx.is_intrinsic(def_id) { + self.tables.is_intrinsic.set(def_id.index, ()); + } } } @@ -1424,7 +1430,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } hir::ItemKind::Fn(ref sig, .., body) => { self.tables.asyncness.set(def_id.index, sig.header.asyncness); - record!(self.tables.fn_arg_names[def_id] <- self.tcx.hir().body_param_names(body)); + record_array!(self.tables.fn_arg_names[def_id] <- self.tcx.hir().body_param_names(body)); self.tables.impl_constness.set(def_id.index, sig.header.constness); EntryKind::Fn } @@ -1524,14 +1530,14 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { record!(self.tables.kind[def_id] <- entry_kind); // FIXME(eddyb) there should be a nicer way to do this. match item.kind { - hir::ItemKind::Enum(..) => record!(self.tables.children[def_id] <- + hir::ItemKind::Enum(..) => record_array!(self.tables.children[def_id] <- self.tcx.adt_def(def_id).variants().iter().map(|v| { assert!(v.def_id.is_local()); v.def_id.index }) ), hir::ItemKind::Struct(..) | hir::ItemKind::Union(..) => { - record!(self.tables.children[def_id] <- + record_array!(self.tables.children[def_id] <- self.tcx.adt_def(def_id).non_enum_variant().fields.iter().map(|f| { assert!(f.did.is_local()); f.did.index @@ -1540,7 +1546,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } hir::ItemKind::Impl { .. } | hir::ItemKind::Trait(..) => { let associated_item_def_ids = self.tcx.associated_item_def_ids(def_id); - record!(self.tables.children[def_id] <- + record_array!(self.tables.children[def_id] <- associated_item_def_ids.iter().map(|&def_id| { assert!(def_id.is_local()); def_id.index @@ -1563,6 +1569,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } if let hir::ItemKind::Fn(..) = item.kind { record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id)); + if tcx.is_intrinsic(def_id) { + self.tables.is_intrinsic.set(def_id.index, ()); + } } if let hir::ItemKind::Impl { .. } = item.kind { if let Some(trait_ref) = self.tcx.impl_trait_ref(def_id) { @@ -1619,16 +1628,16 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.encode_item_type(def_id.to_def_id()); } - fn encode_native_libraries(&mut self) -> Lazy<[NativeLib]> { + fn encode_native_libraries(&mut self) -> LazyArray { empty_proc_macro!(self); let used_libraries = self.tcx.native_libraries(LOCAL_CRATE); - self.lazy(used_libraries.iter()) + self.lazy_array(used_libraries.iter()) } - fn encode_foreign_modules(&mut self) -> Lazy<[ForeignModule]> { + fn encode_foreign_modules(&mut self) -> LazyArray { empty_proc_macro!(self); let foreign_modules = self.tcx.foreign_modules(LOCAL_CRATE); - self.lazy(foreign_modules.iter().map(|(_, m)| m).cloned()) + self.lazy_array(foreign_modules.iter().map(|(_, m)| m).cloned()) } fn encode_hygiene(&mut self) -> (SyntaxContextTable, ExpnDataTable, ExpnHashTable) { @@ -1667,7 +1676,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let proc_macro_decls_static = tcx.proc_macro_decls_static(()).unwrap().local_def_index; let stability = tcx.lookup_stability(CRATE_DEF_ID); let macros = - self.lazy(tcx.resolutions(()).proc_macros.iter().map(|p| p.local_def_index)); + self.lazy_array(tcx.resolutions(()).proc_macros.iter().map(|p| p.local_def_index)); let spans = self.tcx.sess.parse_sess.proc_macro_quoted_spans(); for (i, span) in spans.into_iter().enumerate() { let span = self.lazy(span); @@ -1733,12 +1742,12 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } } - fn encode_debugger_visualizers(&mut self) -> Lazy<[DebuggerVisualizerFile]> { + fn encode_debugger_visualizers(&mut self) -> LazyArray { empty_proc_macro!(self); - self.lazy(self.tcx.debugger_visualizers(LOCAL_CRATE).iter()) + self.lazy_array(self.tcx.debugger_visualizers(LOCAL_CRATE).iter()) } - fn encode_crate_deps(&mut self) -> Lazy<[CrateDep]> { + fn encode_crate_deps(&mut self) -> LazyArray { empty_proc_macro!(self); let deps = self @@ -1770,29 +1779,29 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { // the assumption that they are numbered 1 to n. // FIXME (#2166): This is not nearly enough to support correct versioning // but is enough to get transitive crate dependencies working. - self.lazy(deps.iter().map(|&(_, ref dep)| dep)) + self.lazy_array(deps.iter().map(|&(_, ref dep)| dep)) } - fn encode_lib_features(&mut self) -> Lazy<[(Symbol, Option)]> { + fn encode_lib_features(&mut self) -> LazyArray<(Symbol, Option)> { empty_proc_macro!(self); let tcx = self.tcx; let lib_features = tcx.lib_features(()); - self.lazy(lib_features.to_vec()) + self.lazy_array(lib_features.to_vec()) } - fn encode_diagnostic_items(&mut self) -> Lazy<[(Symbol, DefIndex)]> { + fn encode_diagnostic_items(&mut self) -> LazyArray<(Symbol, DefIndex)> { empty_proc_macro!(self); let tcx = self.tcx; let diagnostic_items = &tcx.diagnostic_items(LOCAL_CRATE).name_to_id; - self.lazy(diagnostic_items.iter().map(|(&name, def_id)| (name, def_id.index))) + self.lazy_array(diagnostic_items.iter().map(|(&name, def_id)| (name, def_id.index))) } - fn encode_lang_items(&mut self) -> Lazy<[(DefIndex, usize)]> { + fn encode_lang_items(&mut self) -> LazyArray<(DefIndex, usize)> { empty_proc_macro!(self); let tcx = self.tcx; let lang_items = tcx.lang_items(); let lang_items = lang_items.items().iter(); - self.lazy(lang_items.enumerate().filter_map(|(i, &opt_def_id)| { + self.lazy_array(lang_items.enumerate().filter_map(|(i, &opt_def_id)| { if let Some(def_id) = opt_def_id { if def_id.is_local() { return Some((def_id.index, i)); @@ -1802,19 +1811,19 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { })) } - fn encode_lang_items_missing(&mut self) -> Lazy<[lang_items::LangItem]> { + fn encode_lang_items_missing(&mut self) -> LazyArray { empty_proc_macro!(self); let tcx = self.tcx; - self.lazy(&tcx.lang_items().missing) + self.lazy_array(&tcx.lang_items().missing) } - fn encode_traits(&mut self) -> Lazy<[DefIndex]> { + fn encode_traits(&mut self) -> LazyArray { empty_proc_macro!(self); - self.lazy(self.tcx.traits_in_crate(LOCAL_CRATE).iter().map(|def_id| def_id.index)) + self.lazy_array(self.tcx.traits_in_crate(LOCAL_CRATE).iter().map(|def_id| def_id.index)) } /// Encodes an index, mapping each trait to its (local) implementations. - fn encode_impls(&mut self) -> Lazy<[TraitImpls]> { + fn encode_impls(&mut self) -> LazyArray { debug!("EncodeContext::encode_traits_and_impls()"); empty_proc_macro!(self); let tcx = self.tcx; @@ -1827,7 +1836,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let simplified_self_ty = fast_reject::simplify_type( self.tcx, trait_ref.self_ty(), - TreatParams::AsPlaceholders, + TreatParams::AsInfer, ); fx_hash_map @@ -1853,15 +1862,15 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { TraitImpls { trait_id: (trait_def_id.krate.as_u32(), trait_def_id.index), - impls: self.lazy(&impls), + impls: self.lazy_array(&impls), } }) .collect(); - self.lazy(&all_impls) + self.lazy_array(&all_impls) } - fn encode_incoherent_impls(&mut self) -> Lazy<[IncoherentImpls]> { + fn encode_incoherent_impls(&mut self) -> LazyArray { debug!("EncodeContext::encode_traits_and_impls()"); empty_proc_macro!(self); let tcx = self.tcx; @@ -1881,11 +1890,11 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { tcx.hir().def_path_hash(LocalDefId { local_def_index }) }); - IncoherentImpls { self_ty: simp, impls: self.lazy(impls) } + IncoherentImpls { self_ty: simp, impls: self.lazy_array(impls) } }) .collect(); - self.lazy(&all_impls) + self.lazy_array(&all_impls) } // Encodes all symbols exported from this crate into the metadata. @@ -1897,13 +1906,13 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { fn encode_exported_symbols( &mut self, exported_symbols: &[(ExportedSymbol<'tcx>, SymbolExportInfo)], - ) -> Lazy<[(ExportedSymbol<'tcx>, SymbolExportInfo)]> { + ) -> LazyArray<(ExportedSymbol<'static>, SymbolExportInfo)> { empty_proc_macro!(self); // The metadata symbol name is special. It should not show up in // downstream crates. let metadata_symbol_name = SymbolName::new(self.tcx, &metadata_symbol_name(self.tcx)); - self.lazy( + self.lazy_array( exported_symbols .iter() .filter(|&&(ref exported_symbol, _)| match *exported_symbol { @@ -1914,21 +1923,21 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { ) } - fn encode_dylib_dependency_formats(&mut self) -> Lazy<[Option]> { + fn encode_dylib_dependency_formats(&mut self) -> LazyArray> { empty_proc_macro!(self); let formats = self.tcx.dependency_formats(()); for (ty, arr) in formats.iter() { if *ty != CrateType::Dylib { continue; } - return self.lazy(arr.iter().map(|slot| match *slot { + return self.lazy_array(arr.iter().map(|slot| match *slot { Linkage::NotLinked | Linkage::IncludedFromDylib => None, Linkage::Dynamic => Some(LinkagePreference::RequireDynamic), Linkage::Static => Some(LinkagePreference::RequireStatic), })); } - Lazy::empty() + LazyArray::empty() } fn encode_info_for_foreign_item(&mut self, def_id: DefId, nitem: &hir::ForeignItem<'_>) { @@ -1939,7 +1948,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { match nitem.kind { hir::ForeignItemKind::Fn(_, ref names, _) => { self.tables.asyncness.set(def_id.index, hir::IsAsync::NotAsync); - record!(self.tables.fn_arg_names[def_id] <- *names); + record_array!(self.tables.fn_arg_names[def_id] <- *names); let constness = if self.tcx.is_const_fn_raw(def_id) { hir::Constness::Const } else { @@ -1959,6 +1968,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.encode_item_type(def_id); if let hir::ForeignItemKind::Fn(..) = nitem.kind { record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id)); + if tcx.is_intrinsic(def_id) { + self.tables.is_intrinsic.set(def_id.index, ()); + } } } } @@ -2243,26 +2255,16 @@ pub fn provide(providers: &mut Providers) { traits_in_crate: |tcx, cnum| { assert_eq!(cnum, LOCAL_CRATE); - #[derive(Default)] - struct TraitsVisitor { - traits: Vec, - } - impl ItemLikeVisitor<'_> for TraitsVisitor { - fn visit_item(&mut self, item: &hir::Item<'_>) { - if let hir::ItemKind::Trait(..) | hir::ItemKind::TraitAlias(..) = item.kind { - self.traits.push(item.def_id.to_def_id()); - } + let mut traits = Vec::new(); + for id in tcx.hir().items() { + if matches!(tcx.def_kind(id.def_id), DefKind::Trait | DefKind::TraitAlias) { + traits.push(id.def_id.to_def_id()) } - fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem<'_>) {} - fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem<'_>) {} - fn visit_foreign_item(&mut self, _foreign_item: &hir::ForeignItem<'_>) {} } - let mut visitor = TraitsVisitor::default(); - tcx.hir().visit_all_item_likes(&mut visitor); // Bring everything into deterministic order. - visitor.traits.sort_by_cached_key(|&def_id| tcx.def_path_hash(def_id)); - tcx.arena.alloc_slice(&visitor.traits) + traits.sort_by_cached_key(|&def_id| tcx.def_path_hash(def_id)); + tcx.arena.alloc_slice(&traits) }, ..*providers diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 356dad4b56be1..fb2ffe1d73d96 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -1,7 +1,7 @@ use crate::creader::CrateMetadataRef; use decoder::Metadata; use def_path_hash_map::DefPathHashMapRef; -use table::{Table, TableBuilder}; +use table::TableBuilder; use rustc_ast as ast; use rustc_attr as attr; @@ -20,8 +20,8 @@ use rustc_middle::mir; use rustc_middle::thir; use rustc_middle::ty::fast_reject::SimplifiedType; use rustc_middle::ty::query::Providers; -use rustc_middle::ty::GeneratorDiagnosticData; use rustc_middle::ty::{self, ReprOptions, Ty}; +use rustc_middle::ty::{GeneratorDiagnosticData, ParameterizedOverTcx, TyCtxt}; use rustc_serialize::opaque::Encoder; use rustc_session::config::SymbolManglingVersion; use rustc_session::cstore::{CrateDepKind, ForeignModule, LinkagePreference, NativeLib}; @@ -36,7 +36,7 @@ use std::num::NonZeroUsize; pub use decoder::provide_extern; use decoder::DecodeContext; -crate use decoder::{CrateMetadata, CrateNumMap, MetadataBlob}; +pub(crate) use decoder::{CrateMetadata, CrateNumMap, MetadataBlob}; use encoder::EncodeContext; pub use encoder::{encode_metadata, EncodedMetadata}; use rustc_span::hygiene::SyntaxContextData; @@ -46,7 +46,7 @@ mod def_path_hash_map; mod encoder; mod table; -crate fn rustc_version() -> String { +pub(crate) fn rustc_version() -> String { format!("rustc {}", option_env!("CFG_VERSION").unwrap_or("unknown version")) } @@ -62,20 +62,6 @@ const METADATA_VERSION: u8 = 6; /// and further followed by the rustc version string. pub const METADATA_HEADER: &[u8] = &[b'r', b'u', b's', b't', 0, 0, 0, METADATA_VERSION]; -/// Additional metadata for a `Lazy` where `T` may not be `Sized`, -/// e.g. for `Lazy<[T]>`, this is the length (count of `T` values). -trait LazyMeta { - type Meta: Copy + 'static; -} - -impl LazyMeta for T { - type Meta = (); -} - -impl LazyMeta for [T] { - type Meta = usize; -} - /// A value of type T referred to by its absolute position /// in the metadata, and which can be decoded lazily. /// @@ -91,8 +77,23 @@ impl LazyMeta for [T] { /// Distances start at 1, as 0-byte nodes are invalid. /// Also invalid are nodes being referred in a different /// order than they were encoded in. -/// -/// # Sequences (`Lazy<[T]>`) +#[must_use] +struct LazyValue { + position: NonZeroUsize, + _marker: PhantomData T>, +} + +impl ParameterizedOverTcx for LazyValue { + type Value<'tcx> = LazyValue>; +} + +impl LazyValue { + fn from_position(position: NonZeroUsize) -> LazyValue { + LazyValue { position, _marker: PhantomData } + } +} + +/// A list of lazily-decoded values. /// /// Unlike `Lazy>`, the length is encoded next to the /// position, not at the position, which means that the length @@ -102,39 +103,66 @@ impl LazyMeta for [T] { /// the encoding is that of `Lazy`, with the distinction that /// the minimal distance the length of the sequence, i.e. /// it's assumed there's no 0-byte element in the sequence. -#[must_use] -// FIXME(#59875) the `Meta` parameter only exists to dodge -// invariance wrt `T` (coming from the `meta: T::Meta` field). -struct Lazy::Meta> -where - T: ?Sized + LazyMeta, - Meta: 'static + Copy, -{ +struct LazyArray { + position: NonZeroUsize, + num_elems: usize, + _marker: PhantomData T>, +} + +impl ParameterizedOverTcx for LazyArray { + type Value<'tcx> = LazyArray>; +} + +impl LazyArray { + fn from_position_and_num_elems(position: NonZeroUsize, num_elems: usize) -> LazyArray { + LazyArray { position, num_elems, _marker: PhantomData } + } + + fn empty() -> LazyArray { + LazyArray::from_position_and_num_elems(NonZeroUsize::new(1).unwrap(), 0) + } +} + +/// A list of lazily-decoded values, with the added capability of random access. +/// +/// Random-access table (i.e. offering constant-time `get`/`set`), similar to +/// `LazyArray`, but without requiring encoding or decoding all the values +/// eagerly and in-order. +struct LazyTable { position: NonZeroUsize, - meta: Meta, - _marker: PhantomData, + encoded_size: usize, + _marker: PhantomData T>, +} + +impl ParameterizedOverTcx for LazyTable { + type Value<'tcx> = LazyTable>; } -impl Lazy { - fn from_position_and_meta(position: NonZeroUsize, meta: T::Meta) -> Lazy { - Lazy { position, meta, _marker: PhantomData } +impl LazyTable { + fn from_position_and_encoded_size( + position: NonZeroUsize, + encoded_size: usize, + ) -> LazyTable { + LazyTable { position, encoded_size, _marker: PhantomData } } } -impl Lazy { - fn from_position(position: NonZeroUsize) -> Lazy { - Lazy::from_position_and_meta(position, ()) +impl Copy for LazyValue {} +impl Clone for LazyValue { + fn clone(&self) -> Self { + *self } } -impl Lazy<[T]> { - fn empty() -> Lazy<[T]> { - Lazy::from_position_and_meta(NonZeroUsize::new(1).unwrap(), 0) +impl Copy for LazyArray {} +impl Clone for LazyArray { + fn clone(&self) -> Self { + *self } } -impl Copy for Lazy {} -impl Clone for Lazy { +impl Copy for LazyTable {} +impl Clone for LazyTable { fn clone(&self) -> Self { *self } @@ -155,29 +183,20 @@ enum LazyState { Previous(NonZeroUsize), } -// FIXME(#59875) `Lazy!(T)` replaces `Lazy`, passing the `Meta` parameter -// manually, instead of relying on the default, to get the correct variance. -// Only needed when `T` itself contains a parameter (e.g. `'tcx`). -macro_rules! Lazy { - (Table<$I:ty, $T:ty>) => {Lazy, usize>}; - ([$T:ty]) => {Lazy<[$T], usize>}; - ($T:ty) => {Lazy<$T, ()>}; -} - -type SyntaxContextTable = Lazy>>; -type ExpnDataTable = Lazy>>; -type ExpnHashTable = Lazy>>; +type SyntaxContextTable = LazyTable>; +type ExpnDataTable = LazyTable>; +type ExpnHashTable = LazyTable>; #[derive(MetadataEncodable, MetadataDecodable)] -crate struct ProcMacroData { +pub(crate) struct ProcMacroData { proc_macro_decls_static: DefIndex, stability: Option, - macros: Lazy<[DefIndex]>, + macros: LazyArray, } /// Serialized metadata for a crate. /// When compiling a proc-macro crate, we encode many of -/// the `Lazy<[T]>` fields as `Lazy::empty()`. This serves two purposes: +/// the `LazyArray` fields as `Lazy::empty()`. This serves two purposes: /// /// 1. We avoid performing unnecessary work. Proc-macro crates can only /// export proc-macros functions, which are compiled into a shared library. @@ -192,7 +211,7 @@ crate struct ProcMacroData { /// a normal crate, much of what we serialized would be unusable in addition /// to being unused. #[derive(MetadataEncodable, MetadataDecodable)] -crate struct CrateRoot<'tcx> { +pub(crate) struct CrateRoot { name: Symbol, triple: TargetTriple, extra_filename: String, @@ -205,32 +224,32 @@ crate struct CrateRoot<'tcx> { has_panic_handler: bool, has_default_lib_allocator: bool, - crate_deps: Lazy<[CrateDep]>, - dylib_dependency_formats: Lazy<[Option]>, - lib_features: Lazy<[(Symbol, Option)]>, - lang_items: Lazy<[(DefIndex, usize)]>, - lang_items_missing: Lazy<[lang_items::LangItem]>, - diagnostic_items: Lazy<[(Symbol, DefIndex)]>, - native_libraries: Lazy<[NativeLib]>, - foreign_modules: Lazy<[ForeignModule]>, - traits: Lazy<[DefIndex]>, - impls: Lazy<[TraitImpls]>, - incoherent_impls: Lazy<[IncoherentImpls]>, - interpret_alloc_index: Lazy<[u32]>, + crate_deps: LazyArray, + dylib_dependency_formats: LazyArray>, + lib_features: LazyArray<(Symbol, Option)>, + lang_items: LazyArray<(DefIndex, usize)>, + lang_items_missing: LazyArray, + diagnostic_items: LazyArray<(Symbol, DefIndex)>, + native_libraries: LazyArray, + foreign_modules: LazyArray, + traits: LazyArray, + impls: LazyArray, + incoherent_impls: LazyArray, + interpret_alloc_index: LazyArray, proc_macro_data: Option, - tables: LazyTables<'tcx>, - debugger_visualizers: Lazy<[rustc_span::DebuggerVisualizerFile]>, + tables: LazyTables, + debugger_visualizers: LazyArray, - exported_symbols: Lazy!([(ExportedSymbol<'tcx>, SymbolExportInfo)]), + exported_symbols: LazyArray<(ExportedSymbol<'static>, SymbolExportInfo)>, syntax_contexts: SyntaxContextTable, expn_data: ExpnDataTable, expn_hashes: ExpnHashTable, - def_path_hash_map: Lazy>, + def_path_hash_map: LazyValue>, - source_map: Lazy<[rustc_span::SourceFile]>, + source_map: LazyArray, compiler_builtins: bool, needs_allocator: bool, @@ -245,7 +264,7 @@ crate struct CrateRoot<'tcx> { /// This creates a type-safe way to enforce that we remap the CrateNum between the on-disk /// representation and the compilation session. #[derive(Copy, Clone)] -crate struct RawDefId { +pub(crate) struct RawDefId { krate: u32, index: u32, } @@ -257,7 +276,12 @@ impl Into for DefId { } impl RawDefId { - fn decode(self, cdata: CrateMetadataRef<'_>) -> DefId { + /// This exists so that `provide_one!` is happy + fn decode(self, meta: (CrateMetadataRef<'_>, TyCtxt<'_>)) -> DefId { + self.decode_from_cdata(meta.0) + } + + fn decode_from_cdata(self, cdata: CrateMetadataRef<'_>) -> DefId { let krate = CrateNum::from_u32(self.krate); let krate = cdata.map_encoded_cnum_to_current(krate); DefId { krate, index: DefIndex::from_u32(self.index) } @@ -265,7 +289,7 @@ impl RawDefId { } #[derive(Encodable, Decodable)] -crate struct CrateDep { +pub(crate) struct CrateDep { pub name: Symbol, pub hash: Svh, pub host_hash: Option, @@ -274,32 +298,32 @@ crate struct CrateDep { } #[derive(MetadataEncodable, MetadataDecodable)] -crate struct TraitImpls { +pub(crate) struct TraitImpls { trait_id: (u32, DefIndex), - impls: Lazy<[(DefIndex, Option)]>, + impls: LazyArray<(DefIndex, Option)>, } #[derive(MetadataEncodable, MetadataDecodable)] -crate struct IncoherentImpls { +pub(crate) struct IncoherentImpls { self_ty: SimplifiedType, - impls: Lazy<[DefIndex]>, + impls: LazyArray, } /// Define `LazyTables` and `TableBuilders` at the same time. macro_rules! define_tables { ($($name:ident: Table<$IDX:ty, $T:ty>),+ $(,)?) => { #[derive(MetadataEncodable, MetadataDecodable)] - crate struct LazyTables<'tcx> { - $($name: Lazy!(Table<$IDX, $T>)),+ + pub(crate) struct LazyTables { + $($name: LazyTable<$IDX, $T>),+ } #[derive(Default)] - struct TableBuilders<'tcx> { + struct TableBuilders { $($name: TableBuilder<$IDX, $T>),+ } - impl<'tcx> TableBuilders<'tcx> { - fn encode(&self, buf: &mut Encoder) -> LazyTables<'tcx> { + impl TableBuilders { + fn encode(&self, buf: &mut Encoder) -> LazyTables { LazyTables { $($name: self.$name.encode(buf)),+ } @@ -309,60 +333,62 @@ macro_rules! define_tables { } define_tables! { - kind: Table>, - attributes: Table>, - children: Table>, + kind: Table>, + attributes: Table>, + children: Table>, opt_def_kind: Table, - visibility: Table>, - def_span: Table>, - def_ident_span: Table>, - lookup_stability: Table>, - lookup_const_stability: Table>, - lookup_deprecation_entry: Table>, + visibility: Table>, + def_span: Table>, + def_ident_span: Table>, + lookup_stability: Table>, + lookup_const_stability: Table>, + lookup_deprecation_entry: Table>, // As an optimization, a missing entry indicates an empty `&[]`. - explicit_item_bounds: Table, Span)])>, - explicit_predicates_of: Table)>, - generics_of: Table>, + explicit_item_bounds: Table, Span)>>, + explicit_predicates_of: Table>>, + generics_of: Table>, // As an optimization, a missing entry indicates an empty `&[]`. - inferred_outlives_of: Table, Span)])>, - super_predicates_of: Table)>, - type_of: Table)>, - variances_of: Table>, - fn_sig: Table)>, - codegen_fn_attrs: Table, - impl_trait_ref: Table)>, - const_param_default: Table>>, - optimized_mir: Table)>, - mir_for_ctfe: Table)>, - promoted_mir: Table>)>, - thir_abstract_const: Table])>, + inferred_outlives_of: Table, Span)>>, + super_predicates_of: Table>>, + type_of: Table>>, + variances_of: Table>, + fn_sig: Table>>, + codegen_fn_attrs: Table>, + impl_trait_ref: Table>>, + const_param_default: Table>>, + optimized_mir: Table>>, + mir_for_ctfe: Table>>, + promoted_mir: Table>>>, + // FIXME(compiler-errors): Why isn't this a LazyArray? + thir_abstract_const: Table]>>, impl_parent: Table, impl_polarity: Table, impl_constness: Table, + is_intrinsic: Table, impl_defaultness: Table, // FIXME(eddyb) perhaps compute this on the fly if cheap enough? - coerce_unsized_info: Table, - mir_const_qualif: Table, - rendered_const: Table, + coerce_unsized_info: Table>, + mir_const_qualif: Table>, + rendered_const: Table>, asyncness: Table, - fn_arg_names: Table, - generator_kind: Table, - trait_def: Table, + fn_arg_names: Table>, + generator_kind: Table>, + trait_def: Table>, trait_item_def_id: Table, - inherent_impls: Table>, - expn_that_defined: Table>, - unused_generic_params: Table>>, - repr_options: Table>, + inherent_impls: Table>, + expn_that_defined: Table>, + unused_generic_params: Table>>, + repr_options: Table>, // `def_keys` and `def_path_hashes` represent a lazy version of a // `DefPathTable`. This allows us to avoid deserializing an entire // `DefPathTable` up front, since we may only ever use a few // definitions from any given crate. - def_keys: Table>, + def_keys: Table>, def_path_hashes: Table, - proc_macro_quoted_spans: Table>, - generator_diagnostic_data: Table>>, + proc_macro_quoted_spans: Table>, + generator_diagnostic_data: Table>>, may_have_doc_links: Table, } @@ -381,19 +407,19 @@ enum EntryKind { OpaqueTy, Enum, Field, - Variant(Lazy), - Struct(Lazy), - Union(Lazy), + Variant(LazyValue), + Struct(LazyValue), + Union(LazyValue), Fn, ForeignFn, - Mod(Lazy<[ModChild]>), - MacroDef(Lazy, /*macro_rules*/ bool), + Mod(LazyArray), + MacroDef(LazyValue, /*macro_rules*/ bool), ProcMacro(MacroKind), Closure, Generator, Trait, Impl, - AssocFn(Lazy), + AssocFn(LazyValue), AssocType(AssocContainer), AssocConst(AssocContainer), TraitAlias, @@ -463,3 +489,14 @@ pub fn provide(providers: &mut Providers) { encoder::provide(providers); decoder::provide(providers); } + +trivially_parameterized_over_tcx! { + VariantData, + AssocFnData, + EntryKind, + RawDefId, + TraitImpls, + IncoherentImpls, + CrateRoot, + CrateDep, +} diff --git a/compiler/rustc_metadata/src/rmeta/table.rs b/compiler/rustc_metadata/src/rmeta/table.rs index 53fc2efe00bb7..100bac15b80a4 100644 --- a/compiler/rustc_metadata/src/rmeta/table.rs +++ b/compiler/rustc_metadata/src/rmeta/table.rs @@ -3,6 +3,7 @@ use crate::rmeta::*; use rustc_data_structures::fingerprint::Fingerprint; use rustc_hir::def::{CtorKind, CtorOf}; use rustc_index::vec::Idx; +use rustc_middle::ty::ParameterizedOverTcx; use rustc_serialize::opaque::Encoder; use rustc_serialize::Encoder as _; use rustc_span::hygiene::MacroKind; @@ -201,15 +202,15 @@ impl FixedSizeEncoding for Option<()> { } // NOTE(eddyb) there could be an impl for `usize`, which would enable a more -// generic `Lazy` impl, but in the general case we might not need / want to -// fit every `usize` in `u32`. -impl FixedSizeEncoding for Option> { +// generic `LazyValue` impl, but in the general case we might not need / want +// to fit every `usize` in `u32`. +impl FixedSizeEncoding for Option> { type ByteArray = [u8; 4]; #[inline] fn from_bytes(b: &[u8; 4]) -> Self { let position = NonZeroUsize::new(u32::from_bytes(b) as usize)?; - Some(Lazy::from_position(position)) + Some(LazyValue::from_position(position)) } #[inline] @@ -220,7 +221,7 @@ impl FixedSizeEncoding for Option> { } } -impl FixedSizeEncoding for Option> { +impl FixedSizeEncoding for Option> { type ByteArray = [u8; 8]; #[inline] @@ -228,7 +229,7 @@ impl FixedSizeEncoding for Option> { let ([ref position_bytes, ref meta_bytes],[])= b.as_chunks::<4>() else { panic!() }; let position = NonZeroUsize::new(u32::from_bytes(position_bytes) as usize)?; let len = u32::from_bytes(meta_bytes) as usize; - Some(Lazy::from_position_and_meta(position, len)) + Some(LazyArray::from_position_and_num_elems(position, len)) } #[inline] @@ -239,28 +240,12 @@ impl FixedSizeEncoding for Option> { let position: u32 = position.try_into().unwrap(); position.write_to_bytes(position_bytes); - let len = self.map_or(0, |lazy| lazy.meta); + let len = self.map_or(0, |lazy| lazy.num_elems); let len: u32 = len.try_into().unwrap(); len.write_to_bytes(meta_bytes); } } -/// Random-access table (i.e. offering constant-time `get`/`set`), similar to -/// `Vec>`, but without requiring encoding or decoding all the values -/// eagerly and in-order. -/// A total of `(max_idx + 1)` times `Option as FixedSizeEncoding>::ByteArray` -/// are used for a table, where `max_idx` is the largest index passed to -/// `TableBuilder::set`. -pub(super) struct Table -where - Option: FixedSizeEncoding, -{ - _marker: PhantomData<(fn(&I), T)>, - // NOTE(eddyb) this makes `Table` not implement `Sized`, but no - // value of `Table` is ever created (it's always behind `Lazy`). - _bytes: [u8], -} - /// Helper for constructing a table's serialization (also see `Table`). pub(super) struct TableBuilder where @@ -296,7 +281,7 @@ where Some(value).write_to_bytes(&mut self.blocks[i]); } - pub(crate) fn encode(&self, buf: &mut Encoder) -> Lazy> + pub(crate) fn encode(&self, buf: &mut Encoder) -> LazyTable where Option: FixedSizeEncoding, { @@ -305,19 +290,14 @@ where buf.emit_raw_bytes(block).unwrap(); } let num_bytes = self.blocks.len() * N; - Lazy::from_position_and_meta(NonZeroUsize::new(pos as usize).unwrap(), num_bytes) + LazyTable::from_position_and_encoded_size( + NonZeroUsize::new(pos as usize).unwrap(), + num_bytes, + ) } } -impl LazyMeta for Table -where - Option: FixedSizeEncoding, -{ - /// Number of bytes in the data stream. - type Meta = usize; -} - -impl Lazy> +impl LazyTable where Option: FixedSizeEncoding, { @@ -327,14 +307,14 @@ where &self, metadata: M, i: I, - ) -> Option + ) -> Option> where - Option: FixedSizeEncoding, + Option>: FixedSizeEncoding, { - debug!("Table::lookup: index={:?} len={:?}", i, self.meta); + debug!("LazyTable::lookup: index={:?} len={:?}", i, self.encoded_size); let start = self.position.get(); - let bytes = &metadata.blob()[start..start + self.meta]; + let bytes = &metadata.blob()[start..start + self.encoded_size]; let (bytes, []) = bytes.as_chunks::() else { panic!() }; let bytes = bytes.get(i.index())?; FixedSizeEncoding::from_bytes(bytes) @@ -343,8 +323,8 @@ where /// Size of the table in entries, including possible gaps. pub(super) fn size(&self) -> usize where - Option: FixedSizeEncoding, + for<'tcx> Option>: FixedSizeEncoding, { - self.meta / N + self.encoded_size / N } } diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml index cd281ea5b38ae..cee80823443f5 100644 --- a/compiler/rustc_middle/Cargo.toml +++ b/compiler/rustc_middle/Cargo.toml @@ -12,8 +12,8 @@ bitflags = "1.2.1" either = "1.5.0" gsgdt = "0.1.2" tracing = "0.1" -rustc-rayon = { version = "0.3.2", optional = true } -rustc-rayon-core = { version = "0.3.2", optional = true } +rustc-rayon = { version = "0.4.0", optional = true } +rustc-rayon-core = { version = "0.4.0", optional = true } polonius-engine = "0.13.0" rustc_apfloat = { path = "../rustc_apfloat" } rustc_attr = { path = "../rustc_attr" } diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index 7c90cbb9092b8..984c95b314ba8 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -31,9 +31,9 @@ macro_rules! arena_types { [decode] unsafety_check_result: rustc_middle::mir::UnsafetyCheckResult, [decode] code_region: rustc_middle::mir::coverage::CodeRegion, [] const_allocs: rustc_middle::mir::interpret::Allocation, + [] region_scope_tree: rustc_middle::middle::region::ScopeTree, // Required for the incremental on-disk cache [] mir_keys: rustc_hir::def_id::DefIdSet, - [] region_scope_tree: rustc_middle::middle::region::ScopeTree, [] dropck_outlives: rustc_middle::infer::canonical::Canonical<'tcx, rustc_middle::infer::canonical::QueryResponse<'tcx, @@ -82,7 +82,7 @@ macro_rules! arena_types { [] upvars_mentioned: rustc_data_structures::fx::FxIndexMap, [] object_safety_violations: rustc_middle::traits::ObjectSafetyViolation, [] codegen_unit: rustc_middle::mir::mono::CodegenUnit<'tcx>, - [] attribute: rustc_ast::Attribute, + [decode] attribute: rustc_ast::Attribute, [] name_set: rustc_data_structures::fx::FxHashSet, [] hir_id_set: rustc_hir::HirIdSet, @@ -95,9 +95,6 @@ macro_rules! arena_types { // since we need to allocate this type on both the `rustc_hir` arena // (during lowering) and the `librustc_middle` arena (for decoding MIR) [decode] asm_template: rustc_ast::InlineAsmTemplatePiece, - - // This is used to decode the &'tcx [Span] for InlineAsm's line_spans. - [decode] span: rustc_span::Span, [decode] used_trait_imports: rustc_data_structures::fx::FxHashSet, [decode] impl_source: rustc_middle::traits::ImplSource<'tcx, ()>, diff --git a/compiler/rustc_middle/src/dep_graph/dep_node.rs b/compiler/rustc_middle/src/dep_graph/dep_node.rs index 8402ca3028cce..555baae35f506 100644 --- a/compiler/rustc_middle/src/dep_graph/dep_node.rs +++ b/compiler/rustc_middle/src/dep_graph/dep_node.rs @@ -195,13 +195,16 @@ rustc_dep_node_append!([define_dep_nodes!][ <'tcx> // WARNING: `construct` is generic and does not know that `CompileCodegenUnit` takes `Symbol`s as keys. // Be very careful changing this type signature! -crate fn make_compile_codegen_unit(tcx: TyCtxt<'_>, name: Symbol) -> DepNode { +pub(crate) fn make_compile_codegen_unit(tcx: TyCtxt<'_>, name: Symbol) -> DepNode { DepNode::construct(tcx, DepKind::CompileCodegenUnit, &name) } // WARNING: `construct` is generic and does not know that `CompileMonoItem` takes `MonoItem`s as keys. // Be very careful changing this type signature! -crate fn make_compile_mono_item<'tcx>(tcx: TyCtxt<'tcx>, mono_item: &MonoItem<'tcx>) -> DepNode { +pub(crate) fn make_compile_mono_item<'tcx>( + tcx: TyCtxt<'tcx>, + mono_item: &MonoItem<'tcx>, +) -> DepNode { DepNode::construct(tcx, DepKind::CompileMonoItem, mono_item) } diff --git a/compiler/rustc_middle/src/dep_graph/mod.rs b/compiler/rustc_middle/src/dep_graph/mod.rs index 6bfd1b7ffab24..e335cb395f84f 100644 --- a/compiler/rustc_middle/src/dep_graph/mod.rs +++ b/compiler/rustc_middle/src/dep_graph/mod.rs @@ -12,7 +12,7 @@ pub use rustc_query_system::dep_graph::{ }; pub use dep_node::{label_strs, DepKind, DepKindStruct, DepNode, DepNodeExt}; -crate use dep_node::{make_compile_codegen_unit, make_compile_mono_item}; +pub(crate) use dep_node::{make_compile_codegen_unit, make_compile_mono_item}; pub type DepGraph = rustc_query_system::dep_graph::DepGraph; pub type TaskDeps = rustc_query_system::dep_graph::TaskDeps; diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 20c8b0bb70f8b..97f429cfd3fa6 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -9,7 +9,6 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE}; use rustc_hir::definitions::{DefKey, DefPath, DefPathHash}; use rustc_hir::intravisit::{self, Visitor}; -use rustc_hir::itemlikevisit::ItemLikeVisitor; use rustc_hir::*; use rustc_index::vec::Idx; use rustc_middle::hir::nested_filter; @@ -161,6 +160,10 @@ impl<'hir> Map<'hir> { self.tcx.hir_crate_items(()).items.iter().copied() } + pub fn module_items(self, module: LocalDefId) -> impl Iterator + 'hir { + self.tcx.hir_module_items(module).items() + } + pub fn par_for_each_item(self, f: impl Fn(ItemId) + Sync + Send) { par_for_each_in(&self.tcx.hir_crate_items(()).items[..], |id| f(*id)); } @@ -491,9 +494,7 @@ impl<'hir> Map<'hir> { BodyOwnerKind::Fn if self.tcx.is_const_fn_raw(def_id.to_def_id()) => { ConstContext::ConstFn } - BodyOwnerKind::Fn - if self.tcx.has_attr(def_id.to_def_id(), sym::default_method_body_is_const) => - { + BodyOwnerKind::Fn if self.tcx.is_const_default_method(def_id.to_def_id()) => { ConstContext::ConstFn } BodyOwnerKind::Fn | BodyOwnerKind::Closure => return None, @@ -603,16 +604,16 @@ impl<'hir> Map<'hir> { } /// Visits all items in the crate in some deterministic (but - /// unspecified) order. If you just need to process every item, - /// but don't care about nesting, this method is the best choice. + /// unspecified) order. If you need to process every item, + /// and care about nesting -- usually because your algorithm + /// follows lexical scoping rules -- then this method is the best choice. + /// If you don't care about nesting, you should use the `tcx.hir_crate_items()` query + /// or `items()` instead. /// - /// If you do care about nesting -- usually because your algorithm - /// follows lexical scoping rules -- then you want a different - /// approach. You should override `visit_nested_item` in your - /// visitor and then call `intravisit::walk_crate` instead. - pub fn visit_all_item_likes(self, visitor: &mut V) + /// Please see the notes in `intravisit.rs` for more information. + pub fn deep_visit_all_item_likes(self, visitor: &mut V) where - V: itemlikevisit::ItemLikeVisitor<'hir>, + V: Visitor<'hir>, { let krate = self.krate(); for owner in krate.owners.iter().filter_map(|i| i.as_owner()) { @@ -643,9 +644,12 @@ impl<'hir> Map<'hir> { }) } - pub fn visit_item_likes_in_module(self, module: LocalDefId, visitor: &mut V) + /// If you don't care about nesting, you should use the + /// `tcx.hir_module_items()` query or `module_items()` instead. + /// Please see notes in `deep_visit_all_item_likes`. + pub fn deep_visit_item_likes_in_module(self, module: LocalDefId, visitor: &mut V) where - V: ItemLikeVisitor<'hir>, + V: Visitor<'hir>, { let module = self.tcx.hir_module_items(module); @@ -666,7 +670,7 @@ impl<'hir> Map<'hir> { } } - pub fn for_each_module(self, f: impl Fn(LocalDefId)) { + pub fn for_each_module(self, mut f: impl FnMut(LocalDefId)) { let crate_items = self.tcx.hir_crate_items(()); for module in crate_items.submodules.iter() { f(*module) diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs index f18067145dd4a..b50f121eff24f 100644 --- a/compiler/rustc_middle/src/hir/mod.rs +++ b/compiler/rustc_middle/src/hir/mod.rs @@ -36,7 +36,7 @@ impl<'a, 'tcx> HashStable> for Owner<'tcx> { /// Gather the LocalDefId for each item-like within a module, including items contained within /// bodies. The Ids are in visitor order. This is used to partition a pass between modules. -#[derive(Debug, HashStable)] +#[derive(Debug, HashStable, Encodable, Decodable)] pub struct ModuleItems { submodules: Box<[LocalDefId]>, items: Box<[ItemId]>, diff --git a/compiler/rustc_middle/src/hir/nested_filter.rs b/compiler/rustc_middle/src/hir/nested_filter.rs index 48efae8045bdd..d56e87bbb4745 100644 --- a/compiler/rustc_middle/src/hir/nested_filter.rs +++ b/compiler/rustc_middle/src/hir/nested_filter.rs @@ -8,7 +8,7 @@ use rustc_hir::intravisit::nested_filter::NestedFilter; /// constant arguments of types, e.g. in `let _: [(); /* HERE */];`. /// /// **This is the most common choice.** A very common pattern is -/// to use `visit_all_item_likes()` as an outer loop, +/// to use `deep_visit_all_item_likes()` as an outer loop, /// and to have the visitor that visits the contents of each item /// using this setting. pub struct OnlyBodies(()); diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index e3522e0c91562..17ca534d91bbc 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -29,10 +29,10 @@ #![feature(backtrace)] #![feature(box_patterns)] #![feature(core_intrinsics)] -#![cfg_attr(bootstrap, feature(derive_default_enum))] #![feature(discriminant_kind)] #![feature(exhaustive_patterns)] #![feature(get_mut_unchecked)] +#![feature(generic_associated_types)] #![feature(if_let_guard)] #![feature(map_first_last)] #![feature(negative_impls)] @@ -46,7 +46,6 @@ #![feature(min_specialization)] #![feature(trusted_len)] #![feature(type_alias_impl_trait)] -#![feature(crate_visibility_modifier)] #![feature(associated_type_bounds)] #![feature(rustc_attrs)] #![feature(half_open_range_patterns)] diff --git a/compiler/rustc_middle/src/middle/region.rs b/compiler/rustc_middle/src/middle/region.rs index af16e5e3fc871..30ef6b775f5e3 100644 --- a/compiler/rustc_middle/src/middle/region.rs +++ b/compiler/rustc_middle/src/middle/region.rs @@ -203,7 +203,7 @@ impl Scope { pub type ScopeDepth = u32; /// The region scope tree encodes information about region relationships. -#[derive(Default, Debug)] +#[derive(TyEncodable, TyDecodable, Default, Debug)] pub struct ScopeTree { /// If not empty, this body is the root of this region hierarchy. pub root_body: Option, @@ -223,15 +223,12 @@ pub struct ScopeTree { /// Maps from a `NodeId` to the associated destruction scope (if any). destruction_scopes: FxIndexMap, - /// `rvalue_scopes` includes entries for those expressions whose - /// cleanup scope is larger than the default. The map goes from the - /// expression ID to the cleanup scope id. For rvalues not present in - /// this table, the appropriate cleanup scope is the innermost - /// enclosing statement, conditional expression, or repeating - /// block (see `terminating_scopes`). - /// In constants, None is used to indicate that certain expressions - /// escape into 'static and should have no local cleanup scope. - rvalue_scopes: FxHashMap>, + /// Identifies expressions which, if captured into a temporary, ought to + /// have a temporary whose lifetime extends to the end of the enclosing *block*, + /// and not the enclosing *statement*. Expressions that are not present in this + /// table are not rvalue candidates. The set of rvalue candidates is computed + /// during type check based on a traversal of the AST. + pub rvalue_candidates: FxHashMap, /// If there are any `yield` nested within a scope, this map /// stores the `Span` of the last one and its index in the @@ -315,6 +312,17 @@ pub struct ScopeTree { pub body_expr_count: FxHashMap, } +/// Identifies the reason that a given expression is an rvalue candidate +/// (see the `rvalue_candidates` field for more information what rvalue +/// candidates in general). In constants, the `lifetime` field is None +/// to indicate that certain expressions escape into 'static and +/// should have no local cleanup scope. +#[derive(Debug, Copy, Clone, TyEncodable, TyDecodable, HashStable)] +pub enum RvalueCandidateType { + Borrow { target: hir::ItemLocalId, lifetime: Option }, + Pattern { target: hir::ItemLocalId, lifetime: Option }, +} + #[derive(Debug, Copy, Clone, TyEncodable, TyDecodable, HashStable)] pub struct YieldData { /// The `Span` of the yield. @@ -349,12 +357,20 @@ impl ScopeTree { self.var_map.insert(var, lifetime); } - pub fn record_rvalue_scope(&mut self, var: hir::ItemLocalId, lifetime: Option) { - debug!("record_rvalue_scope(sub={:?}, sup={:?})", var, lifetime); - if let Some(lifetime) = lifetime { - assert!(var != lifetime.item_local_id()); + pub fn record_rvalue_candidate( + &mut self, + var: hir::HirId, + candidate_type: RvalueCandidateType, + ) { + debug!("record_rvalue_candidate(var={var:?}, type={candidate_type:?})"); + match &candidate_type { + RvalueCandidateType::Borrow { lifetime: Some(lifetime), .. } + | RvalueCandidateType::Pattern { lifetime: Some(lifetime), .. } => { + assert!(var.local_id != lifetime.item_local_id()) + } + _ => {} } - self.rvalue_scopes.insert(var, lifetime); + self.rvalue_candidates.insert(var, candidate_type); } /// Returns the narrowest scope that encloses `id`, if any. @@ -367,34 +383,6 @@ impl ScopeTree { self.var_map.get(&var_id).cloned() } - /// Returns the scope when the temp created by `expr_id` will be cleaned up. - pub fn temporary_scope(&self, expr_id: hir::ItemLocalId) -> Option { - // Check for a designated rvalue scope. - if let Some(&s) = self.rvalue_scopes.get(&expr_id) { - debug!("temporary_scope({:?}) = {:?} [custom]", expr_id, s); - return s; - } - - // Otherwise, locate the innermost terminating scope - // if there's one. Static items, for instance, won't - // have an enclosing scope, hence no scope will be - // returned. - let mut id = Scope { id: expr_id, data: ScopeData::Node }; - - while let Some(&(p, _)) = self.parent_map.get(&id) { - match p.data { - ScopeData::Destruction => { - debug!("temporary_scope({:?}) = {:?} [enclosing]", expr_id, id); - return Some(id); - } - _ => id = p, - } - } - - debug!("temporary_scope({:?}) = None", expr_id); - None - } - /// Returns `true` if `subscope` is equal to or is lexically nested inside `superscope`, and /// `false` otherwise. /// @@ -439,7 +427,7 @@ impl<'a> HashStable> for ScopeTree { ref parent_map, ref var_map, ref destruction_scopes, - ref rvalue_scopes, + ref rvalue_candidates, ref yield_in_scope, } = *self; @@ -448,7 +436,7 @@ impl<'a> HashStable> for ScopeTree { parent_map.hash_stable(hcx, hasher); var_map.hash_stable(hcx, hasher); destruction_scopes.hash_stable(hcx, hasher); - rvalue_scopes.hash_stable(hcx, hasher); + rvalue_candidates.hash_stable(hcx, hasher); yield_in_scope.hash_stable(hcx, hasher); } } diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index 6918046390e6f..8b11e35a7c3f7 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -29,7 +29,7 @@ pub enum StabilityLevel { } /// An entry in the `depr_map`. -#[derive(Copy, Clone, HashStable, Debug)] +#[derive(Copy, Clone, HashStable, Debug, Encodable, Decodable)] pub struct DeprecationEntry { /// The metadata of the attribute associated with this entry. pub attr: Deprecation, diff --git a/compiler/rustc_middle/src/mir/generic_graph.rs b/compiler/rustc_middle/src/mir/generic_graph.rs index dbebed67c2bd1..a4d78911b2760 100644 --- a/compiler/rustc_middle/src/mir/generic_graph.rs +++ b/compiler/rustc_middle/src/mir/generic_graph.rs @@ -24,7 +24,7 @@ pub fn mir_fn_to_generic_graph<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'_>) -> Grap let terminator = body[source].terminator(); let labels = terminator.kind.fmt_successor_labels(); - for (&target, label) in terminator.successors().zip(labels) { + for (target, label) in terminator.successors().zip(labels) { let src = node(def_id, source); let trg = node(def_id, target); edges.push(Edge::new(src, trg, label.to_string())); diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs index 5564852f30539..6252dc1670c2c 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs @@ -171,7 +171,7 @@ impl Allocation { /// Try to create an Allocation of `size` bytes, failing if there is not enough memory /// available to the compiler to do so. - pub fn uninit(size: Size, align: Align, panic_on_fail: bool) -> InterpResult<'static, Self> { + pub fn uninit<'tcx>(size: Size, align: Align, panic_on_fail: bool) -> InterpResult<'tcx, Self> { let bytes = Box::<[u8]>::try_new_zeroed_slice(size.bytes_usize()).map_err(|_| { // This results in an error that can happen non-deterministically, since the memory // available to the compiler can change between runs. Normally queries are always @@ -350,19 +350,22 @@ impl Allocation { /// Reading and writing. impl Allocation { /// Validates that `ptr.offset` and `ptr.offset + size` do not point to the middle of a - /// relocation. If `allow_uninit_and_ptr` is `false`, also enforces that the memory in the - /// given range contains neither relocations nor uninitialized bytes. + /// relocation. If `allow_uninit`/`allow_ptr` is `false`, also enforces that the memory in the + /// given range contains no uninitialized bytes/relocations. pub fn check_bytes( &self, cx: &impl HasDataLayout, range: AllocRange, - allow_uninit_and_ptr: bool, + allow_uninit: bool, + allow_ptr: bool, ) -> AllocResult { // Check bounds and relocations on the edges. self.get_bytes_with_uninit_and_ptr(cx, range)?; // Check uninit and ptr. - if !allow_uninit_and_ptr { + if !allow_uninit { self.check_init(range)?; + } + if !allow_ptr { self.check_relocations(cx, range)?; } Ok(()) diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index 9afe9523fcab0..cb6fd006c3efe 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -1,7 +1,7 @@ use super::{AllocId, ConstAlloc, Pointer, Scalar}; use crate::mir::interpret::ConstValue; -use crate::ty::{layout, query::TyCtxtAt, tls, FnSig, Ty}; +use crate::ty::{layout, query::TyCtxtAt, tls, FnSig, Ty, ValTree}; use rustc_data_structures::sync::Lock; use rustc_errors::{pluralize, struct_span_err, DiagnosticBuilder, ErrorGuaranteed}; @@ -35,6 +35,7 @@ TrivialTypeFoldableAndLiftImpls! { pub type EvalToAllocationRawResult<'tcx> = Result, ErrorHandled>; pub type EvalToConstValueResult<'tcx> = Result, ErrorHandled>; +pub type EvalToValTreeResult<'tcx> = Result>, ErrorHandled>; pub fn struct_error<'tcx>( tcx: TyCtxtAt<'tcx>, @@ -148,8 +149,6 @@ pub enum InvalidProgramInfo<'tcx> { /// (which unfortunately typeck does not reject). /// Not using `FnAbiError` as that contains a nested `LayoutError`. FnAbiAdjustForForeignAbi(call::AdjustForForeignAbiError), - /// An invalid transmute happened. - TransmuteSizeDiff(Ty<'tcx>, Ty<'tcx>), /// SizeOf of unsized type was requested. SizeOfUnsizedType(Ty<'tcx>), } @@ -165,11 +164,6 @@ impl fmt::Display for InvalidProgramInfo<'_> { } Layout(ref err) => write!(f, "{}", err), FnAbiAdjustForForeignAbi(ref err) => write!(f, "{}", err), - TransmuteSizeDiff(from_ty, to_ty) => write!( - f, - "transmuting `{}` to `{}` is not possible, because these types do not have the same size", - from_ty, to_ty - ), SizeOfUnsizedType(ty) => write!(f, "size_of called on unsized type `{}`", ty), } } diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index d8cba39c6d97b..06cd6a66e39f5 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -119,9 +119,9 @@ use crate::ty::{self, Instance, Ty, TyCtxt}; pub use self::error::{ struct_error, CheckInAllocMsg, ErrorHandled, EvalToAllocationRawResult, EvalToConstValueResult, - InterpError, InterpErrorInfo, InterpResult, InvalidProgramInfo, MachineStopType, - ResourceExhaustionInfo, ScalarSizeMismatch, UndefinedBehaviorInfo, UninitBytesAccess, - UnsupportedOpInfo, + EvalToValTreeResult, InterpError, InterpErrorInfo, InterpResult, InvalidProgramInfo, + MachineStopType, ResourceExhaustionInfo, ScalarSizeMismatch, UndefinedBehaviorInfo, + UninitBytesAccess, UnsupportedOpInfo, }; pub use self::value::{get_slice_bytes, ConstAlloc, ConstValue, Scalar, ScalarMaybeUninit}; @@ -203,7 +203,7 @@ enum AllocDiscriminant { Static, } -pub fn specialized_encode_alloc_id<'tcx, E: TyEncoder<'tcx>>( +pub fn specialized_encode_alloc_id<'tcx, E: TyEncoder>>( encoder: &mut E, tcx: TyCtxt<'tcx>, alloc_id: AllocId, @@ -277,7 +277,7 @@ impl<'s> AllocDecodingSession<'s> { /// Decodes an `AllocId` in a thread-safe way. pub fn decode_alloc_id<'tcx, D>(&self, decoder: &mut D) -> AllocId where - D: TyDecoder<'tcx>, + D: TyDecoder>, { // Read the index of the allocation. let idx = usize::try_from(decoder.read_u32()).unwrap(); @@ -305,7 +305,7 @@ impl<'s> AllocDecodingSession<'s> { AllocDiscriminant::Alloc => { // If this is an allocation, we need to reserve an // `AllocId` so we can decode cyclic graphs. - let alloc_id = decoder.tcx().reserve_alloc_id(); + let alloc_id = decoder.interner().reserve_alloc_id(); *entry = State::InProgress(TinyList::new_single(self.session_id), alloc_id); Some(alloc_id) @@ -349,7 +349,7 @@ impl<'s> AllocDecodingSession<'s> { // We already have a reserved `AllocId`. let alloc_id = alloc_id.unwrap(); trace!("decoded alloc {:?}: {:#?}", alloc_id, alloc); - decoder.tcx().set_alloc_id_same_memory(alloc_id, alloc); + decoder.interner().set_alloc_id_same_memory(alloc_id, alloc); alloc_id } AllocDiscriminant::Fn => { @@ -357,7 +357,7 @@ impl<'s> AllocDecodingSession<'s> { trace!("creating fn alloc ID"); let instance = ty::Instance::decode(decoder); trace!("decoded fn alloc instance: {:?}", instance); - let alloc_id = decoder.tcx().create_fn_alloc(instance); + let alloc_id = decoder.interner().create_fn_alloc(instance); alloc_id } AllocDiscriminant::Static => { @@ -365,7 +365,7 @@ impl<'s> AllocDecodingSession<'s> { trace!("creating extern static alloc ID"); let did = >::decode(decoder); trace!("decoded static def-ID: {:?}", did); - let alloc_id = decoder.tcx().create_static_alloc(did); + let alloc_id = decoder.interner().create_static_alloc(did); alloc_id } } @@ -414,7 +414,7 @@ impl<'tcx> GlobalAlloc<'tcx> { } } -crate struct AllocMap<'tcx> { +pub(crate) struct AllocMap<'tcx> { /// Maps `AllocId`s to their corresponding allocations. alloc_map: FxHashMap>, @@ -430,7 +430,7 @@ crate struct AllocMap<'tcx> { } impl<'tcx> AllocMap<'tcx> { - crate fn new() -> Self { + pub(crate) fn new() -> Self { AllocMap { alloc_map: Default::default(), dedup: Default::default(), diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs index 7e5989b4112cf..5fb8e911124d2 100644 --- a/compiler/rustc_middle/src/mir/interpret/queries.rs +++ b/compiler/rustc_middle/src/mir/interpret/queries.rs @@ -110,11 +110,22 @@ impl<'tcx> TyCtxt<'tcx> { Ok(self.global_alloc(raw_const.alloc_id).unwrap_memory()) } - /// Destructure a constant ADT or array into its variant index and its field values. + /// Destructure a type-level constant ADT or array into its variant index and its field values. + /// Panics if the destructuring fails, use `try_destructure_const` for fallible version. pub fn destructure_const( self, param_env_and_val: ty::ParamEnvAnd<'tcx, ty::Const<'tcx>>, ) -> mir::DestructuredConst<'tcx> { self.try_destructure_const(param_env_and_val).unwrap() } + + /// Destructure a mir constant ADT or array into its variant index and its field values. + /// Panics if the destructuring fails, use `try_destructure_const` for fallible version. + pub fn destructure_mir_constant( + self, + param_env: ty::ParamEnv<'tcx>, + constant: mir::ConstantKind<'tcx>, + ) -> mir::DestructuredMirConstant<'tcx> { + self.try_destructure_mir_constant(param_env.and(constant)).unwrap() + } } diff --git a/compiler/rustc_middle/src/mir/interpret/value.rs b/compiler/rustc_middle/src/mir/interpret/value.rs index eeee170f43f94..d00dae85367b8 100644 --- a/compiler/rustc_middle/src/mir/interpret/value.rs +++ b/compiler/rustc_middle/src/mir/interpret/value.rs @@ -397,38 +397,38 @@ impl<'tcx, Tag: Provenance> Scalar { /// Converts the scalar to produce an unsigned integer of the given size. /// Fails if the scalar is a pointer. #[inline] - pub fn to_uint(self, size: Size) -> InterpResult<'static, u128> { + pub fn to_uint(self, size: Size) -> InterpResult<'tcx, u128> { self.to_bits(size) } /// Converts the scalar to produce a `u8`. Fails if the scalar is a pointer. - pub fn to_u8(self) -> InterpResult<'static, u8> { + pub fn to_u8(self) -> InterpResult<'tcx, u8> { self.to_uint(Size::from_bits(8)).map(|v| u8::try_from(v).unwrap()) } /// Converts the scalar to produce a `u16`. Fails if the scalar is a pointer. - pub fn to_u16(self) -> InterpResult<'static, u16> { + pub fn to_u16(self) -> InterpResult<'tcx, u16> { self.to_uint(Size::from_bits(16)).map(|v| u16::try_from(v).unwrap()) } /// Converts the scalar to produce a `u32`. Fails if the scalar is a pointer. - pub fn to_u32(self) -> InterpResult<'static, u32> { + pub fn to_u32(self) -> InterpResult<'tcx, u32> { self.to_uint(Size::from_bits(32)).map(|v| u32::try_from(v).unwrap()) } /// Converts the scalar to produce a `u64`. Fails if the scalar is a pointer. - pub fn to_u64(self) -> InterpResult<'static, u64> { + pub fn to_u64(self) -> InterpResult<'tcx, u64> { self.to_uint(Size::from_bits(64)).map(|v| u64::try_from(v).unwrap()) } /// Converts the scalar to produce a `u128`. Fails if the scalar is a pointer. - pub fn to_u128(self) -> InterpResult<'static, u128> { + pub fn to_u128(self) -> InterpResult<'tcx, u128> { self.to_uint(Size::from_bits(128)) } /// Converts the scalar to produce a machine-pointer-sized unsigned integer. /// Fails if the scalar is a pointer. - pub fn to_machine_usize(self, cx: &impl HasDataLayout) -> InterpResult<'static, u64> { + pub fn to_machine_usize(self, cx: &impl HasDataLayout) -> InterpResult<'tcx, u64> { let b = self.to_uint(cx.data_layout().pointer_size)?; Ok(u64::try_from(b).unwrap()) } @@ -436,51 +436,51 @@ impl<'tcx, Tag: Provenance> Scalar { /// Converts the scalar to produce a signed integer of the given size. /// Fails if the scalar is a pointer. #[inline] - pub fn to_int(self, size: Size) -> InterpResult<'static, i128> { + pub fn to_int(self, size: Size) -> InterpResult<'tcx, i128> { let b = self.to_bits(size)?; Ok(size.sign_extend(b) as i128) } /// Converts the scalar to produce an `i8`. Fails if the scalar is a pointer. - pub fn to_i8(self) -> InterpResult<'static, i8> { + pub fn to_i8(self) -> InterpResult<'tcx, i8> { self.to_int(Size::from_bits(8)).map(|v| i8::try_from(v).unwrap()) } /// Converts the scalar to produce an `i16`. Fails if the scalar is a pointer. - pub fn to_i16(self) -> InterpResult<'static, i16> { + pub fn to_i16(self) -> InterpResult<'tcx, i16> { self.to_int(Size::from_bits(16)).map(|v| i16::try_from(v).unwrap()) } /// Converts the scalar to produce an `i32`. Fails if the scalar is a pointer. - pub fn to_i32(self) -> InterpResult<'static, i32> { + pub fn to_i32(self) -> InterpResult<'tcx, i32> { self.to_int(Size::from_bits(32)).map(|v| i32::try_from(v).unwrap()) } /// Converts the scalar to produce an `i64`. Fails if the scalar is a pointer. - pub fn to_i64(self) -> InterpResult<'static, i64> { + pub fn to_i64(self) -> InterpResult<'tcx, i64> { self.to_int(Size::from_bits(64)).map(|v| i64::try_from(v).unwrap()) } /// Converts the scalar to produce an `i128`. Fails if the scalar is a pointer. - pub fn to_i128(self) -> InterpResult<'static, i128> { + pub fn to_i128(self) -> InterpResult<'tcx, i128> { self.to_int(Size::from_bits(128)) } /// Converts the scalar to produce a machine-pointer-sized signed integer. /// Fails if the scalar is a pointer. - pub fn to_machine_isize(self, cx: &impl HasDataLayout) -> InterpResult<'static, i64> { + pub fn to_machine_isize(self, cx: &impl HasDataLayout) -> InterpResult<'tcx, i64> { let b = self.to_int(cx.data_layout().pointer_size)?; Ok(i64::try_from(b).unwrap()) } #[inline] - pub fn to_f32(self) -> InterpResult<'static, Single> { + pub fn to_f32(self) -> InterpResult<'tcx, Single> { // Going through `u32` to check size and truncation. Ok(Single::from_bits(self.to_u32()?.into())) } #[inline] - pub fn to_f64(self) -> InterpResult<'static, Double> { + pub fn to_f64(self) -> InterpResult<'tcx, Double> { // Going through `u64` to check size and truncation. Ok(Double::from_bits(self.to_u64()?.into())) } @@ -534,7 +534,7 @@ impl ScalarMaybeUninit { } #[inline] - pub fn check_init(self) -> InterpResult<'static, Scalar> { + pub fn check_init<'tcx>(self) -> InterpResult<'tcx, Scalar> { match self { ScalarMaybeUninit::Scalar(scalar) => Ok(scalar), ScalarMaybeUninit::Uninit => throw_ub!(InvalidUninitBytes(None)), diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index af18adac2ff79..d9cdca8bcb5d7 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -3,7 +3,7 @@ //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/mir/index.html use crate::mir::coverage::{CodeRegion, CoverageKind}; -use crate::mir::interpret::{ConstAllocation, ConstValue, GlobalAlloc, Scalar}; +use crate::mir::interpret::{ConstAllocation, ConstValue, GlobalAlloc, LitToConstInput, Scalar}; use crate::mir::visit::MirVisitable; use crate::ty::adjustment::PointerCast; use crate::ty::codec::{TyDecoder, TyEncoder}; @@ -13,6 +13,7 @@ use crate::ty::subst::{GenericArg, InternalSubsts, Subst, SubstsRef}; use crate::ty::{self, List, Ty, TyCtxt}; use crate::ty::{AdtDef, InstanceDef, Region, ScalarInt, UserTypeAnnotationIndex}; +use rustc_data_structures::captures::Captures; use rustc_errors::ErrorGuaranteed; use rustc_hir::def::{CtorKind, Namespace}; use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID}; @@ -171,12 +172,14 @@ pub enum MirPhase { /// terminator means that the auto-generated drop glue will be invoked. Also, `Copy` operands /// are allowed for non-`Copy` types. DropsLowered = 3, + /// After this projections may only contain deref projections as the first element. + Derefered = 4, /// Beginning with this phase, the following variant is disallowed: /// * [`Rvalue::Aggregate`] for any `AggregateKind` except `Array` /// /// And the following variant is allowed: /// * [`StatementKind::SetDiscriminant`] - Deaggregated = 4, + Deaggregated = 5, /// Before this phase, generators are in the "source code" form, featuring `yield` statements /// and such. With this phase change, they are transformed into a proper state machine. Running /// optimizations before this change can be potentially dangerous because the source code is to @@ -189,9 +192,9 @@ pub enum MirPhase { /// /// Beginning with this phase, the following variants are disallowed: /// * [`TerminatorKind::Yield`](terminator::TerminatorKind::Yield) - /// * [`TerminatorKind::GeneratorDrop](terminator::TerminatorKind::GeneratorDrop) - GeneratorsLowered = 5, - Optimized = 6, + /// * [`TerminatorKind::GeneratorDrop`](terminator::TerminatorKind::GeneratorDrop) + GeneratorsLowered = 6, + Optimized = 7, } impl MirPhase { @@ -484,7 +487,7 @@ impl<'tcx> Body<'tcx> { /// Returns an iterator over all user-declared mutable locals. #[inline] - pub fn mut_vars_iter<'a>(&'a self) -> impl Iterator + 'a { + pub fn mut_vars_iter<'a>(&'a self) -> impl Iterator + Captures<'tcx> + 'a { (self.arg_count + 1..self.local_decls.len()).filter_map(move |index| { let local = Local::new(index); let decl = &self.local_decls[local]; @@ -498,7 +501,9 @@ impl<'tcx> Body<'tcx> { /// Returns an iterator over all user-declared mutable arguments and locals. #[inline] - pub fn mut_vars_and_args_iter<'a>(&'a self) -> impl Iterator + 'a { + pub fn mut_vars_and_args_iter<'a>( + &'a self, + ) -> impl Iterator + Captures<'tcx> + 'a { (1..self.local_decls.len()).filter_map(move |index| { let local = Local::new(index); let decl = &self.local_decls[local]; @@ -665,7 +670,7 @@ impl ClearCrossCrate { const TAG_CLEAR_CROSS_CRATE_CLEAR: u8 = 0; const TAG_CLEAR_CROSS_CRATE_SET: u8 = 1; -impl<'tcx, E: TyEncoder<'tcx>, T: Encodable> Encodable for ClearCrossCrate { +impl> Encodable for ClearCrossCrate { #[inline] fn encode(&self, e: &mut E) -> Result<(), E::Error> { if E::CLEAR_CROSS_CRATE { @@ -681,7 +686,7 @@ impl<'tcx, E: TyEncoder<'tcx>, T: Encodable> Encodable for ClearCrossCrate } } } -impl<'tcx, D: TyDecoder<'tcx>, T: Decodable> Decodable for ClearCrossCrate { +impl> Decodable for ClearCrossCrate { #[inline] fn decode(d: &mut D) -> ClearCrossCrate { if D::CLEAR_CROSS_CRATE { @@ -1355,10 +1360,7 @@ pub enum InlineAsmOperand<'tcx> { /// Type for MIR `Assert` terminator error messages. pub type AssertMessage<'tcx> = AssertKind>; -// FIXME: Change `Successors` to `impl Iterator`. -#[allow(rustc::pass_by_value)] -pub type Successors<'a> = - iter::Chain, slice::Iter<'a, BasicBlock>>; +pub type Successors<'a> = impl Iterator + 'a; pub type SuccessorsMut<'a> = iter::Chain, slice::IterMut<'a, BasicBlock>>; @@ -2602,9 +2604,20 @@ pub enum Rvalue<'tcx> { #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] static_assert_size!(Rvalue<'_>, 40); +impl<'tcx> Rvalue<'tcx> { + #[inline] + pub fn is_pointer_int_cast(&self) -> bool { + matches!(self, Rvalue::Cast(CastKind::PointerExposeAddress, _, _)) + } +} + #[derive(Clone, Copy, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)] pub enum CastKind { Misc, + /// An exposing pointer to address cast. A cast between a pointer and an integer type, or + /// between a function pointer and an integer type. + /// See the docs on `expose_addr` for more details. + PointerExposeAddress, Pointer(PointerCast), } @@ -3078,6 +3091,58 @@ impl<'tcx> ConstantKind<'tcx> { Self::from_opt_const_arg_anon_const(tcx, ty::WithOptConstParam::unknown(def_id), param_env) } + #[instrument(skip(tcx), level = "debug")] + pub fn from_inline_const(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self { + let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); + let body_id = match tcx.hir().get(hir_id) { + hir::Node::AnonConst(ac) => ac.body, + _ => span_bug!( + tcx.def_span(def_id.to_def_id()), + "from_inline_const can only process anonymous constants" + ), + }; + let expr = &tcx.hir().body(body_id).value; + let ty = tcx.typeck(def_id).node_type(hir_id); + + let lit_input = match expr.kind { + hir::ExprKind::Lit(ref lit) => Some(LitToConstInput { lit: &lit.node, ty, neg: false }), + hir::ExprKind::Unary(hir::UnOp::Neg, ref expr) => match expr.kind { + hir::ExprKind::Lit(ref lit) => { + Some(LitToConstInput { lit: &lit.node, ty, neg: true }) + } + _ => None, + }, + _ => None, + }; + if let Some(lit_input) = lit_input { + // If an error occurred, ignore that it's a literal and leave reporting the error up to + // mir. + match tcx.at(expr.span).lit_to_mir_constant(lit_input) { + Ok(c) => return c, + Err(_) => {} + } + } + + let typeck_root_def_id = tcx.typeck_root_def_id(def_id.to_def_id()); + let parent_substs = + tcx.erase_regions(InternalSubsts::identity_for_item(tcx, typeck_root_def_id)); + let substs = + ty::InlineConstSubsts::new(tcx, ty::InlineConstSubstsParts { parent_substs, ty }) + .substs; + let uneval_const = tcx.mk_const(ty::ConstS { + val: ty::ConstKind::Unevaluated(ty::Unevaluated { + def: ty::WithOptConstParam::unknown(def_id).to_global(), + substs, + promoted: None, + }), + ty, + }); + debug!(?uneval_const); + debug_assert!(!uneval_const.has_free_regions()); + + Self::Ty(uneval_const) + } + #[instrument(skip(tcx), level = "debug")] fn from_opt_const_arg_anon_const( tcx: TyCtxt<'tcx>, @@ -3434,13 +3499,13 @@ impl<'tcx> graph::WithStartNode for Body<'tcx> { impl<'tcx> graph::WithSuccessors for Body<'tcx> { #[inline] fn successors(&self, node: Self::Node) -> >::Iter { - self.basic_blocks[node].terminator().successors().cloned() + self.basic_blocks[node].terminator().successors() } } impl<'a, 'b> graph::GraphSuccessors<'b> for Body<'a> { type Item = BasicBlock; - type Iter = iter::Cloned>; + type Iter = Successors<'b>; } impl<'tcx, 'graph> graph::GraphPredecessors<'graph> for Body<'tcx> { diff --git a/compiler/rustc_middle/src/mir/patch.rs b/compiler/rustc_middle/src/mir/patch.rs index d03f9235efd58..c1e1cfef9f89d 100644 --- a/compiler/rustc_middle/src/mir/patch.rs +++ b/compiler/rustc_middle/src/mir/patch.rs @@ -166,11 +166,8 @@ impl<'tcx> MirPatch<'tcx> { // get terminator's targets and apply the statement to all of them. if loc.statement_index > body[loc.block].statements.len() { let term = body[loc.block].terminator(); - let successors = term.successors().clone(); - - for i in successors { - stmts_and_targets - .push((Statement { source_info, kind: stmt.clone() }, i.clone())); + for i in term.successors() { + stmts_and_targets.push((Statement { source_info, kind: stmt.clone() }, i)); } delta += 1; continue; @@ -194,7 +191,7 @@ impl<'tcx> MirPatch<'tcx> { } } - pub fn source_info_for_location(&self, body: &Body<'_>, loc: Location) -> SourceInfo { + pub fn source_info_for_location(&self, body: &Body<'tcx>, loc: Location) -> SourceInfo { let data = match loc.block.index().checked_sub(body.basic_blocks().len()) { Some(new) => &self.new_blocks[new], None => &body[loc.block], diff --git a/compiler/rustc_middle/src/mir/predecessors.rs b/compiler/rustc_middle/src/mir/predecessors.rs index 4fe2cde753290..ad09328585d27 100644 --- a/compiler/rustc_middle/src/mir/predecessors.rs +++ b/compiler/rustc_middle/src/mir/predecessors.rs @@ -43,7 +43,7 @@ impl PredecessorCache { let mut preds = IndexVec::from_elem(SmallVec::new(), basic_blocks); for (bb, data) in basic_blocks.iter_enumerated() { if let Some(term) = &data.terminator { - for &succ in term.successors() { + for succ in term.successors() { preds[succ].push(bb); } } diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 8111409b8bc0e..eaa68bf1b38dd 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -1007,10 +1007,11 @@ fn write_user_type_annotations( for (index, annotation) in body.user_type_annotations.iter_enumerated() { writeln!( w, - "| {:?}: {:?} at {}", + "| {:?}: user_ty: {:?}, span: {}, inferred_ty: {:?}", index.index(), annotation.user_ty, - tcx.sess.source_map().span_to_embeddable_string(annotation.span) + tcx.sess.source_map().span_to_embeddable_string(annotation.span), + annotation.inferred_ty, )?; } if !body.user_type_annotations.is_empty() { diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index 4d4eed179ca9d..01945b543b14b 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -1,6 +1,6 @@ //! Values computed by queries that use MIR. -use crate::mir::{Body, Promoted}; +use crate::mir::{self, Body, Promoted}; use crate::ty::{self, OpaqueHiddenType, Ty, TyCtxt}; use rustc_data_structures::stable_map::FxHashMap; use rustc_data_structures::vec_map::VecMap; @@ -338,11 +338,12 @@ pub struct ClosureOutlivesRequirement<'tcx> { pub blame_span: Span, // ... due to this reason. - pub category: ConstraintCategory, + pub category: ConstraintCategory<'tcx>, } // Make sure this enum doesn't unintentionally grow -rustc_data_structures::static_assert_size!(ConstraintCategory, 12); +#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] +rustc_data_structures::static_assert_size!(ConstraintCategory<'_>, 16); /// Outlives-constraints can be categorized to determine whether and why they /// are interesting (for error reporting). Order of variants indicates sort @@ -351,7 +352,7 @@ rustc_data_structures::static_assert_size!(ConstraintCategory, 12); /// See also `rustc_const_eval::borrow_check::constraints`. #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash)] #[derive(TyEncodable, TyDecodable, HashStable)] -pub enum ConstraintCategory { +pub enum ConstraintCategory<'tcx> { Return(ReturnConstraint), Yield, UseAsConst, @@ -363,7 +364,9 @@ pub enum ConstraintCategory { /// /// We try to get the category that the closure used when reporting this. ClosureBounds, - CallArgument, + + /// Contains the function type if available. + CallArgument(Option>), CopyBound, SizedBound, Assignment, @@ -413,13 +416,20 @@ pub enum ClosureOutlivesSubject<'tcx> { Region(ty::RegionVid), } -/// The constituent parts of an ADT or array. +/// The constituent parts of a type level constant of kind ADT or array. #[derive(Copy, Clone, Debug, HashStable)] pub struct DestructuredConst<'tcx> { pub variant: Option, pub fields: &'tcx [ty::Const<'tcx>], } +/// The constituent parts of a mir constant of kind ADT or array. +#[derive(Copy, Clone, Debug, HashStable)] +pub struct DestructuredMirConstant<'tcx> { + pub variant: Option, + pub fields: &'tcx [mir::ConstantKind<'tcx>], +} + /// Coverage information summarized from a MIR if instrumented for source code coverage (see /// compiler option `-Cinstrument-coverage`). This information is generated by the /// `InstrumentCoverage` MIR pass and can be retrieved via the `coverageinfo` query. diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs index e6eb63fd3b2b8..c859d93043e3e 100644 --- a/compiler/rustc_middle/src/mir/terminator.rs +++ b/compiler/rustc_middle/src/mir/terminator.rs @@ -250,8 +250,10 @@ pub enum TerminatorKind<'tcx> { /// This allows the memory occupied by "by-value" arguments to be /// reused across function calls without duplicating the contents. args: Vec>, - /// Destination for the return value. If none, the call necessarily diverges. - destination: Option<(Place<'tcx>, BasicBlock)>, + /// Where the returned value will be written + destination: Place<'tcx>, + /// Where to go after this call returns. If none, the call necessarily diverges. + target: Option, /// Cleanups to be done if the call unwinds. cleanup: Option, /// `true` if this is from a call in HIR rather than from an overloaded @@ -415,33 +417,37 @@ impl<'tcx> TerminatorKind<'tcx> { | GeneratorDrop | Return | Unreachable - | Call { destination: None, cleanup: None, .. } - | InlineAsm { destination: None, cleanup: None, .. } => None.into_iter().chain(&[]), - Goto { target: ref t } - | Call { destination: None, cleanup: Some(ref t), .. } - | Call { destination: Some((_, ref t)), cleanup: None, .. } - | Yield { resume: ref t, drop: None, .. } - | DropAndReplace { target: ref t, unwind: None, .. } - | Drop { target: ref t, unwind: None, .. } - | Assert { target: ref t, cleanup: None, .. } - | FalseUnwind { real_target: ref t, unwind: None } - | InlineAsm { destination: Some(ref t), cleanup: None, .. } - | InlineAsm { destination: None, cleanup: Some(ref t), .. } => { - Some(t).into_iter().chain(&[]) + | Call { target: None, cleanup: None, .. } + | InlineAsm { destination: None, cleanup: None, .. } => { + None.into_iter().chain((&[]).into_iter().copied()) } - Call { destination: Some((_, ref t)), cleanup: Some(ref u), .. } - | Yield { resume: ref t, drop: Some(ref u), .. } - | DropAndReplace { target: ref t, unwind: Some(ref u), .. } - | Drop { target: ref t, unwind: Some(ref u), .. } - | Assert { target: ref t, cleanup: Some(ref u), .. } - | FalseUnwind { real_target: ref t, unwind: Some(ref u) } - | InlineAsm { destination: Some(ref t), cleanup: Some(ref u), .. } => { - Some(t).into_iter().chain(slice::from_ref(u)) + Goto { target: t } + | Call { target: None, cleanup: Some(t), .. } + | Call { target: Some(t), cleanup: None, .. } + | Yield { resume: t, drop: None, .. } + | DropAndReplace { target: t, unwind: None, .. } + | Drop { target: t, unwind: None, .. } + | Assert { target: t, cleanup: None, .. } + | FalseUnwind { real_target: t, unwind: None } + | InlineAsm { destination: Some(t), cleanup: None, .. } + | InlineAsm { destination: None, cleanup: Some(t), .. } => { + Some(t).into_iter().chain((&[]).into_iter().copied()) } - SwitchInt { ref targets, .. } => None.into_iter().chain(&targets.targets), - FalseEdge { ref real_target, ref imaginary_target } => { - Some(real_target).into_iter().chain(slice::from_ref(imaginary_target)) + Call { target: Some(t), cleanup: Some(ref u), .. } + | Yield { resume: t, drop: Some(ref u), .. } + | DropAndReplace { target: t, unwind: Some(ref u), .. } + | Drop { target: t, unwind: Some(ref u), .. } + | Assert { target: t, cleanup: Some(ref u), .. } + | FalseUnwind { real_target: t, unwind: Some(ref u) } + | InlineAsm { destination: Some(t), cleanup: Some(ref u), .. } => { + Some(t).into_iter().chain(slice::from_ref(u).into_iter().copied()) } + SwitchInt { ref targets, .. } => { + None.into_iter().chain(targets.targets.iter().copied()) + } + FalseEdge { real_target, ref imaginary_target } => Some(real_target) + .into_iter() + .chain(slice::from_ref(imaginary_target).into_iter().copied()), } } @@ -453,11 +459,11 @@ impl<'tcx> TerminatorKind<'tcx> { | GeneratorDrop | Return | Unreachable - | Call { destination: None, cleanup: None, .. } + | Call { target: None, cleanup: None, .. } | InlineAsm { destination: None, cleanup: None, .. } => None.into_iter().chain(&mut []), Goto { target: ref mut t } - | Call { destination: None, cleanup: Some(ref mut t), .. } - | Call { destination: Some((_, ref mut t)), cleanup: None, .. } + | Call { target: None, cleanup: Some(ref mut t), .. } + | Call { target: Some(ref mut t), cleanup: None, .. } | Yield { resume: ref mut t, drop: None, .. } | DropAndReplace { target: ref mut t, unwind: None, .. } | Drop { target: ref mut t, unwind: None, .. } @@ -467,7 +473,7 @@ impl<'tcx> TerminatorKind<'tcx> { | InlineAsm { destination: None, cleanup: Some(ref mut t), .. } => { Some(t).into_iter().chain(&mut []) } - Call { destination: Some((_, ref mut t)), cleanup: Some(ref mut u), .. } + Call { target: Some(ref mut t), cleanup: Some(ref mut u), .. } | Yield { resume: ref mut t, drop: Some(ref mut u), .. } | DropAndReplace { target: ref mut t, unwind: Some(ref mut u), .. } | Drop { target: ref mut t, unwind: Some(ref mut u), .. } @@ -586,9 +592,7 @@ impl<'tcx> TerminatorKind<'tcx> { write!(fmt, "replace({:?} <- {:?})", place, value) } Call { func, args, destination, .. } => { - if let Some((destination, _)) = destination { - write!(fmt, "{:?} = ", destination)?; - } + write!(fmt, "{:?} = ", destination)?; write!(fmt, "{:?}(", func)?; for (index, arg) in args.iter().enumerate() { if index > 0 { @@ -679,12 +683,12 @@ impl<'tcx> TerminatorKind<'tcx> { .chain(iter::once("otherwise".into())) .collect() }), - Call { destination: Some(_), cleanup: Some(_), .. } => { + Call { target: Some(_), cleanup: Some(_), .. } => { vec!["return".into(), "unwind".into()] } - Call { destination: Some(_), cleanup: None, .. } => vec!["return".into()], - Call { destination: None, cleanup: Some(_), .. } => vec!["unwind".into()], - Call { destination: None, cleanup: None, .. } => vec![], + Call { target: Some(_), cleanup: None, .. } => vec!["return".into()], + Call { target: None, cleanup: Some(_), .. } => vec!["unwind".into()], + Call { target: None, cleanup: None, .. } => vec![], Yield { drop: Some(_), .. } => vec!["resume".into(), "drop".into()], Yield { drop: None, .. } => vec!["resume".into()], DropAndReplace { unwind: None, .. } | Drop { unwind: None, .. } => { diff --git a/compiler/rustc_middle/src/mir/traversal.rs b/compiler/rustc_middle/src/mir/traversal.rs index 8d831cc73b8a4..1cbfed621560d 100644 --- a/compiler/rustc_middle/src/mir/traversal.rs +++ b/compiler/rustc_middle/src/mir/traversal.rs @@ -180,7 +180,7 @@ impl<'a, 'tcx> Postorder<'a, 'tcx> { // two iterations yield `C` and finally `A` for a final traversal of [E, D, B, C, A] loop { let bb = if let Some(&mut (_, ref mut iter)) = self.visit_stack.last_mut() { - if let Some(&bb) = iter.next() { + if let Some(bb) = iter.next() { bb } else { break; diff --git a/compiler/rustc_middle/src/mir/type_foldable.rs b/compiler/rustc_middle/src/mir/type_foldable.rs index 901f3bf4f7d41..14d4cb2c3302e 100644 --- a/compiler/rustc_middle/src/mir/type_foldable.rs +++ b/compiler/rustc_middle/src/mir/type_foldable.rs @@ -44,20 +44,15 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> { resume_arg: resume_arg.try_fold_with(folder)?, drop, }, - Call { func, args, destination, cleanup, from_hir_call, fn_span } => { - let dest = destination - .map(|(loc, dest)| (loc.try_fold_with(folder).map(|loc| (loc, dest)))) - .transpose()?; - - Call { - func: func.try_fold_with(folder)?, - args: args.try_fold_with(folder)?, - destination: dest, - cleanup, - from_hir_call, - fn_span, - } - } + Call { func, args, destination, target, cleanup, from_hir_call, fn_span } => Call { + func: func.try_fold_with(folder)?, + args: args.try_fold_with(folder)?, + destination: destination.try_fold_with(folder)?, + target, + cleanup, + from_hir_call, + fn_span, + }, Assert { cond, expected, msg, target, cleanup } => { use AssertKind::*; let msg = match msg { @@ -113,9 +108,7 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> { } Yield { ref value, .. } => value.visit_with(visitor), Call { ref func, ref args, ref destination, .. } => { - if let Some((ref loc, _)) = *destination { - loc.visit_with(visitor)?; - }; + destination.visit_with(visitor)?; func.visit_with(visitor)?; args.visit_with(visitor) } diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index ef4f1f5e84ef5..5ce92d127f3db 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -258,7 +258,7 @@ macro_rules! make_mir_visitor { // for best performance, we want to use an iterator rather // than a for-loop, to avoid calling `body::Body::invalidate` for // each basic block. - #[cfg_attr(not(bootstrap), allow(unused_macro_rules))] + #[allow(unused_macro_rules)] macro_rules! basic_blocks { (mut) => (body.basic_blocks_mut().iter_enumerated_mut()); () => (body.basic_blocks().iter_enumerated()); @@ -280,7 +280,7 @@ macro_rules! make_mir_visitor { self.visit_local_decl(local, & $($mutability)? body.local_decls[local]); } - #[cfg_attr(not(bootstrap), allow(unused_macro_rules))] + #[allow(unused_macro_rules)] macro_rules! type_annotations { (mut) => (body.user_type_annotations.iter_enumerated_mut()); () => (body.user_type_annotations.iter_enumerated()); @@ -534,6 +534,7 @@ macro_rules! make_mir_visitor { func, args, destination, + target: _, cleanup: _, from_hir_call: _, fn_span: _ @@ -542,13 +543,11 @@ macro_rules! make_mir_visitor { for arg in args { self.visit_operand(arg, location); } - if let Some((destination, _)) = destination { - self.visit_place( - destination, - PlaceContext::MutatingUse(MutatingUseContext::Call), - location - ); - } + self.visit_place( + destination, + PlaceContext::MutatingUse(MutatingUseContext::Call), + location + ); } TerminatorKind::Assert { @@ -934,7 +933,7 @@ macro_rules! make_mir_visitor { body: &$($mutability)? Body<'tcx>, location: Location ) { - #[cfg_attr(not(bootstrap), allow(unused_macro_rules))] + #[allow(unused_macro_rules)] macro_rules! basic_blocks { (mut) => (body.basic_blocks_mut()); () => (body.basic_blocks()); diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 6d7ec247d0452..38d8e0b581953 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -59,6 +59,7 @@ rustc_queries! { query hir_module_items(key: LocalDefId) -> rustc_middle::hir::ModuleItems { storage(ArenaCacheSelector<'tcx>) desc { |tcx| "HIR module items in `{}`", tcx.def_path_str(key.to_def_id()) } + cache_on_disk_if { true } } /// Gives access to the HIR node for the HIR owner `key`. @@ -128,6 +129,7 @@ rustc_queries! { /// parameter. e.g. `fn example` called on `N` would return `3`. query const_param_default(param: DefId) -> ty::Const<'tcx> { desc { |tcx| "compute const default for a given parameter `{}`", tcx.def_path_str(param) } + cache_on_disk_if { param.is_local() } separate_provide_extern } @@ -223,6 +225,7 @@ rustc_queries! { /// Bounds from the parent (e.g. with nested impl trait) are not included. query explicit_item_bounds(key: DefId) -> &'tcx [(ty::Predicate<'tcx>, Span)] { desc { |tcx| "finding item bounds for `{}`", tcx.def_path_str(key) } + cache_on_disk_if { key.is_local() } separate_provide_extern } @@ -508,6 +511,7 @@ rustc_queries! { /// Returns the predicates written explicitly by the user. query explicit_predicates_of(key: DefId) -> ty::GenericPredicates<'tcx> { desc { |tcx| "computing explicit predicates of `{}`", tcx.def_path_str(key) } + cache_on_disk_if { key.is_local() } separate_provide_extern } @@ -515,6 +519,7 @@ rustc_queries! { /// Foo<'a, T> { x: &'a T }`, this would return `T: 'a`). query inferred_outlives_of(key: DefId) -> &'tcx [(ty::Predicate<'tcx>, Span)] { desc { |tcx| "computing inferred outlives predicates of `{}`", tcx.def_path_str(key) } + cache_on_disk_if { key.is_local() } separate_provide_extern } @@ -526,6 +531,7 @@ rustc_queries! { /// additional acyclicity requirements). query super_predicates_of(key: DefId) -> ty::GenericPredicates<'tcx> { desc { |tcx| "computing the super predicates of `{}`", tcx.def_path_str(key) } + cache_on_disk_if { key.is_local() } separate_provide_extern } @@ -549,6 +555,7 @@ rustc_queries! { query trait_def(key: DefId) -> ty::TraitDef { desc { |tcx| "computing trait definition for `{}`", tcx.def_path_str(key) } storage(ArenaCacheSelector<'tcx>) + cache_on_disk_if { key.is_local() } separate_provide_extern } query adt_def(key: DefId) -> ty::AdtDef<'tcx> { @@ -558,6 +565,7 @@ rustc_queries! { } query adt_destructor(key: DefId) -> Option { desc { |tcx| "computing `Drop` impl for `{}`", tcx.def_path_str(key) } + cache_on_disk_if { key.is_local() } separate_provide_extern } @@ -587,11 +595,13 @@ rustc_queries! { /// `is_const_fn` function. query impl_constness(key: DefId) -> hir::Constness { desc { |tcx| "checking if item is const fn: `{}`", tcx.def_path_str(key) } + cache_on_disk_if { key.is_local() } separate_provide_extern } query asyncness(key: DefId) -> hir::IsAsync { desc { |tcx| "checking if the function is async: `{}`", tcx.def_path_str(key) } + cache_on_disk_if { key.is_local() } separate_provide_extern } @@ -609,12 +619,14 @@ rustc_queries! { /// Returns `true` if this is a foreign item (i.e., linked via `extern { ... }`). query is_foreign_item(key: DefId) -> bool { desc { |tcx| "checking if `{}` is a foreign item", tcx.def_path_str(key) } + cache_on_disk_if { key.is_local() } separate_provide_extern } /// Returns `Some(generator_kind)` if the node pointed to by `def_id` is a generator. query generator_kind(def_id: DefId) -> Option { desc { |tcx| "looking up generator kind of `{}`", tcx.def_path_str(def_id) } + cache_on_disk_if { def_id.is_local() } separate_provide_extern } @@ -627,6 +639,7 @@ rustc_queries! { /// Maps from the `DefId` of a type or region parameter to its (inferred) variance. query variances_of(def_id: DefId) -> &'tcx [ty::Variance] { desc { |tcx| "computing the variances of `{}`", tcx.def_path_str(def_id) } + cache_on_disk_if { def_id.is_local() } separate_provide_extern } @@ -639,6 +652,7 @@ rustc_queries! { /// Maps from an impl/trait `DefId` to a list of the `DefId`s of its items. query associated_item_def_ids(key: DefId) -> &'tcx [DefId] { desc { |tcx| "collecting associated items of `{}`", tcx.def_path_str(key) } + cache_on_disk_if { key.is_local() } separate_provide_extern } @@ -646,6 +660,7 @@ rustc_queries! { query associated_item(key: DefId) -> ty::AssocItem { desc { |tcx| "computing associated item data for `{}`", tcx.def_path_str(key) } storage(ArenaCacheSelector<'tcx>) + cache_on_disk_if { key.is_local() } separate_provide_extern } @@ -685,10 +700,12 @@ rustc_queries! { /// Return `None` if this is an inherent impl. query impl_trait_ref(impl_id: DefId) -> Option> { desc { |tcx| "computing trait implemented by `{}`", tcx.def_path_str(impl_id) } + cache_on_disk_if { impl_id.is_local() } separate_provide_extern } query impl_polarity(impl_id: DefId) -> ty::ImplPolarity { desc { |tcx| "computing implementation polarity of `{}`", tcx.def_path_str(impl_id) } + cache_on_disk_if { impl_id.is_local() } separate_provide_extern } @@ -701,6 +718,7 @@ rustc_queries! { /// Methods in these implementations don't need to be exported. query inherent_impls(key: DefId) -> &'tcx [DefId] { desc { |tcx| "collecting inherent impls for `{}`", tcx.def_path_str(key) } + cache_on_disk_if { key.is_local() } separate_provide_extern } @@ -745,6 +763,7 @@ rustc_queries! { /// Computes the signature of the function. query fn_sig(key: DefId) -> ty::PolyFnSig<'tcx> { desc { |tcx| "computing function signature of `{}`", tcx.def_path_str(key) } + cache_on_disk_if { key.is_local() } separate_provide_extern } @@ -785,10 +804,6 @@ rustc_queries! { desc { |tcx| "checking privacy in {}", describe_as_module(key, tcx) } } - query check_mod_intrinsics(key: LocalDefId) -> () { - desc { |tcx| "checking intrinsics in {}", describe_as_module(key, tcx) } - } - query check_mod_liveness(key: LocalDefId) -> () { desc { |tcx| "checking liveness of variables in {}", describe_as_module(key, tcx) } } @@ -820,6 +835,7 @@ rustc_queries! { /// Caches `CoerceUnsized` kinds for impls on custom types. query coerce_unsized_info(key: DefId) -> ty::adjustment::CoerceUnsizedInfo { desc { |tcx| "computing CoerceUnsized info for `{}`", tcx.def_path_str(key) } + cache_on_disk_if { key.is_local() } separate_provide_extern } @@ -946,12 +962,12 @@ rustc_queries! { cache_on_disk_if { true } } - /// Convert an evaluated constant to a type level constant or + /// Evaluate a constant and convert it to a type level constant or /// return `None` if that is not possible. - query const_to_valtree( - key: ty::ParamEnvAnd<'tcx, ConstAlloc<'tcx>> - ) -> Option> { - desc { "destructure constant" } + query eval_to_valtree( + key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>> + ) -> EvalToValTreeResult<'tcx> { + desc { "evaluate type-level constant" } remap_env_constness } @@ -964,10 +980,14 @@ rustc_queries! { /// field values or return `None` if constant is invalid. /// /// Use infallible `TyCtxt::destructure_const` when you know that constant is valid. - query try_destructure_const( - key: ty::ParamEnvAnd<'tcx, ty::Const<'tcx>> - ) -> Option> { - desc { "destructure constant" } + query try_destructure_const(key: ty::ParamEnvAnd<'tcx, ty::Const<'tcx>>) -> Option> { + desc { "destructure type level constant"} + } + + /// Tries to destructure an `mir::ConstantKind` ADT or array into its variant index + /// and its field values. + query try_destructure_mir_constant(key: ty::ParamEnvAnd<'tcx, mir::ConstantKind<'tcx>>) -> Option> { + desc { "destructure mir constant"} remap_env_constness } @@ -980,6 +1000,15 @@ rustc_queries! { remap_env_constness } + /// Dereference a constant reference or raw pointer and turn the result into a constant + /// again. + query deref_mir_constant( + key: ty::ParamEnvAnd<'tcx, mir::ConstantKind<'tcx>> + ) -> mir::ConstantKind<'tcx> { + desc { "deref constant" } + remap_env_constness + } + query const_caller_location(key: (rustc_span::Symbol, u32, u32)) -> ConstValue<'tcx> { desc { "get a &core::panic::Location referring to a span" } } @@ -991,6 +1020,10 @@ rustc_queries! { desc { "converting literal to const" } } + query lit_to_mir_constant(key: LitToConstInput<'tcx>) -> Result, LitToConstError> { + desc { "converting literal to mir constant" } + } + query check_match(key: DefId) { desc { |tcx| "match-checking `{}`", tcx.def_path_str(key) } cache_on_disk_if { key.is_local() } @@ -1013,7 +1046,7 @@ rustc_queries! { /// Per-body `region::ScopeTree`. The `DefId` should be the owner `DefId` for the body; /// in the case of closures, this will be redirected to the enclosing function. - query region_scope_tree(def_id: DefId) -> &'tcx region::ScopeTree { + query region_scope_tree(def_id: DefId) -> &'tcx crate::middle::region::ScopeTree { desc { |tcx| "computing drop scopes for `{}`", tcx.def_path_str(def_id) } } @@ -1033,28 +1066,33 @@ rustc_queries! { query opt_def_kind(def_id: DefId) -> Option { desc { |tcx| "looking up definition kind of `{}`", tcx.def_path_str(def_id) } + cache_on_disk_if { def_id.is_local() } separate_provide_extern } /// Gets the span for the definition. query def_span(def_id: DefId) -> Span { desc { |tcx| "looking up span for `{}`", tcx.def_path_str(def_id) } + cache_on_disk_if { def_id.is_local() } separate_provide_extern } /// Gets the span for the identifier of the definition. query def_ident_span(def_id: DefId) -> Option { desc { |tcx| "looking up span for `{}`'s identifier", tcx.def_path_str(def_id) } + cache_on_disk_if { def_id.is_local() } separate_provide_extern } query lookup_stability(def_id: DefId) -> Option { desc { |tcx| "looking up stability of `{}`", tcx.def_path_str(def_id) } + cache_on_disk_if { def_id.is_local() } separate_provide_extern } query lookup_const_stability(def_id: DefId) -> Option { desc { |tcx| "looking up const stability of `{}`", tcx.def_path_str(def_id) } + cache_on_disk_if { def_id.is_local() } separate_provide_extern } @@ -1064,6 +1102,7 @@ rustc_queries! { query lookup_deprecation_entry(def_id: DefId) -> Option { desc { |tcx| "checking whether `{}` is deprecated", tcx.def_path_str(def_id) } + cache_on_disk_if { def_id.is_local() } separate_provide_extern } @@ -1093,6 +1132,7 @@ rustc_queries! { query fn_arg_names(def_id: DefId) -> &'tcx [rustc_span::symbol::Ident] { desc { |tcx| "looking up function parameter names for `{}`", tcx.def_path_str(def_id) } + cache_on_disk_if { def_id.is_local() } separate_provide_extern } /// Gets the rendered value of the specified constant or associated constant. @@ -1100,10 +1140,12 @@ rustc_queries! { query rendered_const(def_id: DefId) -> String { storage(ArenaCacheSelector<'tcx>) desc { |tcx| "rendering constant intializer of `{}`", tcx.def_path_str(def_id) } + cache_on_disk_if { def_id.is_local() } separate_provide_extern } query impl_parent(def_id: DefId) -> Option { desc { |tcx| "computing specialization parent impl of `{}`", tcx.def_path_str(def_id) } + cache_on_disk_if { def_id.is_local() } separate_provide_extern } @@ -1111,15 +1153,18 @@ rustc_queries! { /// Return `None` if the `DefId` is not an associated item. query trait_of_item(associated_item: DefId) -> Option { desc { |tcx| "finding trait defining `{}`", tcx.def_path_str(associated_item) } + cache_on_disk_if { associated_item.is_local() } separate_provide_extern } query is_ctfe_mir_available(key: DefId) -> bool { desc { |tcx| "checking if item has ctfe mir available: `{}`", tcx.def_path_str(key) } + cache_on_disk_if { key.is_local() } separate_provide_extern } query is_mir_available(key: DefId) -> bool { desc { |tcx| "checking if item has mir available: `{}`", tcx.def_path_str(key) } + cache_on_disk_if { key.is_local() } separate_provide_extern } @@ -1361,6 +1406,7 @@ rustc_queries! { query impl_defaultness(def_id: DefId) -> hir::Defaultness { desc { |tcx| "looking up whether `{}` is a default impl", tcx.def_path_str(def_id) } + cache_on_disk_if { def_id.is_local() } separate_provide_extern } @@ -1394,6 +1440,7 @@ rustc_queries! { } query is_reachable_non_generic(def_id: DefId) -> bool { desc { |tcx| "checking whether `{}` is an exported symbol", tcx.def_path_str(def_id) } + cache_on_disk_if { def_id.is_local() } separate_provide_extern } query is_unreachable_local_definition(def_id: LocalDefId) -> bool { @@ -1601,6 +1648,11 @@ rustc_queries! { desc { "calculating the lib features defined in a crate" } separate_provide_extern } + /// Whether the function is an intrinsic + query is_intrinsic(def_id: DefId) -> bool { + desc { |tcx| "is_intrinsic({})", tcx.def_path_str(def_id) } + separate_provide_extern + } /// Returns the lang items defined in another crate by loading it from metadata. query get_lang_items(_: ()) -> LanguageItems { storage(ArenaCacheSelector<'tcx>) @@ -1708,9 +1760,9 @@ rustc_queries! { /// - All names contained in `exported_symbols(cnum)` are guaranteed to /// correspond to a publicly visible symbol in `cnum` machine code. /// - The `exported_symbols` sets of different crates do not intersect. - query exported_symbols(_: CrateNum) - -> &'tcx [(ExportedSymbol<'tcx>, SymbolExportInfo)] { + query exported_symbols(cnum: CrateNum) -> &'tcx [(ExportedSymbol<'tcx>, SymbolExportInfo)] { desc { "exported_symbols" } + cache_on_disk_if { *cnum == LOCAL_CRATE } separate_provide_extern } diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index fdf5ecfdaf7ef..b99e7573000c9 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -18,15 +18,11 @@ use rustc_index::vec::IndexVec; use rustc_middle::infer::canonical::Canonical; use rustc_middle::middle::region; use rustc_middle::mir::interpret::AllocId; -use rustc_middle::mir::{ - self, BinOp, BorrowKind, FakeReadCause, Field, Mutability, UnOp, UserTypeProjection, -}; +use rustc_middle::mir::{self, BinOp, BorrowKind, FakeReadCause, Field, Mutability, UnOp}; use rustc_middle::ty::adjustment::PointerCast; use rustc_middle::ty::subst::SubstsRef; +use rustc_middle::ty::CanonicalUserTypeAnnotation; use rustc_middle::ty::{self, AdtDef, Ty, UpvarSubsts, UserType}; -use rustc_middle::ty::{ - CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, -}; use rustc_span::{Span, Symbol, DUMMY_SP}; use rustc_target::abi::VariantIdx; use rustc_target::asm::InlineAsmRegOrRegClass; @@ -540,13 +536,13 @@ pub enum BindingMode { ByRef(BorrowKind), } -#[derive(Clone, Debug, PartialEq, HashStable)] +#[derive(Clone, Debug, HashStable)] pub struct FieldPat<'tcx> { pub field: Field, pub pattern: Pat<'tcx>, } -#[derive(Clone, Debug, PartialEq, HashStable)] +#[derive(Clone, Debug, HashStable)] pub struct Pat<'tcx> { pub ty: Ty<'tcx>, pub span: Span, @@ -559,37 +555,10 @@ impl<'tcx> Pat<'tcx> { } } -#[derive(Copy, Clone, Debug, PartialEq, HashStable)] -pub struct PatTyProj<'tcx> { - pub user_ty: CanonicalUserType<'tcx>, -} - -impl<'tcx> PatTyProj<'tcx> { - pub fn from_user_type(user_annotation: CanonicalUserType<'tcx>) -> Self { - Self { user_ty: user_annotation } - } - - pub fn user_ty( - self, - annotations: &mut CanonicalUserTypeAnnotations<'tcx>, - inferred_ty: Ty<'tcx>, - span: Span, - ) -> UserTypeProjection { - UserTypeProjection { - base: annotations.push(CanonicalUserTypeAnnotation { - span, - user_ty: self.user_ty, - inferred_ty, - }), - projs: Vec::new(), - } - } -} - -#[derive(Copy, Clone, Debug, PartialEq, HashStable)] +#[derive(Clone, Debug, HashStable)] pub struct Ascription<'tcx> { - pub user_ty: PatTyProj<'tcx>, - /// Variance to use when relating the type `user_ty` to the **type of the value being + pub annotation: CanonicalUserTypeAnnotation<'tcx>, + /// Variance to use when relating the `user_ty` to the **type of the value being /// matched**. Typically, this is `Variance::Covariant`, since the value being matched must /// have a type that is some subtype of the ascribed type. /// @@ -608,12 +577,11 @@ pub struct Ascription<'tcx> { /// probably be checking for a `PartialEq` impl instead, but this preserves the behavior /// of the old type-check for now. See #57280 for details. pub variance: ty::Variance, - pub user_ty_span: Span, } -#[derive(Clone, Debug, PartialEq, HashStable)] +#[derive(Clone, Debug, HashStable)] pub enum PatKind<'tcx> { - /// A wildward pattern: `_`. + /// A wildcard pattern: `_`. Wild, AscribeUserType { @@ -662,7 +630,7 @@ pub enum PatKind<'tcx> { /// * Opaque constants, that must not be matched structurally. So anything that does not derive /// `PartialEq` and `Eq`. Constant { - value: ty::Const<'tcx>, + value: mir::ConstantKind<'tcx>, }, Range(PatRange<'tcx>), @@ -692,8 +660,8 @@ pub enum PatKind<'tcx> { #[derive(Copy, Clone, Debug, PartialEq, HashStable)] pub struct PatRange<'tcx> { - pub lo: ty::Const<'tcx>, - pub hi: ty::Const<'tcx>, + pub lo: mir::ConstantKind<'tcx>, + pub hi: mir::ConstantKind<'tcx>, pub end: RangeEnd, } diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 8c660e38a7fbe..4006b2fcf177a 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -61,6 +61,9 @@ pub enum Reveal { /// let x: <() as Assoc>::Output = true; /// } /// ``` + /// + /// We also do not reveal the hidden type of opaque types during + /// type-checking. UserFacing, /// At codegen time, all monomorphic projections will succeed. @@ -97,9 +100,7 @@ pub struct ObligationCause<'tcx> { /// information. pub body_id: hir::HirId, - /// `None` for `MISC_OBLIGATION_CAUSE_CODE` (a common case, occurs ~60% of - /// the time). `Some` otherwise. - code: Option>>, + code: InternedObligationCauseCode<'tcx>, } // This custom hash function speeds up hashing for `Obligation` deduplication @@ -114,8 +115,6 @@ impl Hash for ObligationCause<'_> { } } -const MISC_OBLIGATION_CAUSE_CODE: ObligationCauseCode<'static> = MiscObligation; - impl<'tcx> ObligationCause<'tcx> { #[inline] pub fn new( @@ -123,11 +122,7 @@ impl<'tcx> ObligationCause<'tcx> { body_id: hir::HirId, code: ObligationCauseCode<'tcx>, ) -> ObligationCause<'tcx> { - ObligationCause { - span, - body_id, - code: if code == MISC_OBLIGATION_CAUSE_CODE { None } else { Some(Lrc::new(code)) }, - } + ObligationCause { span, body_id, code: code.into() } } pub fn misc(span: Span, body_id: hir::HirId) -> ObligationCause<'tcx> { @@ -136,15 +131,12 @@ impl<'tcx> ObligationCause<'tcx> { #[inline(always)] pub fn dummy() -> ObligationCause<'tcx> { - ObligationCause { span: DUMMY_SP, body_id: hir::CRATE_HIR_ID, code: None } + ObligationCause::dummy_with_span(DUMMY_SP) } + #[inline(always)] pub fn dummy_with_span(span: Span) -> ObligationCause<'tcx> { - ObligationCause { span, body_id: hir::CRATE_HIR_ID, code: None } - } - - pub fn make_mut_code(&mut self) -> &mut ObligationCauseCode<'tcx> { - Lrc::make_mut(self.code.get_or_insert_with(|| Lrc::new(MISC_OBLIGATION_CAUSE_CODE))) + ObligationCause { span, body_id: hir::CRATE_HIR_ID, code: Default::default() } } pub fn span(&self, tcx: TyCtxt<'tcx>) -> Span { @@ -164,14 +156,37 @@ impl<'tcx> ObligationCause<'tcx> { #[inline] pub fn code(&self) -> &ObligationCauseCode<'tcx> { - self.code.as_deref().unwrap_or(&MISC_OBLIGATION_CAUSE_CODE) + &self.code } - pub fn clone_code(&self) -> Lrc> { - match &self.code { - Some(code) => code.clone(), - None => Lrc::new(MISC_OBLIGATION_CAUSE_CODE), - } + pub fn map_code( + &mut self, + f: impl FnOnce(InternedObligationCauseCode<'tcx>) -> ObligationCauseCode<'tcx>, + ) { + self.code = f(std::mem::take(&mut self.code)).into(); + } + + pub fn derived_cause( + mut self, + parent_trait_pred: ty::PolyTraitPredicate<'tcx>, + variant: impl FnOnce(DerivedObligationCause<'tcx>) -> ObligationCauseCode<'tcx>, + ) -> ObligationCause<'tcx> { + /*! + * Creates a cause for obligations that are derived from + * `obligation` by a recursive search (e.g., for a builtin + * bound, or eventually a `auto trait Foo`). If `obligation` + * is itself a derived obligation, this is just a clone, but + * otherwise we create a "derived obligation" cause so as to + * keep track of the original root obligation for error + * reporting. + */ + + // NOTE(flaper87): As of now, it keeps track of the whole error + // chain. Ideally, we should have a way to configure this either + // by using -Z verbose or just a CLI argument. + self.code = + variant(DerivedObligationCause { parent_trait_pred, parent_code: self.code }).into(); + self } } @@ -182,6 +197,34 @@ pub struct UnifyReceiverContext<'tcx> { pub substs: SubstsRef<'tcx>, } +#[derive(Clone, Debug, PartialEq, Eq, Hash, Lift, Default)] +pub struct InternedObligationCauseCode<'tcx> { + /// `None` for `ObligationCauseCode::MiscObligation` (a common case, occurs ~60% of + /// the time). `Some` otherwise. + code: Option>>, +} + +impl<'tcx> ObligationCauseCode<'tcx> { + #[inline(always)] + fn into(self) -> InternedObligationCauseCode<'tcx> { + InternedObligationCauseCode { + code: if let ObligationCauseCode::MiscObligation = self { + None + } else { + Some(Lrc::new(self)) + }, + } + } +} + +impl<'tcx> std::ops::Deref for InternedObligationCauseCode<'tcx> { + type Target = ObligationCauseCode<'tcx>; + + fn deref(&self) -> &Self::Target { + self.code.as_deref().unwrap_or(&ObligationCauseCode::MiscObligation) + } +} + #[derive(Clone, Debug, PartialEq, Eq, Hash, Lift)] pub enum ObligationCauseCode<'tcx> { /// Not well classified or should be obvious from the span. @@ -269,7 +312,7 @@ pub enum ObligationCauseCode<'tcx> { /// The node of the function call. call_hir_id: hir::HirId, /// The obligation introduced by this argument. - parent_code: Lrc>, + parent_code: InternedObligationCauseCode<'tcx>, }, /// Error derived when matching traits/impls; see ObligationCause for more details @@ -404,25 +447,27 @@ pub struct ImplDerivedObligationCause<'tcx> { pub span: Span, } -impl ObligationCauseCode<'_> { +impl<'tcx> ObligationCauseCode<'tcx> { // Return the base obligation, ignoring derived obligations. pub fn peel_derives(&self) -> &Self { let mut base_cause = self; - loop { - match base_cause { - BuiltinDerivedObligation(DerivedObligationCause { parent_code, .. }) - | DerivedObligation(DerivedObligationCause { parent_code, .. }) - | FunctionArgumentObligation { parent_code, .. } => { - base_cause = &parent_code; - } - ImplDerivedObligation(obligation_cause) => { - base_cause = &*obligation_cause.derived.parent_code; - } - _ => break, - } + while let Some((parent_code, _)) = base_cause.parent() { + base_cause = parent_code; } base_cause } + + pub fn parent(&self) -> Option<(&Self, Option>)> { + match self { + FunctionArgumentObligation { parent_code, .. } => Some((parent_code, None)), + BuiltinDerivedObligation(derived) + | DerivedObligation(derived) + | ImplDerivedObligation(box ImplDerivedObligationCause { derived, .. }) => { + Some((&derived.parent_code, Some(derived.parent_trait_pred))) + } + _ => None, + } + } } // `ObligationCauseCode` is used a lot. Make sure it doesn't unintentionally get bigger. @@ -472,7 +517,7 @@ pub struct DerivedObligationCause<'tcx> { pub parent_trait_pred: ty::PolyTraitPredicate<'tcx>, /// The parent trait had this cause. - pub parent_code: Lrc>, + pub parent_code: InternedObligationCauseCode<'tcx>, } #[derive(Clone, Debug, TypeFoldable, Lift)] diff --git a/compiler/rustc_middle/src/ty/assoc.rs b/compiler/rustc_middle/src/ty/assoc.rs index 49f846562a3cc..2c93af506679d 100644 --- a/compiler/rustc_middle/src/ty/assoc.rs +++ b/compiler/rustc_middle/src/ty/assoc.rs @@ -9,7 +9,7 @@ use rustc_span::symbol::{Ident, Symbol}; use super::{TyCtxt, Visibility}; -#[derive(Clone, Copy, PartialEq, Eq, Debug, HashStable, Hash)] +#[derive(Clone, Copy, PartialEq, Eq, Debug, HashStable, Hash, Encodable, Decodable)] pub enum AssocItemContainer { TraitContainer(DefId), ImplContainer(DefId), @@ -41,7 +41,7 @@ impl AssocItemContainer { } /// Information about an associated item -#[derive(Copy, Clone, Debug, PartialEq, HashStable, Eq, Hash)] +#[derive(Copy, Clone, Debug, PartialEq, HashStable, Eq, Hash, Encodable, Decodable)] pub struct AssocItem { pub def_id: DefId, pub name: Symbol, @@ -81,7 +81,7 @@ impl AssocItem { } } -#[derive(Copy, Clone, PartialEq, Debug, HashStable, Eq, Hash)] +#[derive(Copy, Clone, PartialEq, Debug, HashStable, Eq, Hash, Encodable, Decodable)] pub enum AssocKind { Const, Fn, diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs index 23c377651cc6c..1e2d1fbeb4bf6 100644 --- a/compiler/rustc_middle/src/ty/codec.rs +++ b/compiler/rustc_middle/src/ty/codec.rs @@ -15,10 +15,12 @@ use crate::mir::{ use crate::thir; use crate::traits; use crate::ty::subst::SubstsRef; -use crate::ty::{self, AdtDef, Ty, TyCtxt}; +use crate::ty::{self, AdtDef, Ty}; use rustc_data_structures::fx::FxHashMap; -use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; +use rustc_middle::ty::TyCtxt; +use rustc_serialize::{Decodable, Encodable}; use rustc_span::Span; +pub use rustc_type_ir::{TyDecoder, TyEncoder}; use std::hash::Hash; use std::intrinsics; use std::marker::DiscriminantKind; @@ -28,13 +30,13 @@ use std::marker::DiscriminantKind; /// This offset is also chosen so that the first byte is never < 0x80. pub const SHORTHAND_OFFSET: usize = 0x80; -pub trait EncodableWithShorthand<'tcx, E: TyEncoder<'tcx>>: Copy + Eq + Hash { +pub trait EncodableWithShorthand: Copy + Eq + Hash { type Variant: Encodable; fn variant(&self) -> &Self::Variant; } #[allow(rustc::usage_of_ty_tykind)] -impl<'tcx, E: TyEncoder<'tcx>> EncodableWithShorthand<'tcx, E> for Ty<'tcx> { +impl<'tcx, E: TyEncoder>> EncodableWithShorthand for Ty<'tcx> { type Variant = ty::TyKind<'tcx>; #[inline] @@ -43,7 +45,7 @@ impl<'tcx, E: TyEncoder<'tcx>> EncodableWithShorthand<'tcx, E> for Ty<'tcx> { } } -impl<'tcx, E: TyEncoder<'tcx>> EncodableWithShorthand<'tcx, E> for ty::PredicateKind<'tcx> { +impl<'tcx, E: TyEncoder>> EncodableWithShorthand for ty::PredicateKind<'tcx> { type Variant = ty::PredicateKind<'tcx>; #[inline] @@ -52,15 +54,6 @@ impl<'tcx, E: TyEncoder<'tcx>> EncodableWithShorthand<'tcx, E> for ty::Predicate } } -pub trait TyEncoder<'tcx>: Encoder { - const CLEAR_CROSS_CRATE: bool; - - fn position(&self) -> usize; - fn type_shorthands(&mut self) -> &mut FxHashMap, usize>; - fn predicate_shorthands(&mut self) -> &mut FxHashMap, usize>; - fn encode_alloc_id(&mut self, alloc_id: &AllocId) -> Result<(), Self::Error>; -} - /// Trait for decoding to a reference. /// /// This is a separate trait from `Decodable` so that we can implement it for @@ -71,7 +64,7 @@ pub trait TyEncoder<'tcx>: Encoder { /// /// `Decodable` can still be implemented in cases where `Decodable` is required /// by a trait bound. -pub trait RefDecodable<'tcx, D: TyDecoder<'tcx>> { +pub trait RefDecodable<'tcx, D: TyDecoder>> { fn decode(d: &mut D) -> &'tcx Self; } @@ -82,9 +75,9 @@ pub fn encode_with_shorthand<'tcx, E, T, M>( cache: M, ) -> Result<(), E::Error> where - E: TyEncoder<'tcx>, + E: TyEncoder>, M: for<'b> Fn(&'b mut E) -> &'b mut FxHashMap, - T: EncodableWithShorthand<'tcx, E>, + T: EncodableWithShorthand, // The discriminant and shorthand must have the same size. T::Variant: DiscriminantKind, { @@ -119,119 +112,86 @@ where Ok(()) } -impl<'tcx, E: TyEncoder<'tcx>> Encodable for Ty<'tcx> { +impl<'tcx, E: TyEncoder>> Encodable for Ty<'tcx> { fn encode(&self, e: &mut E) -> Result<(), E::Error> { encode_with_shorthand(e, self, TyEncoder::type_shorthands) } } -impl<'tcx, E: TyEncoder<'tcx>> Encodable for ty::Binder<'tcx, ty::PredicateKind<'tcx>> { +impl<'tcx, E: TyEncoder>> Encodable + for ty::Binder<'tcx, ty::PredicateKind<'tcx>> +{ fn encode(&self, e: &mut E) -> Result<(), E::Error> { self.bound_vars().encode(e)?; encode_with_shorthand(e, &self.skip_binder(), TyEncoder::predicate_shorthands) } } -impl<'tcx, E: TyEncoder<'tcx>> Encodable for ty::Predicate<'tcx> { +impl<'tcx, E: TyEncoder>> Encodable for ty::Predicate<'tcx> { fn encode(&self, e: &mut E) -> Result<(), E::Error> { self.kind().encode(e) } } -impl<'tcx, E: TyEncoder<'tcx>> Encodable for ty::Region<'tcx> { +impl<'tcx, E: TyEncoder>> Encodable for ty::Region<'tcx> { fn encode(&self, e: &mut E) -> Result<(), E::Error> { self.kind().encode(e) } } -impl<'tcx, E: TyEncoder<'tcx>> Encodable for ty::Const<'tcx> { +impl<'tcx, E: TyEncoder>> Encodable for ty::Const<'tcx> { fn encode(&self, e: &mut E) -> Result<(), E::Error> { self.0.0.encode(e) } } -impl<'tcx, E: TyEncoder<'tcx>> Encodable for ConstAllocation<'tcx> { +impl<'tcx, E: TyEncoder>> Encodable for ConstAllocation<'tcx> { fn encode(&self, e: &mut E) -> Result<(), E::Error> { self.inner().encode(e) } } -impl<'tcx, E: TyEncoder<'tcx>> Encodable for AdtDef<'tcx> { +impl<'tcx, E: TyEncoder>> Encodable for AdtDef<'tcx> { fn encode(&self, e: &mut E) -> Result<(), E::Error> { self.0.0.encode(e) } } -impl<'tcx, E: TyEncoder<'tcx>> Encodable for AllocId { +impl<'tcx, E: TyEncoder>> Encodable for AllocId { fn encode(&self, e: &mut E) -> Result<(), E::Error> { e.encode_alloc_id(self) } } -macro_rules! encodable_via_deref { - ($($t:ty),+) => { - $(impl<'tcx, E: TyEncoder<'tcx>> Encodable for $t { - fn encode(&self, e: &mut E) -> Result<(), E::Error> { - (**self).encode(e) - } - })* - } -} - -encodable_via_deref! { - &'tcx ty::TypeckResults<'tcx>, - &'tcx traits::ImplSource<'tcx, ()>, - &'tcx mir::Body<'tcx>, - &'tcx mir::UnsafetyCheckResult, - &'tcx mir::BorrowCheckResult<'tcx>, - &'tcx mir::coverage::CodeRegion -} - -pub trait TyDecoder<'tcx>: Decoder { - const CLEAR_CROSS_CRATE: bool; - - fn tcx(&self) -> TyCtxt<'tcx>; - - fn peek_byte(&self) -> u8; - - fn position(&self) -> usize; - - fn cached_ty_for_shorthand(&mut self, shorthand: usize, or_insert_with: F) -> Ty<'tcx> - where - F: FnOnce(&mut Self) -> Ty<'tcx>; - - fn with_position(&mut self, pos: usize, f: F) -> R - where - F: FnOnce(&mut Self) -> R; - - fn positioned_at_shorthand(&self) -> bool { - (self.peek_byte() & (SHORTHAND_OFFSET as u8)) != 0 - } - - fn decode_alloc_id(&mut self) -> AllocId; -} - #[inline] -fn decode_arena_allocable<'tcx, D, T: ArenaAllocatable<'tcx> + Decodable>( +fn decode_arena_allocable< + 'tcx, + D: TyDecoder>, + T: ArenaAllocatable<'tcx> + Decodable, +>( decoder: &mut D, ) -> &'tcx T where - D: TyDecoder<'tcx>, + D: TyDecoder, { - decoder.tcx().arena.alloc(Decodable::decode(decoder)) + decoder.interner().arena.alloc(Decodable::decode(decoder)) } #[inline] -fn decode_arena_allocable_slice<'tcx, D, T: ArenaAllocatable<'tcx> + Decodable>( +fn decode_arena_allocable_slice< + 'tcx, + D: TyDecoder>, + T: ArenaAllocatable<'tcx> + Decodable, +>( decoder: &mut D, ) -> &'tcx [T] where - D: TyDecoder<'tcx>, + D: TyDecoder, { - decoder.tcx().arena.alloc_from_iter( as Decodable>::decode(decoder)) + decoder.interner().arena.alloc_from_iter( as Decodable>::decode(decoder)) } -impl<'tcx, D: TyDecoder<'tcx>> Decodable for Ty<'tcx> { +impl<'tcx, D: TyDecoder>> Decodable for Ty<'tcx> { #[allow(rustc::usage_of_ty_tykind)] fn decode(decoder: &mut D) -> Ty<'tcx> { // Handle shorthands first, if we have a usize > 0x80. @@ -244,13 +204,15 @@ impl<'tcx, D: TyDecoder<'tcx>> Decodable for Ty<'tcx> { decoder.with_position(shorthand, Ty::decode) }) } else { - let tcx = decoder.tcx(); - tcx.mk_ty(ty::TyKind::decode(decoder)) + let tcx = decoder.interner(); + tcx.mk_ty(rustc_type_ir::TyKind::decode(decoder)) } } } -impl<'tcx, D: TyDecoder<'tcx>> Decodable for ty::Binder<'tcx, ty::PredicateKind<'tcx>> { +impl<'tcx, D: TyDecoder>> Decodable + for ty::Binder<'tcx, ty::PredicateKind<'tcx>> +{ fn decode(decoder: &mut D) -> ty::Binder<'tcx, ty::PredicateKind<'tcx>> { let bound_vars = Decodable::decode(decoder); // Handle shorthands first, if we have a usize > 0x80. @@ -269,64 +231,64 @@ impl<'tcx, D: TyDecoder<'tcx>> Decodable for ty::Binder<'tcx, ty::PredicateKi } } -impl<'tcx, D: TyDecoder<'tcx>> Decodable for ty::Predicate<'tcx> { +impl<'tcx, D: TyDecoder>> Decodable for ty::Predicate<'tcx> { fn decode(decoder: &mut D) -> ty::Predicate<'tcx> { let predicate_kind = Decodable::decode(decoder); - decoder.tcx().mk_predicate(predicate_kind) + decoder.interner().mk_predicate(predicate_kind) } } -impl<'tcx, D: TyDecoder<'tcx>> Decodable for SubstsRef<'tcx> { +impl<'tcx, D: TyDecoder>> Decodable for SubstsRef<'tcx> { fn decode(decoder: &mut D) -> Self { let len = decoder.read_usize(); - let tcx = decoder.tcx(); + let tcx = decoder.interner(); tcx.mk_substs( (0..len).map::, _>(|_| Decodable::decode(decoder)), ) } } -impl<'tcx, D: TyDecoder<'tcx>> Decodable for mir::Place<'tcx> { +impl<'tcx, D: TyDecoder>> Decodable for mir::Place<'tcx> { fn decode(decoder: &mut D) -> Self { let local: mir::Local = Decodable::decode(decoder); let len = decoder.read_usize(); - let projection = decoder.tcx().mk_place_elems( + let projection = decoder.interner().mk_place_elems( (0..len).map::, _>(|_| Decodable::decode(decoder)), ); mir::Place { local, projection } } } -impl<'tcx, D: TyDecoder<'tcx>> Decodable for ty::Region<'tcx> { +impl<'tcx, D: TyDecoder>> Decodable for ty::Region<'tcx> { fn decode(decoder: &mut D) -> Self { - decoder.tcx().mk_region(Decodable::decode(decoder)) + decoder.interner().mk_region(Decodable::decode(decoder)) } } -impl<'tcx, D: TyDecoder<'tcx>> Decodable for CanonicalVarInfos<'tcx> { +impl<'tcx, D: TyDecoder>> Decodable for CanonicalVarInfos<'tcx> { fn decode(decoder: &mut D) -> Self { let len = decoder.read_usize(); let interned: Vec> = (0..len).map(|_| Decodable::decode(decoder)).collect(); - decoder.tcx().intern_canonical_var_infos(interned.as_slice()) + decoder.interner().intern_canonical_var_infos(interned.as_slice()) } } -impl<'tcx, D: TyDecoder<'tcx>> Decodable for AllocId { +impl<'tcx, D: TyDecoder>> Decodable for AllocId { fn decode(decoder: &mut D) -> Self { decoder.decode_alloc_id() } } -impl<'tcx, D: TyDecoder<'tcx>> Decodable for ty::SymbolName<'tcx> { +impl<'tcx, D: TyDecoder>> Decodable for ty::SymbolName<'tcx> { fn decode(decoder: &mut D) -> Self { - ty::SymbolName::new(decoder.tcx(), &decoder.read_str()) + ty::SymbolName::new(decoder.interner(), &decoder.read_str()) } } macro_rules! impl_decodable_via_ref { ($($t:ty),+) => { - $(impl<'tcx, D: TyDecoder<'tcx>> Decodable for $t { + $(impl<'tcx, D: TyDecoder>> Decodable for $t { fn decode(decoder: &mut D) -> Self { RefDecodable::decode(decoder) } @@ -334,78 +296,86 @@ macro_rules! impl_decodable_via_ref { } } -impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for ty::List> { +impl<'tcx, D: TyDecoder>> RefDecodable<'tcx, D> for ty::List> { fn decode(decoder: &mut D) -> &'tcx Self { let len = decoder.read_usize(); - decoder.tcx().mk_type_list((0..len).map::, _>(|_| Decodable::decode(decoder))) + decoder.interner().mk_type_list((0..len).map::, _>(|_| Decodable::decode(decoder))) } } -impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> +impl<'tcx, D: TyDecoder>> RefDecodable<'tcx, D> for ty::List>> { fn decode(decoder: &mut D) -> &'tcx Self { let len = decoder.read_usize(); - decoder.tcx().mk_poly_existential_predicates( + decoder.interner().mk_poly_existential_predicates( (0..len).map::, _>(|_| Decodable::decode(decoder)), ) } } -impl<'tcx, D: TyDecoder<'tcx>> Decodable for ty::Const<'tcx> { +impl<'tcx, D: TyDecoder>> Decodable for ty::Const<'tcx> { fn decode(decoder: &mut D) -> Self { - decoder.tcx().mk_const(Decodable::decode(decoder)) + decoder.interner().mk_const(Decodable::decode(decoder)) } } -impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [ty::ValTree<'tcx>] { +impl<'tcx, D: TyDecoder>> RefDecodable<'tcx, D> for [ty::ValTree<'tcx>] { fn decode(decoder: &mut D) -> &'tcx Self { - decoder.tcx().arena.alloc_from_iter( + decoder.interner().arena.alloc_from_iter( (0..decoder.read_usize()).map(|_| Decodable::decode(decoder)).collect::>(), ) } } -impl<'tcx, D: TyDecoder<'tcx>> Decodable for ConstAllocation<'tcx> { +impl<'tcx, D: TyDecoder>> Decodable for ConstAllocation<'tcx> { fn decode(decoder: &mut D) -> Self { - decoder.tcx().intern_const_alloc(Decodable::decode(decoder)) + decoder.interner().intern_const_alloc(Decodable::decode(decoder)) } } -impl<'tcx, D: TyDecoder<'tcx>> Decodable for AdtDef<'tcx> { +impl<'tcx, D: TyDecoder>> Decodable for AdtDef<'tcx> { fn decode(decoder: &mut D) -> Self { - decoder.tcx().intern_adt_def(Decodable::decode(decoder)) + decoder.interner().intern_adt_def(Decodable::decode(decoder)) } } -impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [(ty::Predicate<'tcx>, Span)] { +impl<'tcx, D: TyDecoder>> RefDecodable<'tcx, D> + for [(ty::Predicate<'tcx>, Span)] +{ fn decode(decoder: &mut D) -> &'tcx Self { - decoder.tcx().arena.alloc_from_iter( + decoder.interner().arena.alloc_from_iter( (0..decoder.read_usize()).map(|_| Decodable::decode(decoder)).collect::>(), ) } } -impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [thir::abstract_const::Node<'tcx>] { +impl<'tcx, D: TyDecoder>> RefDecodable<'tcx, D> + for [thir::abstract_const::Node<'tcx>] +{ fn decode(decoder: &mut D) -> &'tcx Self { - decoder.tcx().arena.alloc_from_iter( + decoder.interner().arena.alloc_from_iter( (0..decoder.read_usize()).map(|_| Decodable::decode(decoder)).collect::>(), ) } } -impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [thir::abstract_const::NodeId] { +impl<'tcx, D: TyDecoder>> RefDecodable<'tcx, D> + for [thir::abstract_const::NodeId] +{ fn decode(decoder: &mut D) -> &'tcx Self { - decoder.tcx().arena.alloc_from_iter( + decoder.interner().arena.alloc_from_iter( (0..decoder.read_usize()).map(|_| Decodable::decode(decoder)).collect::>(), ) } } -impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for ty::List { +impl<'tcx, D: TyDecoder>> RefDecodable<'tcx, D> + for ty::List +{ fn decode(decoder: &mut D) -> &'tcx Self { let len = decoder.read_usize(); - decoder.tcx().mk_bound_variable_kinds( + decoder.interner().mk_bound_variable_kinds( (0..len).map::(|_| Decodable::decode(decoder)), ) } @@ -439,14 +409,14 @@ macro_rules! impl_arena_allocatable_decoder { ([]$args:tt) => {}; ([decode $(, $attrs:ident)*] [$name:ident: $ty:ty]) => { - impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for $ty { + impl<'tcx, D: TyDecoder>> RefDecodable<'tcx, D> for $ty { #[inline] fn decode(decoder: &mut D) -> &'tcx Self { decode_arena_allocable(decoder) } } - impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [$ty] { + impl<'tcx, D: TyDecoder>> RefDecodable<'tcx, D> for [$ty] { #[inline] fn decode(decoder: &mut D) -> &'tcx Self { decode_arena_allocable_slice(decoder) @@ -466,6 +436,33 @@ macro_rules! impl_arena_allocatable_decoders { rustc_hir::arena_types!(impl_arena_allocatable_decoders); arena_types!(impl_arena_allocatable_decoders); +macro_rules! impl_arena_copy_decoder { + (<$tcx:tt> $($ty:ty,)*) => { + $(impl<'tcx, D: TyDecoder>> RefDecodable<'tcx, D> for $ty { + #[inline] + fn decode(decoder: &mut D) -> &'tcx Self { + decoder.interner().arena.alloc(Decodable::decode(decoder)) + } + } + + impl<'tcx, D: TyDecoder>> RefDecodable<'tcx, D> for [$ty] { + #[inline] + fn decode(decoder: &mut D) -> &'tcx Self { + decoder.interner().arena.alloc_from_iter( as Decodable>::decode(decoder)) + } + })* + }; +} + +impl_arena_copy_decoder! {<'tcx> + Span, + rustc_span::symbol::Ident, + ty::Variance, + rustc_span::def_id::DefId, + rustc_span::def_id::LocalDefId, + (rustc_middle::middle::exported_symbols::ExportedSymbol<'tcx>, rustc_middle::middle::exported_symbols::SymbolExportInfo), +} + #[macro_export] macro_rules! implement_ty_decoder { ($DecoderName:ident <$($typaram:tt),*>) => { @@ -510,13 +507,13 @@ macro_rules! implement_ty_decoder { macro_rules! impl_binder_encode_decode { ($($t:ty),+ $(,)?) => { $( - impl<'tcx, E: TyEncoder<'tcx>> Encodable for ty::Binder<'tcx, $t> { + impl<'tcx, E: TyEncoder>> Encodable for ty::Binder<'tcx, $t> { fn encode(&self, e: &mut E) -> Result<(), E::Error> { self.bound_vars().encode(e)?; self.as_ref().skip_binder().encode(e) } } - impl<'tcx, D: TyDecoder<'tcx>> Decodable for ty::Binder<'tcx, $t> { + impl<'tcx, D: TyDecoder>> Decodable for ty::Binder<'tcx, $t> { fn decode(decoder: &mut D) -> Self { let bound_vars = Decodable::decode(decoder); ty::Binder::bind_with_vars(Decodable::decode(decoder), bound_vars) diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 1616b753433a8..a0d92e2a5dd94 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -16,7 +16,6 @@ use crate::thir::Thir; use crate::traits; use crate::ty::query::{self, TyCtxtAt}; use crate::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst, SubstsRef, UserSubsts}; -use crate::ty::TyKind::*; use crate::ty::{ self, AdtDef, AdtDefData, AdtKind, Binder, BindingMode, BoundVar, CanonicalPolyFnSig, ClosureSizeProfileData, Const, ConstS, ConstVid, DefIdTree, ExistentialPredicate, FloatTy, @@ -60,9 +59,9 @@ use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi::{Layout, LayoutS, TargetDataLayout, VariantIdx}; use rustc_target::spec::abi; +use rustc_type_ir::sty::TyKind::*; +use rustc_type_ir::{InternAs, InternIteratorElement, Interner, TypeFlags}; -use rustc_type_ir::TypeFlags; -use smallvec::SmallVec; use std::any::Any; use std::borrow::Borrow; use std::cmp::Ordering; @@ -74,6 +73,8 @@ use std::mem; use std::ops::{Bound, Deref}; use std::sync::Arc; +use super::RvalueScopes; + pub trait OnDiskCache<'tcx>: rustc_data_structures::sync::Sync { /// Creates a new `OnDiskCache` instance from the serialized data in `data`. fn new(sess: &'tcx Session, data: Mmap, start_pos: usize) -> Self @@ -89,6 +90,31 @@ pub trait OnDiskCache<'tcx>: rustc_data_structures::sync::Sync { fn serialize(&self, tcx: TyCtxt<'tcx>, encoder: &mut FileEncoder) -> FileEncodeResult; } +#[allow(rustc::usage_of_ty_tykind)] +impl<'tcx> Interner for TyCtxt<'tcx> { + type AdtDef = ty::AdtDef<'tcx>; + type SubstsRef = ty::SubstsRef<'tcx>; + type DefId = DefId; + type Ty = Ty<'tcx>; + type Const = ty::Const<'tcx>; + type Region = Region<'tcx>; + type TypeAndMut = TypeAndMut<'tcx>; + type Mutability = hir::Mutability; + type Movability = hir::Movability; + type PolyFnSig = PolyFnSig<'tcx>; + type ListBinderExistentialPredicate = &'tcx List>>; + type BinderListTy = Binder<'tcx, &'tcx List>>; + type ListTy = &'tcx List>; + type ProjectionTy = ty::ProjectionTy<'tcx>; + type ParamTy = ParamTy; + type BoundTy = ty::BoundTy; + type PlaceholderType = ty::PlaceholderType; + type InferTy = InferTy; + type DelaySpanBugEmitted = DelaySpanBugEmitted; + type PredicateKind = ty::PredicateKind<'tcx>; + type AllocId = crate::mir::interpret::AllocId; +} + /// A type that is not publicly constructable. This prevents people from making [`TyKind::Error`]s /// except through the error-reporting functions on a [`tcx`][TyCtxt]. #[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)] @@ -535,6 +561,11 @@ pub struct TypeckResults<'tcx> { /// issue by fake reading `t`. pub closure_fake_reads: FxHashMap, FakeReadCause, hir::HirId)>>, + /// Tracks the rvalue scoping rules which defines finer scoping for rvalue expressions + /// by applying extended parameter rules. + /// Details may be find in `rustc_typeck::check::rvalue_scopes`. + pub rvalue_scopes: RvalueScopes, + /// Stores the type, expression, span and optional scope span of all types /// that are live across the yield of this generator (if a generator). pub generator_interior_types: ty::Binder<'tcx, Vec>>, @@ -572,6 +603,7 @@ impl<'tcx> TypeckResults<'tcx> { concrete_opaque_types: Default::default(), closure_min_captures: Default::default(), closure_fake_reads: Default::default(), + rvalue_scopes: Default::default(), generator_interior_types: ty::Binder::dummy(Default::default()), treat_byte_string_as_slice: Default::default(), closure_size_eval: Default::default(), @@ -1230,7 +1262,7 @@ impl<'tcx> TyCtxt<'tcx> { } } - crate fn query_kind(self, k: DepKind) -> &'tcx DepKindStruct { + pub(crate) fn query_kind(self, k: DepKind) -> &'tcx DepKindStruct { &self.query_kinds[k as usize] } @@ -1669,7 +1701,7 @@ macro_rules! nop_lift { impl<'a, 'tcx> Lift<'tcx> for $ty { type Lifted = $lifted; fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option { - if tcx.interners.$set.contains_pointer_to(&InternedInSet(self.0.0)) { + if tcx.interners.$set.contains_pointer_to(&InternedInSet(&*self.0.0)) { // SAFETY: `self` is interned and therefore valid // for the entire lifetime of the `TyCtxt`. Some(unsafe { mem::transmute(self) }) @@ -2791,7 +2823,7 @@ impl<'tcx> TyCtxt<'tcx> { pub fn is_const_fn(self, def_id: DefId) -> bool { if self.is_const_fn_raw(def_id) { match self.lookup_const_stability(def_id) { - Some(stability) if stability.level.is_unstable() => { + Some(stability) if stability.is_const_unstable() => { // has a `rustc_const_unstable` attribute, check whether the user enabled the // corresponding feature gate. self.features() @@ -2808,6 +2840,21 @@ impl<'tcx> TyCtxt<'tcx> { false } } + + /// Whether the trait impl is marked const. This does not consider stability or feature gates. + pub fn is_const_trait_impl_raw(self, def_id: DefId) -> bool { + let Some(local_def_id) = def_id.as_local() else { return false }; + let hir_id = self.local_def_id_to_hir_id(local_def_id); + let node = self.hir().get(hir_id); + + matches!( + node, + hir::Node::Item(hir::Item { + kind: hir::ItemKind::Impl(hir::Impl { constness: hir::Constness::Const, .. }), + .. + }) + ) + } } impl<'tcx> TyCtxtAt<'tcx> { @@ -2825,108 +2872,6 @@ impl<'tcx> TyCtxtAt<'tcx> { } } -pub trait InternAs { - type Output; - fn intern_with(self, f: F) -> Self::Output - where - F: FnOnce(&T) -> R; -} - -impl InternAs<[T], R> for I -where - E: InternIteratorElement, - I: Iterator, -{ - type Output = E::Output; - fn intern_with(self, f: F) -> Self::Output - where - F: FnOnce(&[T]) -> R, - { - E::intern_with(self, f) - } -} - -pub trait InternIteratorElement: Sized { - type Output; - fn intern_with, F: FnOnce(&[T]) -> R>(iter: I, f: F) -> Self::Output; -} - -impl InternIteratorElement for T { - type Output = R; - fn intern_with, F: FnOnce(&[T]) -> R>( - mut iter: I, - f: F, - ) -> Self::Output { - // This code is hot enough that it's worth specializing for the most - // common length lists, to avoid the overhead of `SmallVec` creation. - // Lengths 0, 1, and 2 typically account for ~95% of cases. If - // `size_hint` is incorrect a panic will occur via an `unwrap` or an - // `assert`. - match iter.size_hint() { - (0, Some(0)) => { - assert!(iter.next().is_none()); - f(&[]) - } - (1, Some(1)) => { - let t0 = iter.next().unwrap(); - assert!(iter.next().is_none()); - f(&[t0]) - } - (2, Some(2)) => { - let t0 = iter.next().unwrap(); - let t1 = iter.next().unwrap(); - assert!(iter.next().is_none()); - f(&[t0, t1]) - } - _ => f(&iter.collect::>()), - } - } -} - -impl<'a, T, R> InternIteratorElement for &'a T -where - T: Clone + 'a, -{ - type Output = R; - fn intern_with, F: FnOnce(&[T]) -> R>(iter: I, f: F) -> Self::Output { - // This code isn't hot. - f(&iter.cloned().collect::>()) - } -} - -impl InternIteratorElement for Result { - type Output = Result; - fn intern_with, F: FnOnce(&[T]) -> R>( - mut iter: I, - f: F, - ) -> Self::Output { - // This code is hot enough that it's worth specializing for the most - // common length lists, to avoid the overhead of `SmallVec` creation. - // Lengths 0, 1, and 2 typically account for ~95% of cases. If - // `size_hint` is incorrect a panic will occur via an `unwrap` or an - // `assert`, unless a failure happens first, in which case the result - // will be an error anyway. - Ok(match iter.size_hint() { - (0, Some(0)) => { - assert!(iter.next().is_none()); - f(&[]) - } - (1, Some(1)) => { - let t0 = iter.next().unwrap()?; - assert!(iter.next().is_none()); - f(&[t0]) - } - (2, Some(2)) => { - let t0 = iter.next().unwrap()?; - let t1 = iter.next().unwrap()?; - assert!(iter.next().is_none()); - f(&[t0, t1]) - } - _ => f(&iter.collect::, _>>()?), - }) - } -} - // We are comparing types with different invariant lifetimes, so `ptr::eq` // won't work for us. fn ptr_eq(t: *const T, u: *const U) -> bool { diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index a671774697919..462fc27009de9 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -1,7 +1,6 @@ //! Diagnostics related methods for `Ty`. use crate::ty::subst::{GenericArg, GenericArgKind}; -use crate::ty::TyKind::*; use crate::ty::{ ConstKind, DefIdTree, ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, InferTy, ProjectionTy, Term, Ty, TyCtxt, TypeAndMut, @@ -13,6 +12,7 @@ use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::WherePredicate; use rustc_span::Span; +use rustc_type_ir::sty::TyKind::*; impl<'tcx> IntoDiagnosticArg for Ty<'tcx> { fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs index a0fe632f11a07..a6c14ea0de343 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -135,11 +135,10 @@ impl<'tcx> fmt::Display for TypeError<'tcx> { ArgCount => write!(f, "incorrect number of function parameters"), FieldMisMatch(adt, field) => write!(f, "field type mismatch: {}.{}", adt, field), RegionsDoesNotOutlive(..) => write!(f, "lifetime mismatch"), - RegionsInsufficientlyPolymorphic(br, _) => write!( - f, - "expected bound lifetime parameter{}, found concrete lifetime", - br_string(br) - ), + // Actually naming the region here is a bit confusing because context is lacking + RegionsInsufficientlyPolymorphic(..) => { + write!(f, "one type is more general than the other") + } RegionsOverlyPolymorphic(br, _) => write!( f, "expected concrete lifetime, found bound lifetime parameter{}", diff --git a/compiler/rustc_middle/src/ty/fast_reject.rs b/compiler/rustc_middle/src/ty/fast_reject.rs index 9c018dc685c46..208cd9ba16a08 100644 --- a/compiler/rustc_middle/src/ty/fast_reject.rs +++ b/compiler/rustc_middle/src/ty/fast_reject.rs @@ -1,11 +1,10 @@ use crate::mir::Mutability; -use crate::ty::{self, Ty, TyCtxt}; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; +use crate::ty::subst::GenericArgKind; +use crate::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc_hir::def_id::DefId; -use rustc_query_system::ich::StableHashingContext; use std::fmt::Debug; use std::hash::Hash; -use std::mem; +use std::iter; use self::SimplifiedTypeGen::*; @@ -17,7 +16,7 @@ pub type SimplifiedType = SimplifiedTypeGen; /// because we sometimes need to use SimplifiedTypeGen values as stable sorting /// keys (in which case we use a DefPathHash as id-type) but in the general case /// the non-stable but fast to construct DefId-version is the better choice. -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)] pub enum SimplifiedTypeGen where D: Copy + Debug + Eq, @@ -45,34 +44,53 @@ where GeneratorWitnessSimplifiedType(usize), OpaqueSimplifiedType(D), FunctionSimplifiedType(usize), - ParameterSimplifiedType, + PlaceholderSimplifiedType, } +/// Generic parameters are pretty much just bound variables, e.g. +/// the type of `fn foo<'a, T>(x: &'a T) -> u32 { ... }` can be thought of as +/// `for<'a, T> fn(&'a T) -> u32`. +/// +/// Typecheck of `foo` has to succeed for all possible generic arguments, so +/// during typeck, we have to treat its generic parameters as if they +/// were placeholders. +/// +/// But when calling `foo` we only have to provide a specific generic argument. +/// In that case the generic parameters are instantiated with inference variables. +/// As we use `simplify_type` before that instantiation happens, we just treat +/// generic parameters as if they were inference variables in that case. #[derive(PartialEq, Eq, Debug, Clone, Copy)] pub enum TreatParams { - /// Treat parameters as bound types in the given environment. + /// Treat parameters as placeholders in the given environment. /// - /// For this to be correct the input has to be fully normalized - /// in its param env as it may otherwise cause us to ignore - /// potentially applying impls. - AsBoundTypes, - AsPlaceholders, + /// Note that this also causes us to treat projections as if they were + /// placeholders. This is only correct if the given projection cannot + /// be normalized in the current context. Even if normalization fails, + /// it may still succeed later if the projection contains any inference + /// variables. + AsPlaceholder, + AsInfer, } /// Tries to simplify a type by only returning the outermost injective¹ layer, if one exists. /// +/// **This function should only be used if you need to store or retrieve the type from some +/// hashmap. If you want to quickly decide whether two types may unify, use the [DeepRejectCtxt] +/// instead.** +/// /// The idea is to get something simple that we can use to quickly decide if two types could unify, -/// for example during method lookup. +/// for example during method lookup. If this function returns `Some(x)` it can only unify with +/// types for which this method returns either `Some(x)` as well or `None`. /// /// A special case here are parameters and projections, which are only injective -/// if they are treated as bound types. +/// if they are treated as placeholders. /// /// For example when storing impls based on their simplified self type, we treat -/// generic parameters as placeholders. We must not simplify them here, +/// generic parameters as if they were inference variables. We must not simplify them here, /// as they can unify with any other type. /// -/// With projections we have to be even more careful, as even when treating them as bound types -/// this is still only correct if they are fully normalized. +/// With projections we have to be even more careful, as treating them as placeholders +/// is only correct if they are fully normalized. /// /// ¹ meaning that if the outermost layers are different, then the whole types are also different. pub fn simplify_type<'tcx>( @@ -104,20 +122,25 @@ pub fn simplify_type<'tcx>( ty::Never => Some(NeverSimplifiedType), ty::Tuple(tys) => Some(TupleSimplifiedType(tys.len())), ty::FnPtr(f) => Some(FunctionSimplifiedType(f.skip_binder().inputs().len())), - ty::Param(_) | ty::Projection(_) => match treat_params { - // When treated as bound types, projections don't unify with - // anything as long as they are fully normalized. + ty::Placeholder(..) => Some(PlaceholderSimplifiedType), + ty::Param(_) => match treat_params { + TreatParams::AsPlaceholder => Some(PlaceholderSimplifiedType), + TreatParams::AsInfer => None, + }, + ty::Projection(_) => match treat_params { + // When treating `ty::Param` as a placeholder, projections also + // don't unify with anything else as long as they are fully normalized. // // We will have to be careful with lazy normalization here. - TreatParams::AsBoundTypes => { - debug!("treating `{}` as a bound type", ty); - Some(ParameterSimplifiedType) + TreatParams::AsPlaceholder if !ty.has_infer_types_or_consts() => { + debug!("treating `{}` as a placeholder", ty); + Some(PlaceholderSimplifiedType) } - TreatParams::AsPlaceholders => None, + TreatParams::AsPlaceholder | TreatParams::AsInfer => None, }, ty::Opaque(def_id, _) => Some(OpaqueSimplifiedType(def_id)), ty::Foreign(def_id) => Some(ForeignSimplifiedType(def_id)), - ty::Placeholder(..) | ty::Bound(..) | ty::Infer(_) | ty::Error(_) => None, + ty::Bound(..) | ty::Infer(_) | ty::Error(_) => None, } } @@ -161,41 +184,222 @@ impl SimplifiedTypeGen { GeneratorWitnessSimplifiedType(n) => GeneratorWitnessSimplifiedType(n), OpaqueSimplifiedType(d) => OpaqueSimplifiedType(map(d)), FunctionSimplifiedType(n) => FunctionSimplifiedType(n), - ParameterSimplifiedType => ParameterSimplifiedType, + PlaceholderSimplifiedType => PlaceholderSimplifiedType, } } } -impl<'a, D> HashStable> for SimplifiedTypeGen -where - D: Copy + Debug + Eq + HashStable>, -{ - fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - mem::discriminant(self).hash_stable(hcx, hasher); - match *self { - BoolSimplifiedType - | CharSimplifiedType - | StrSimplifiedType - | ArraySimplifiedType - | SliceSimplifiedType - | NeverSimplifiedType - | ParameterSimplifiedType - | MarkerTraitObjectSimplifiedType => { - // nothing to do +/// Given generic arguments from an obligation and an impl, +/// could these two be unified after replacing parameters in the +/// the impl with inference variables. +/// +/// For obligations, parameters won't be replaced by inference +/// variables and only unify with themselves. We treat them +/// the same way we treat placeholders. +/// +/// We also use this function during coherence. For coherence the +/// impls only have to overlap for some value, so we treat parameters +/// on both sides like inference variables. This behavior is toggled +/// using the `treat_obligation_params` field. +#[derive(Debug, Clone, Copy)] +pub struct DeepRejectCtxt { + pub treat_obligation_params: TreatParams, +} + +impl DeepRejectCtxt { + pub fn generic_args_may_unify<'tcx>( + self, + obligation_arg: ty::GenericArg<'tcx>, + impl_arg: ty::GenericArg<'tcx>, + ) -> bool { + match (obligation_arg.unpack(), impl_arg.unpack()) { + // We don't fast reject based on regions for now. + (GenericArgKind::Lifetime(_), GenericArgKind::Lifetime(_)) => true, + (GenericArgKind::Type(obl), GenericArgKind::Type(imp)) => { + self.types_may_unify(obl, imp) + } + (GenericArgKind::Const(obl), GenericArgKind::Const(imp)) => { + self.consts_may_unify(obl, imp) + } + _ => bug!("kind mismatch: {obligation_arg} {impl_arg}"), + } + } + + pub fn types_may_unify<'tcx>(self, obligation_ty: Ty<'tcx>, impl_ty: Ty<'tcx>) -> bool { + match impl_ty.kind() { + // Start by checking whether the type in the impl may unify with + // pretty much everything. Just return `true` in that case. + ty::Param(_) | ty::Projection(_) | ty::Error(_) => return true, + // These types only unify with inference variables or their own + // variant. + ty::Bool + | ty::Char + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Adt(..) + | ty::Str + | ty::Array(..) + | ty::Slice(..) + | ty::RawPtr(..) + | ty::Dynamic(..) + | ty::Ref(..) + | ty::Never + | ty::Tuple(..) + | ty::FnPtr(..) + | ty::Foreign(..) + | ty::Opaque(..) => {} + ty::FnDef(..) + | ty::Closure(..) + | ty::Generator(..) + | ty::GeneratorWitness(..) + | ty::Placeholder(..) + | ty::Bound(..) + | ty::Infer(_) => bug!("unexpected impl_ty: {impl_ty}"), + } + + let k = impl_ty.kind(); + match *obligation_ty.kind() { + // Purely rigid types, use structural equivalence. + ty::Bool + | ty::Char + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Str + | ty::Never + | ty::Foreign(_) => obligation_ty == impl_ty, + ty::Ref(_, obl_ty, obl_mutbl) => match k { + &ty::Ref(_, impl_ty, impl_mutbl) => { + obl_mutbl == impl_mutbl && self.types_may_unify(obl_ty, impl_ty) + } + _ => false, + }, + ty::Adt(obl_def, obl_substs) => match k { + &ty::Adt(impl_def, impl_substs) => { + obl_def == impl_def + && iter::zip(obl_substs, impl_substs) + .all(|(obl, imp)| self.generic_args_may_unify(obl, imp)) + } + _ => false, + }, + ty::Slice(obl_ty) => { + matches!(k, &ty::Slice(impl_ty) if self.types_may_unify(obl_ty, impl_ty)) + } + ty::Array(obl_ty, obl_len) => match k { + &ty::Array(impl_ty, impl_len) => { + self.types_may_unify(obl_ty, impl_ty) + && self.consts_may_unify(obl_len, impl_len) + } + _ => false, + }, + ty::Tuple(obl) => match k { + &ty::Tuple(imp) => { + obl.len() == imp.len() + && iter::zip(obl, imp).all(|(obl, imp)| self.types_may_unify(obl, imp)) + } + _ => false, + }, + ty::RawPtr(obl) => match k { + ty::RawPtr(imp) => obl.mutbl == imp.mutbl && self.types_may_unify(obl.ty, imp.ty), + _ => false, + }, + ty::Dynamic(obl_preds, ..) => { + // Ideally we would walk the existential predicates here or at least + // compare their length. But considering that the relevant `Relate` impl + // actually sorts and deduplicates these, that doesn't work. + matches!(k, ty::Dynamic(impl_preds, ..) if + obl_preds.principal_def_id() == impl_preds.principal_def_id() + ) + } + ty::FnPtr(obl_sig) => match k { + ty::FnPtr(impl_sig) => { + let ty::FnSig { inputs_and_output, c_variadic, unsafety, abi } = + obl_sig.skip_binder(); + let impl_sig = impl_sig.skip_binder(); + + abi == impl_sig.abi + && c_variadic == impl_sig.c_variadic + && unsafety == impl_sig.unsafety + && inputs_and_output.len() == impl_sig.inputs_and_output.len() + && iter::zip(inputs_and_output, impl_sig.inputs_and_output) + .all(|(obl, imp)| self.types_may_unify(obl, imp)) + } + _ => false, + }, + + // Opaque types in impls should be forbidden, but that doesn't + // stop compilation. So this match arm should never return true + // if compilation succeeds. + ty::Opaque(..) => matches!(k, ty::Opaque(..)), + + // Impls cannot contain these types as these cannot be named directly. + ty::FnDef(..) | ty::Closure(..) | ty::Generator(..) => false, + + ty::Placeholder(..) => false, + + // Depending on the value of `treat_obligation_params`, we either + // treat generic parameters like placeholders or like inference variables. + ty::Param(_) => match self.treat_obligation_params { + TreatParams::AsPlaceholder => false, + TreatParams::AsInfer => true, + }, + + ty::Infer(_) => true, + + // As we're walking the whole type, it may encounter projections + // inside of binders and what not, so we're just going to assume that + // projections can unify with other stuff. + // + // Looking forward to lazy normalization this is the safer strategy anyways. + ty::Projection(_) => true, + + ty::Error(_) => true, + + ty::GeneratorWitness(..) | ty::Bound(..) => { + bug!("unexpected obligation type: {:?}", obligation_ty) + } + } + } + + pub fn consts_may_unify(self, obligation_ct: ty::Const<'_>, impl_ct: ty::Const<'_>) -> bool { + match impl_ct.val() { + ty::ConstKind::Param(_) | ty::ConstKind::Unevaluated(_) | ty::ConstKind::Error(_) => { + return true; + } + ty::ConstKind::Value(_) => {} + ty::ConstKind::Infer(_) | ty::ConstKind::Bound(..) | ty::ConstKind::Placeholder(_) => { + bug!("unexpected impl arg: {:?}", impl_ct) + } + } + + let k = impl_ct.val(); + match obligation_ct.val() { + ty::ConstKind::Param(_) => match self.treat_obligation_params { + TreatParams::AsPlaceholder => false, + TreatParams::AsInfer => true, + }, + + // As we don't necessarily eagerly evaluate constants, + // they might unify with any value. + ty::ConstKind::Unevaluated(_) | ty::ConstKind::Error(_) => true, + ty::ConstKind::Value(obl) => match k { + ty::ConstKind::Value(imp) => { + // FIXME(valtrees): Once we have valtrees, we can just + // compare them directly here. + match (obl.try_to_scalar_int(), imp.try_to_scalar_int()) { + (Some(obl), Some(imp)) => obl == imp, + _ => true, + } + } + _ => true, + }, + + ty::ConstKind::Infer(_) => true, + + ty::ConstKind::Bound(..) | ty::ConstKind::Placeholder(_) => { + bug!("unexpected obl const: {:?}", obligation_ct) } - RefSimplifiedType(m) | PtrSimplifiedType(m) => m.hash_stable(hcx, hasher), - IntSimplifiedType(t) => t.hash_stable(hcx, hasher), - UintSimplifiedType(t) => t.hash_stable(hcx, hasher), - FloatSimplifiedType(t) => t.hash_stable(hcx, hasher), - AdtSimplifiedType(d) => d.hash_stable(hcx, hasher), - TupleSimplifiedType(n) => n.hash_stable(hcx, hasher), - TraitSimplifiedType(d) => d.hash_stable(hcx, hasher), - ClosureSimplifiedType(d) => d.hash_stable(hcx, hasher), - GeneratorSimplifiedType(d) => d.hash_stable(hcx, hasher), - GeneratorWitnessSimplifiedType(n) => n.hash_stable(hcx, hasher), - OpaqueSimplifiedType(d) => d.hash_stable(hcx, hasher), - FunctionSimplifiedType(n) => n.hash_stable(hcx, hasher), - ForeignSimplifiedType(d) => d.hash_stable(hcx, hasher), } } } diff --git a/compiler/rustc_middle/src/ty/impls_ty.rs b/compiler/rustc_middle/src/ty/impls_ty.rs index 65c9b1aed050e..42e5a05d63b76 100644 --- a/compiler/rustc_middle/src/ty/impls_ty.rs +++ b/compiler/rustc_middle/src/ty/impls_ty.rs @@ -135,8 +135,8 @@ impl<'a> HashStable> for ty::RegionKind { ty::RePlaceholder(p) => { p.hash_stable(hcx, hasher); } - ty::ReVar(..) => { - bug!("StableHasher: unexpected region {:?}", *self) + ty::ReVar(reg) => { + reg.hash_stable(hcx, hasher); } } } diff --git a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs index b8088766cca68..3d22f5a04a2bf 100644 --- a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs +++ b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs @@ -2,11 +2,12 @@ pub use self::def_id_forest::DefIdForest; use crate::ty; use crate::ty::context::TyCtxt; -use crate::ty::TyKind::*; use crate::ty::{AdtDef, FieldDef, Ty, VariantDef}; use crate::ty::{AdtKind, Visibility}; use crate::ty::{DefId, SubstsRef}; +use rustc_type_ir::sty::TyKind::*; + mod def_id_forest; // The methods in this module calculate `DefIdForest`s of modules in which an diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index d187146476ab4..30552c685a33a 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -2163,7 +2163,7 @@ impl<'tcx> SizeSkeleton<'tcx> { } } - pub fn same_size(self, other: SizeSkeleton<'_>) -> bool { + pub fn same_size(self, other: SizeSkeleton<'tcx>) -> bool { match (self, other) { (SizeSkeleton::Known(a), SizeSkeleton::Known(b)) => a == b, (SizeSkeleton::Pointer { tail: a, .. }, SizeSkeleton::Pointer { tail: b, .. }) => { @@ -2888,6 +2888,14 @@ pub fn fn_can_unwind<'tcx>(tcx: TyCtxt<'tcx>, fn_def_id: Option, abi: Spe return false; } + // With `-C panic=abort`, all non-FFI functions are required to not unwind. + // + // Note that this is true regardless ABI specified on the function -- a `extern "C-unwind"` + // function defined in Rust is also required to abort. + if tcx.sess.panic_strategy() == PanicStrategy::Abort && !tcx.is_foreign_item(did) { + return false; + } + // With -Z panic-in-drop=abort, drop_in_place never unwinds. // // This is not part of `codegen_fn_attrs` as it can differ between crates diff --git a/compiler/rustc_middle/src/ty/list.rs b/compiler/rustc_middle/src/ty/list.rs index 197dc9205b480..3c9e96df59aa4 100644 --- a/compiler/rustc_middle/src/ty/list.rs +++ b/compiler/rustc_middle/src/ty/list.rs @@ -122,13 +122,6 @@ impl> Encodable for List { } } -impl> Encodable for &List { - #[inline] - fn encode(&self, s: &mut S) -> Result<(), S::Error> { - (**self).encode(s) - } -} - impl PartialEq for List { #[inline] fn eq(&self, other: &List) -> bool { diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 1c552591b117c..a493aaac276b1 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -51,6 +51,7 @@ use std::{fmt, str}; pub use crate::ty::diagnostics::*; pub use rustc_type_ir::InferTy::*; +pub use rustc_type_ir::TyKind::*; pub use rustc_type_ir::*; pub use self::binding::BindingMode; @@ -72,17 +73,18 @@ pub use self::context::{ }; pub use self::instance::{Instance, InstanceDef}; pub use self::list::List; +pub use self::parameterized::ParameterizedOverTcx; +pub use self::rvalue_scopes::RvalueScopes; pub use self::sty::BoundRegionKind::*; pub use self::sty::RegionKind::*; -pub use self::sty::TyKind::*; pub use self::sty::{ - Binder, BoundRegion, BoundRegionKind, BoundTy, BoundTyKind, BoundVar, BoundVariableKind, - CanonicalPolyFnSig, ClosureSubsts, ClosureSubstsParts, ConstVid, EarlyBinder, EarlyBoundRegion, - ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, FnSig, FreeRegion, GenSig, - GeneratorSubsts, GeneratorSubstsParts, InlineConstSubsts, InlineConstSubstsParts, ParamConst, - ParamTy, PolyExistentialProjection, PolyExistentialTraitRef, PolyFnSig, PolyGenSig, - PolyTraitRef, ProjectionTy, Region, RegionKind, RegionVid, TraitRef, TyKind, TypeAndMut, - UpvarSubsts, VarianceDiagInfo, + Article, Binder, BoundRegion, BoundRegionKind, BoundTy, BoundTyKind, BoundVar, + BoundVariableKind, CanonicalPolyFnSig, ClosureSubsts, ClosureSubstsParts, ConstVid, + EarlyBinder, EarlyBoundRegion, ExistentialPredicate, ExistentialProjection, + ExistentialTraitRef, FnSig, FreeRegion, GenSig, GeneratorSubsts, GeneratorSubstsParts, + InlineConstSubsts, InlineConstSubstsParts, ParamConst, ParamTy, PolyExistentialProjection, + PolyExistentialTraitRef, PolyFnSig, PolyGenSig, PolyTraitRef, ProjectionTy, Region, RegionKind, + RegionVid, TraitRef, TyKind, TypeAndMut, UpvarSubsts, VarianceDiagInfo, }; pub use self::trait_def::TraitDef; @@ -118,6 +120,8 @@ mod generics; mod impls_ty; mod instance; mod list; +mod parameterized; +mod rvalue_scopes; mod structural_impls; mod sty; @@ -227,7 +231,7 @@ impl fmt::Display for ImplPolarity { } } -#[derive(Clone, Debug, PartialEq, Eq, Copy, Hash, TyEncodable, TyDecodable, HashStable)] +#[derive(Clone, Debug, PartialEq, Eq, Copy, Hash, Encodable, Decodable, HashStable)] pub enum Visibility { /// Visible everywhere (including in other crates). Public, @@ -409,7 +413,7 @@ pub struct CReaderCacheKey { /// of the relevant methods. #[derive(PartialEq, Eq, PartialOrd, Ord)] #[allow(rustc::usage_of_ty_tykind)] -crate struct TyS<'tcx> { +pub(crate) struct TyS<'tcx> { /// This field shouldn't be used directly and may be removed in the future. /// Use `Ty::kind()` instead. kind: TyKind<'tcx>, @@ -459,16 +463,18 @@ static_assert_size!(WithStableHash>, 56); #[rustc_pass_by_value] pub struct Ty<'tcx>(Interned<'tcx, WithStableHash>>); -// Statics only used for internal testing. -pub static BOOL_TY: Ty<'static> = Ty(Interned::new_unchecked(&WithStableHash { - internee: BOOL_TYS, - stable_hash: Fingerprint::ZERO, -})); -const BOOL_TYS: TyS<'static> = TyS { - kind: ty::Bool, - flags: TypeFlags::empty(), - outer_exclusive_binder: DebruijnIndex::from_usize(0), -}; +impl<'tcx> TyCtxt<'tcx> { + /// A "bool" type used in rustc_mir_transform unit tests when we + /// have not spun up a TyCtxt. + pub const BOOL_TY_FOR_UNIT_TESTING: Ty<'tcx> = Ty(Interned::new_unchecked(&WithStableHash { + internee: TyS { + kind: ty::Bool, + flags: TypeFlags::empty(), + outer_exclusive_binder: DebruijnIndex::from_usize(0), + }, + stable_hash: Fingerprint::ZERO, + })); +} impl<'a, 'tcx> HashStable> for TyS<'tcx> { #[inline] @@ -500,7 +506,7 @@ impl ty::EarlyBoundRegion { /// See comments on `TyS`, which apply here too (albeit for /// `PredicateS`/`Predicate` rather than `TyS`/`Ty`). #[derive(Debug)] -crate struct PredicateS<'tcx> { +pub(crate) struct PredicateS<'tcx> { kind: Binder<'tcx, PredicateKind<'tcx>>, flags: TypeFlags, /// See the comment for the corresponding field of [TyS]. @@ -1628,7 +1634,7 @@ where } } -#[derive(Copy, Clone, Debug, HashStable)] +#[derive(Copy, Clone, Debug, HashStable, Encodable, Decodable)] pub struct Destructor { /// The `DefId` of the destructor method pub did: DefId, @@ -1995,7 +2001,7 @@ impl<'tcx> TyCtxt<'tcx> { } /// Look up the name of a definition across crates. This does not look at HIR. - fn opt_item_name(self, def_id: DefId) -> Option { + pub fn opt_item_name(self, def_id: DefId) -> Option { if let Some(cnum) = def_id.as_crate_root() { Some(self.crate_name(cnum)) } else { @@ -2297,6 +2303,11 @@ impl<'tcx> TyCtxt<'tcx> { matches!(self.def_kind(def_id), DefKind::Fn | DefKind::AssocFn | DefKind::Ctor(..)) && self.impl_constness(def_id) == hir::Constness::Const } + + #[inline] + pub fn is_const_default_method(self, def_id: DefId) -> bool { + matches!(self.trait_of_item(def_id), Some(trait_id) if self.has_attr(trait_id, sym::const_trait)) + } } /// Yields the parent function's `LocalDefId` if `def_id` is an `impl Trait` definition. diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs new file mode 100644 index 0000000000000..54ba9e84fdb7b --- /dev/null +++ b/compiler/rustc_middle/src/ty/parameterized.rs @@ -0,0 +1,119 @@ +use rustc_hir::def_id::DefId; +use rustc_index::vec::{Idx, IndexVec}; + +use crate::middle::exported_symbols::ExportedSymbol; +use crate::mir::Body; +use crate::thir::abstract_const::Node; +use crate::ty::{ + self, Const, FnSig, GeneratorDiagnosticData, GenericPredicates, Predicate, TraitRef, Ty, +}; + +pub trait ParameterizedOverTcx: 'static { + #[allow(unused_lifetimes)] + type Value<'tcx>; +} + +impl ParameterizedOverTcx for &'static [T] { + type Value<'tcx> = &'tcx [T::Value<'tcx>]; +} + +impl ParameterizedOverTcx for Option { + type Value<'tcx> = Option>; +} + +impl ParameterizedOverTcx for (A, B) { + type Value<'tcx> = (A::Value<'tcx>, B::Value<'tcx>); +} + +impl ParameterizedOverTcx for IndexVec { + type Value<'tcx> = IndexVec>; +} + +impl ParameterizedOverTcx for ty::Binder<'static, T> { + type Value<'tcx> = ty::Binder<'tcx, T::Value<'tcx>>; +} + +#[macro_export] +macro_rules! trivially_parameterized_over_tcx { + ($($ty:ty),+ $(,)?) => { + $( + impl $crate::ty::ParameterizedOverTcx for $ty { + #[allow(unused_lifetimes)] + type Value<'tcx> = $ty; + } + )* + } +} + +trivially_parameterized_over_tcx! { + usize, + (), + u32, + std::string::String, + crate::metadata::ModChild, + crate::middle::codegen_fn_attrs::CodegenFnAttrs, + crate::middle::exported_symbols::SymbolExportInfo, + crate::mir::ConstQualifs, + ty::Generics, + ty::ImplPolarity, + ty::ReprOptions, + ty::TraitDef, + ty::Visibility, + ty::adjustment::CoerceUnsizedInfo, + ty::fast_reject::SimplifiedTypeGen, + rustc_ast::Attribute, + rustc_ast::MacArgs, + rustc_attr::ConstStability, + rustc_attr::Deprecation, + rustc_attr::Stability, + rustc_hir::Constness, + rustc_hir::Defaultness, + rustc_hir::GeneratorKind, + rustc_hir::IsAsync, + rustc_hir::LangItem, + rustc_hir::def::DefKind, + rustc_hir::def_id::DefIndex, + rustc_hir::definitions::DefKey, + rustc_index::bit_set::FiniteBitSet, + rustc_session::cstore::ForeignModule, + rustc_session::cstore::LinkagePreference, + rustc_session::cstore::NativeLib, + rustc_span::DebuggerVisualizerFile, + rustc_span::ExpnData, + rustc_span::ExpnHash, + rustc_span::ExpnId, + rustc_span::SourceFile, + rustc_span::Span, + rustc_span::Symbol, + rustc_span::def_id::DefPathHash, + rustc_span::hygiene::SyntaxContextData, + rustc_span::symbol::Ident, + rustc_type_ir::Variance, +} + +// HACK(compiler-errors): This macro rule can only take an ident, +// not a path, due to parsing ambiguity reasons. That means we gotta +// import all of these types above. +#[macro_export] +macro_rules! parameterized_over_tcx { + ($($ident:ident),+ $(,)?) => { + $( + impl $crate::ty::ParameterizedOverTcx for $ident<'static> { + type Value<'tcx> = $ident<'tcx>; + } + )* + } +} + +parameterized_over_tcx! { + Ty, + FnSig, + GenericPredicates, + TraitRef, + Const, + Predicate, + GeneratorDiagnosticData, + Body, + Node, + ExportedSymbol, +} diff --git a/compiler/rustc_middle/src/ty/query.rs b/compiler/rustc_middle/src/ty/query.rs index fb937ded65af1..65f41c5266d17 100644 --- a/compiler/rustc_middle/src/ty/query.rs +++ b/compiler/rustc_middle/src/ty/query.rs @@ -6,15 +6,16 @@ use crate::middle::codegen_fn_attrs::CodegenFnAttrs; use crate::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo}; use crate::middle::lib_features::LibFeatures; use crate::middle::privacy::AccessLevels; -use crate::middle::region; use crate::middle::resolve_lifetime::{ LifetimeScopeForPath, ObjectLifetimeDefault, Region, ResolveLifetimes, }; use crate::middle::stability::{self, DeprecationEntry}; use crate::mir; use crate::mir::interpret::GlobalId; -use crate::mir::interpret::{ConstAlloc, LitToConstError, LitToConstInput}; -use crate::mir::interpret::{ConstValue, EvalToAllocationRawResult, EvalToConstValueResult}; +use crate::mir::interpret::{ + ConstValue, EvalToAllocationRawResult, EvalToConstValueResult, EvalToValTreeResult, +}; +use crate::mir::interpret::{LitToConstError, LitToConstInput}; use crate::mir::mono::CodegenUnit; use crate::thir; use crate::traits::query::{ diff --git a/compiler/rustc_middle/src/ty/rvalue_scopes.rs b/compiler/rustc_middle/src/ty/rvalue_scopes.rs new file mode 100644 index 0000000000000..e86dafae338f2 --- /dev/null +++ b/compiler/rustc_middle/src/ty/rvalue_scopes.rs @@ -0,0 +1,57 @@ +use crate::middle::region::{Scope, ScopeData, ScopeTree}; +use rustc_data_structures::fx::FxHashMap; +use rustc_hir as hir; + +/// `RvalueScopes` is a mapping from sub-expressions to _extended_ lifetime as determined by +/// rules laid out in `rustc_typeck::check::rvalue_scopes`. +#[derive(TyEncodable, TyDecodable, Clone, Debug, Default, Eq, PartialEq, HashStable)] +pub struct RvalueScopes { + map: FxHashMap>, +} + +impl RvalueScopes { + pub fn new() -> Self { + Self { map: <_>::default() } + } + + /// Returns the scope when the temp created by `expr_id` will be cleaned up. + pub fn temporary_scope( + &self, + region_scope_tree: &ScopeTree, + expr_id: hir::ItemLocalId, + ) -> Option { + // Check for a designated rvalue scope. + if let Some(&s) = self.map.get(&expr_id) { + debug!("temporary_scope({expr_id:?}) = {s:?} [custom]"); + return s; + } + + // Otherwise, locate the innermost terminating scope + // if there's one. Static items, for instance, won't + // have an enclosing scope, hence no scope will be + // returned. + let mut id = Scope { id: expr_id, data: ScopeData::Node }; + + while let Some(&(p, _)) = region_scope_tree.parent_map.get(&id) { + match p.data { + ScopeData::Destruction => { + debug!("temporary_scope({expr_id:?}) = {id:?} [enclosing]"); + return Some(id); + } + _ => id = p, + } + } + + debug!("temporary_scope({expr_id:?}) = None"); + None + } + + /// Make an association between a sub-expression and an extended lifetime + pub fn record_rvalue_scope(&mut self, var: hir::ItemLocalId, lifetime: Option) { + debug!("record_rvalue_scope(var={var:?}, lifetime={lifetime:?})"); + if let Some(lifetime) = lifetime { + assert!(var != lifetime.item_local_id()); + } + self.map.insert(var, lifetime); + } +} diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index a973a5c9b5053..faeb729c88483 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -2,16 +2,14 @@ #![allow(rustc::usage_of_ty_tykind)] -use self::TyKind::*; - use crate::infer::canonical::Canonical; use crate::ty::fold::ValidateBoundVars; use crate::ty::subst::{GenericArg, InternalSubsts, Subst, SubstsRef}; -use crate::ty::InferTy::{self, *}; +use crate::ty::InferTy::*; use crate::ty::{ self, AdtDef, DefIdTree, Discr, Term, Ty, TyCtxt, TypeFlags, TypeFoldable, TypeVisitor, }; -use crate::ty::{DelaySpanBugEmitted, List, ParamEnv}; +use crate::ty::{List, ParamEnv}; use polonius_engine::Atom; use rustc_data_structures::captures::Captures; use rustc_data_structures::intern::Interned; @@ -29,6 +27,13 @@ use std::marker::PhantomData; use std::ops::{ControlFlow, Deref, Range}; use ty::util::IntTypeExt; +use rustc_type_ir::sty::TyKind::*; +use rustc_type_ir::TyKind as IrTyKind; + +// Re-export the `TyKind` from `rustc_type_ir` here for convenience +#[rustc_diagnostic_item = "TyKind"] +pub type TyKind<'tcx> = IrTyKind>; + #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)] #[derive(HashStable, TypeFoldable, Lift)] pub struct TypeAndMut<'tcx> { @@ -78,190 +83,13 @@ impl BoundRegionKind { } } -/// Defines the kinds of types used by the type system. -/// -/// Types written by the user start out as [hir::TyKind](rustc_hir::TyKind) and get -/// converted to this representation using `AstConv::ast_ty_to_ty`. -#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable, Debug)] -#[derive(HashStable)] -#[rustc_diagnostic_item = "TyKind"] -pub enum TyKind<'tcx> { - /// The primitive boolean type. Written as `bool`. - Bool, - - /// The primitive character type; holds a Unicode scalar value - /// (a non-surrogate code point). Written as `char`. - Char, - - /// A primitive signed integer type. For example, `i32`. - Int(ty::IntTy), - - /// A primitive unsigned integer type. For example, `u32`. - Uint(ty::UintTy), - - /// A primitive floating-point type. For example, `f64`. - Float(ty::FloatTy), - - /// Algebraic data types (ADT). For example: structures, enumerations and unions. - /// - /// For example, the type `List` would be represented using the `AdtDef` - /// for `struct List` and the substs `[i32]`. - /// - /// Note that generic parameters in fields only get lazily substituted - /// by using something like `adt_def.all_fields().map(|field| field.ty(tcx, substs))`. - Adt(AdtDef<'tcx>, SubstsRef<'tcx>), - - /// An unsized FFI type that is opaque to Rust. Written as `extern type T`. - Foreign(DefId), - - /// The pointee of a string slice. Written as `str`. - Str, - - /// An array with the given length. Written as `[T; N]`. - Array(Ty<'tcx>, ty::Const<'tcx>), - - /// The pointee of an array slice. Written as `[T]`. - Slice(Ty<'tcx>), - - /// A raw pointer. Written as `*mut T` or `*const T` - RawPtr(TypeAndMut<'tcx>), - - /// A reference; a pointer with an associated lifetime. Written as - /// `&'a mut T` or `&'a T`. - Ref(Region<'tcx>, Ty<'tcx>, hir::Mutability), - - /// The anonymous type of a function declaration/definition. Each - /// function has a unique type. - /// - /// For the function `fn foo() -> i32 { 3 }` this type would be - /// shown to the user as `fn() -> i32 {foo}`. - /// - /// For example the type of `bar` here: - /// ```rust - /// fn foo() -> i32 { 1 } - /// let bar = foo; // bar: fn() -> i32 {foo} - /// ``` - FnDef(DefId, SubstsRef<'tcx>), - - /// A pointer to a function. Written as `fn() -> i32`. - /// - /// Note that both functions and closures start out as either - /// [FnDef] or [Closure] which can be then be coerced to this variant. - /// - /// For example the type of `bar` here: - /// - /// ```rust - /// fn foo() -> i32 { 1 } - /// let bar: fn() -> i32 = foo; - /// ``` - FnPtr(PolyFnSig<'tcx>), - - /// A trait object. Written as `dyn for<'b> Trait<'b, Assoc = u32> + Send + 'a`. - Dynamic(&'tcx List>>, ty::Region<'tcx>), - - /// The anonymous type of a closure. Used to represent the type of `|a| a`. - /// - /// Closure substs contain both the - potentially substituted - generic parameters - /// of its parent and some synthetic parameters. See the documentation for - /// [ClosureSubsts] for more details. - Closure(DefId, SubstsRef<'tcx>), - - /// The anonymous type of a generator. Used to represent the type of - /// `|a| yield a`. - /// - /// For more info about generator substs, visit the documentation for - /// [GeneratorSubsts]. - Generator(DefId, SubstsRef<'tcx>, hir::Movability), - - /// A type representing the types stored inside a generator. - /// This should only appear as part of the [GeneratorSubsts]. - /// - /// Note that the captured variables for generators are stored separately - /// using a tuple in the same way as for closures. - /// - /// Unlike upvars, the witness can reference lifetimes from - /// inside of the generator itself. To deal with them in - /// the type of the generator, we convert them to higher ranked - /// lifetimes bound by the witness itself. - /// - /// Looking at the following example, the witness for this generator - /// may end up as something like `for<'a> [Vec, &'a Vec]`: - /// - /// ```ignore UNSOLVED (ask @compiler-errors, should this error? can we just swap the yields?) - /// #![feature(generators)] - /// |a| { - /// let x = &vec![3]; - /// yield a; - /// yield x[0]; - /// } - /// # ; - /// ``` - GeneratorWitness(Binder<'tcx, &'tcx List>>), - - /// The never type `!`. - Never, - - /// A tuple type. For example, `(i32, bool)`. - Tuple(&'tcx List>), - - /// The projection of an associated type. For example, - /// `>::N`. - Projection(ProjectionTy<'tcx>), - - /// Opaque (`impl Trait`) type found in a return type. - /// - /// The `DefId` comes either from - /// * the `impl Trait` ast::Ty node, - /// * or the `type Foo = impl Trait` declaration - /// - /// For RPIT the substitutions are for the generics of the function, - /// while for TAIT it is used for the generic parameters of the alias. - /// - /// During codegen, `tcx.type_of(def_id)` can be used to get the underlying type. - Opaque(DefId, SubstsRef<'tcx>), - - /// A type parameter; for example, `T` in `fn f(x: T) {}`. - Param(ParamTy), - - /// Bound type variable, used to represent the `'a` in `for<'a> fn(&'a ())`. - /// - /// For canonical queries, we replace inference variables with bound variables, - /// so e.g. when checking whether `&'_ (): Trait<_>` holds, we canonicalize that to - /// `for<'a, T> &'a (): Trait` and then convert the introduced bound variables - /// back to inference variables in a new inference context when inside of the query. - /// - /// See the `rustc-dev-guide` for more details about - /// [higher-ranked trait bounds][1] and [canonical queries][2]. - /// - /// [1]: https://rustc-dev-guide.rust-lang.org/traits/hrtb.html - /// [2]: https://rustc-dev-guide.rust-lang.org/traits/canonical-queries.html - Bound(ty::DebruijnIndex, BoundTy), - - /// A placeholder type, used during higher ranked subtyping to instantiate - /// bound variables. - Placeholder(ty::PlaceholderType), - - /// A type variable used during type checking. - /// - /// Similar to placeholders, inference variables also live in a universe to - /// correctly deal with higher ranked types. Though unlike placeholders, - /// that universe is stored in the `InferCtxt` instead of directly - /// inside of the type. - Infer(InferTy), - - /// A placeholder for a type which could not be computed; this is - /// propagated to avoid useless error messages. - Error(DelaySpanBugEmitted), +pub trait Article { + fn article(&self) -> &'static str; } -impl<'tcx> TyKind<'tcx> { - #[inline] - pub fn is_primitive(&self) -> bool { - matches!(self, Bool | Char | Int(_) | Uint(_) | Float(_)) - } - +impl<'tcx> Article for TyKind<'tcx> { /// Get the article ("a" or "an") to use with this type. - pub fn article(&self) -> &'static str { + fn article(&self) -> &'static str { match self { Int(_) | Float(_) | Array(_, _) => "an", Adt(def, _) if def.is_enum() => "an", @@ -930,7 +758,7 @@ impl<'tcx> List>> { } #[inline] - pub fn auto_traits<'a>(&'a self) -> impl Iterator + 'a { + pub fn auto_traits<'a>(&'a self) -> impl Iterator + Captures<'tcx> + 'a { self.iter().filter_map(|predicate| match predicate.skip_binder() { ExistentialPredicate::AutoTrait(did) => Some(did), _ => None, @@ -1469,7 +1297,7 @@ impl ParamConst { } } -/// Use this rather than `TyKind`, whenever possible. +/// Use this rather than `RegionKind`, whenever possible. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable)] #[rustc_pass_by_value] pub struct Region<'tcx>(pub Interned<'tcx, RegionKind>); diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs index 48c71113d5032..290485ab5fe0f 100644 --- a/compiler/rustc_middle/src/ty/subst.rs +++ b/compiler/rustc_middle/src/ty/subst.rs @@ -4,7 +4,7 @@ use crate::mir; use crate::ty::codec::{TyDecoder, TyEncoder}; use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeFolder, TypeVisitor}; use crate::ty::sty::{ClosureSubsts, GeneratorSubsts, InlineConstSubsts}; -use crate::ty::{self, EarlyBinder, Lift, List, ParamConst, Ty, TyCtxt}; +use crate::ty::{self, Lift, List, ParamConst, Ty, TyCtxt}; use rustc_data_structures::intern::{Interned, WithStableHash}; use rustc_hir::def_id::DefId; @@ -79,17 +79,17 @@ impl<'tcx> GenericArgKind<'tcx> { let (tag, ptr) = match self { GenericArgKind::Lifetime(lt) => { // Ensure we can use the tag bits. - assert_eq!(mem::align_of_val(lt.0.0) & TAG_MASK, 0); + assert_eq!(mem::align_of_val(&*lt.0.0) & TAG_MASK, 0); (REGION_TAG, lt.0.0 as *const ty::RegionKind as usize) } GenericArgKind::Type(ty) => { // Ensure we can use the tag bits. - assert_eq!(mem::align_of_val(ty.0.0) & TAG_MASK, 0); + assert_eq!(mem::align_of_val(&*ty.0.0) & TAG_MASK, 0); (TYPE_TAG, ty.0.0 as *const WithStableHash> as usize) } GenericArgKind::Const(ct) => { // Ensure we can use the tag bits. - assert_eq!(mem::align_of_val(ct.0.0) & TAG_MASK, 0); + assert_eq!(mem::align_of_val(&*ct.0.0) & TAG_MASK, 0); (CONST_TAG, ct.0.0 as *const ty::ConstS<'tcx> as usize) } }; @@ -109,13 +109,13 @@ impl<'tcx> fmt::Debug for GenericArg<'tcx> { } impl<'tcx> Ord for GenericArg<'tcx> { - fn cmp(&self, other: &GenericArg<'_>) -> Ordering { + fn cmp(&self, other: &GenericArg<'tcx>) -> Ordering { self.unpack().cmp(&other.unpack()) } } impl<'tcx> PartialOrd for GenericArg<'tcx> { - fn partial_cmp(&self, other: &GenericArg<'_>) -> Option { + fn partial_cmp(&self, other: &GenericArg<'tcx>) -> Option { Some(self.cmp(&other)) } } @@ -216,13 +216,13 @@ impl<'tcx> TypeFoldable<'tcx> for GenericArg<'tcx> { } } -impl<'tcx, E: TyEncoder<'tcx>> Encodable for GenericArg<'tcx> { +impl<'tcx, E: TyEncoder>> Encodable for GenericArg<'tcx> { fn encode(&self, e: &mut E) -> Result<(), E::Error> { self.unpack().encode(e) } } -impl<'tcx, D: TyDecoder<'tcx>> Decodable for GenericArg<'tcx> { +impl<'tcx, D: TyDecoder>> Decodable for GenericArg<'tcx> { fn decode(d: &mut D) -> GenericArg<'tcx> { GenericArgKind::decode(d).pack() } @@ -233,7 +233,7 @@ pub type InternalSubsts<'tcx> = List>; pub type SubstsRef<'tcx> = &'tcx InternalSubsts<'tcx>; -impl<'a, 'tcx> InternalSubsts<'tcx> { +impl<'tcx> InternalSubsts<'tcx> { /// Checks whether all elements of this list are types, if so, transmute. pub fn try_as_type_list(&'tcx self) -> Option<&'tcx List>> { if self.iter().all(|arg| matches!(arg.unpack(), GenericArgKind::Type(_))) { @@ -249,7 +249,7 @@ impl<'a, 'tcx> InternalSubsts<'tcx> { /// Closure substitutions have a particular structure controlled by the /// compiler that encodes information like the signature and closure kind; /// see `ty::ClosureSubsts` struct for more comments. - pub fn as_closure(&'a self) -> ClosureSubsts<'a> { + pub fn as_closure(&'tcx self) -> ClosureSubsts<'tcx> { ClosureSubsts { substs: self } } @@ -330,20 +330,20 @@ impl<'a, 'tcx> InternalSubsts<'tcx> { } #[inline] - pub fn types(&'a self) -> impl DoubleEndedIterator> + 'a { + pub fn types(&'tcx self) -> impl DoubleEndedIterator> + 'tcx { self.iter() .filter_map(|k| if let GenericArgKind::Type(ty) = k.unpack() { Some(ty) } else { None }) } #[inline] - pub fn regions(&'a self) -> impl DoubleEndedIterator> + 'a { + pub fn regions(&'tcx self) -> impl DoubleEndedIterator> + 'tcx { self.iter().filter_map(|k| { if let GenericArgKind::Lifetime(lt) = k.unpack() { Some(lt) } else { None } }) } #[inline] - pub fn consts(&'a self) -> impl DoubleEndedIterator> + 'a { + pub fn consts(&'tcx self) -> impl DoubleEndedIterator> + 'tcx { self.iter().filter_map(|k| { if let GenericArgKind::Const(ct) = k.unpack() { Some(ct) } else { None } }) @@ -351,8 +351,8 @@ impl<'a, 'tcx> InternalSubsts<'tcx> { #[inline] pub fn non_erasable_generics( - &'a self, - ) -> impl DoubleEndedIterator> + 'a { + &'tcx self, + ) -> impl DoubleEndedIterator> + 'tcx { self.iter().filter_map(|k| match k.unpack() { GenericArgKind::Lifetime(_) => None, generic => Some(generic), @@ -506,7 +506,7 @@ pub trait Subst<'tcx>: Sized { fn subst(self, tcx: TyCtxt<'tcx>, substs: &[GenericArg<'tcx>]) -> Self::Inner; } -impl<'tcx, T: TypeFoldable<'tcx>> Subst<'tcx> for EarlyBinder { +impl<'tcx, T: TypeFoldable<'tcx>> Subst<'tcx> for ty::EarlyBinder { type Inner = T; fn subst(self, tcx: TyCtxt<'tcx>, substs: &[GenericArg<'tcx>]) -> Self::Inner { diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs index ca6fabf7f4018..cb34b64660d2b 100644 --- a/compiler/rustc_middle/src/ty/trait_def.rs +++ b/compiler/rustc_middle/src/ty/trait_def.rs @@ -143,7 +143,7 @@ impl<'tcx> TyCtxt<'tcx> { self_ty: Ty<'tcx>, ) -> impl Iterator + 'tcx { let impls = self.trait_impls_of(def_id); - if let Some(simp) = fast_reject::simplify_type(self, self_ty, TreatParams::AsPlaceholders) { + if let Some(simp) = fast_reject::simplify_type(self, self_ty, TreatParams::AsInfer) { if let Some(impls) = impls.non_blanket_impls.get(&simp) { return impls.iter().copied(); } @@ -173,14 +173,14 @@ impl<'tcx> TyCtxt<'tcx> { } } - // Note that we're using `TreatParams::AsBoundTypes` to query `non_blanket_impls` while using - // `TreatParams::AsPlaceholders` while actually adding them. + // Note that we're using `TreatParams::AsPlaceholder` to query `non_blanket_impls` while using + // `TreatParams::AsInfer` while actually adding them. // // This way, when searching for some impl for `T: Trait`, we do not look at any impls // whose outer level is not a parameter or projection. Especially for things like // `T: Clone` this is incredibly useful as we would otherwise look at all the impls // of `Clone` for `Option`, `Vec`, `ConcreteType` and so on. - if let Some(simp) = fast_reject::simplify_type(self, self_ty, TreatParams::AsBoundTypes) { + if let Some(simp) = fast_reject::simplify_type(self, self_ty, TreatParams::AsPlaceholder) { if let Some(impls) = impls.non_blanket_impls.get(&simp) { for &impl_def_id in impls { if let result @ Some(_) = f(impl_def_id) { @@ -240,7 +240,7 @@ pub(super) fn trait_impls_of_provider(tcx: TyCtxt<'_>, trait_id: DefId) -> Trait } if let Some(simplified_self_ty) = - fast_reject::simplify_type(tcx, impl_self_ty, TreatParams::AsPlaceholders) + fast_reject::simplify_type(tcx, impl_self_ty, TreatParams::AsInfer) { impls.non_blanket_impls.entry(simplified_self_ty).or_default().push(impl_def_id); } else { diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 10520670069b4..809e7ce2e745b 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -5,10 +5,7 @@ use crate::ty::fold::{FallibleTypeFolder, TypeFolder}; use crate::ty::layout::IntegerExt; use crate::ty::query::TyCtxtAt; use crate::ty::subst::{GenericArgKind, Subst, SubstsRef}; -use crate::ty::{ - self, Const, DebruijnIndex, DefIdTree, EarlyBinder, List, ReEarlyBound, Ty, TyCtxt, TyKind::*, - TypeFoldable, -}; +use crate::ty::{self, DefIdTree, Ty, TyCtxt, TypeFoldable}; use rustc_apfloat::Float as _; use rustc_ast as ast; use rustc_attr::{self as attr, SignedInt, UnsignedInt}; @@ -18,9 +15,11 @@ use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind, Res}; use rustc_hir::def_id::DefId; +use rustc_index::bit_set::GrowableBitSet; use rustc_macros::HashStable; use rustc_span::{sym, DUMMY_SP}; use rustc_target::abi::{Integer, Size, TargetDataLayout}; +use rustc_target::spec::abi::Abi; use smallvec::SmallVec; use std::{fmt, iter}; @@ -31,6 +30,19 @@ pub struct Discr<'tcx> { pub ty: Ty<'tcx>, } +/// Used as an input to [`TyCtxt::uses_unique_generic_params`]. +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum IgnoreRegions { + Yes, + No, +} + +#[derive(Copy, Clone, Debug)] +pub enum NotUniqueParam<'tcx> { + DuplicateParam(ty::GenericArg<'tcx>), + NotParam(ty::GenericArg<'tcx>), +} + impl<'tcx> fmt::Display for Discr<'tcx> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { match *self.ty.kind() { @@ -48,8 +60,8 @@ impl<'tcx> fmt::Display for Discr<'tcx> { fn int_size_and_signed<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> (Size, bool) { let (int, signed) = match *ty.kind() { - Int(ity) => (Integer::from_int_ty(&tcx, ity), true), - Uint(uty) => (Integer::from_uint_ty(&tcx, uty), false), + ty::Int(ity) => (Integer::from_int_ty(&tcx, ity), true), + ty::Uint(uty) => (Integer::from_uint_ty(&tcx, uty), false), _ => bug!("non integer discriminant"), }; (int.size(), signed) @@ -175,7 +187,7 @@ impl<'tcx> TyCtxt<'tcx> { if let ty::Adt(def, substs) = *ty.kind() { for field in def.all_fields() { let field_ty = field.ty(self, substs); - if let Error(_) = field_ty.kind() { + if let ty::Error(_) = field_ty.kind() { return true; } } @@ -310,7 +322,7 @@ impl<'tcx> TyCtxt<'tcx> { let (mut a, mut b) = (source, target); loop { match (&a.kind(), &b.kind()) { - (&Adt(a_def, a_substs), &Adt(b_def, b_substs)) + (&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.last() { @@ -320,7 +332,7 @@ impl<'tcx> TyCtxt<'tcx> { break; } } - (&Tuple(a_tys), &Tuple(b_tys)) if a_tys.len() == b_tys.len() => { + (&ty::Tuple(a_tys), &ty::Tuple(b_tys)) if a_tys.len() == b_tys.len() => { if let Some(&a_last) = a_tys.last() { a = a_last; b = *b_tys.last().unwrap(); @@ -426,7 +438,7 @@ impl<'tcx> TyCtxt<'tcx> { .filter(|&(_, k)| { match k.unpack() { GenericArgKind::Lifetime(region) => match region.kind() { - ReEarlyBound(ref ebr) => { + ty::ReEarlyBound(ref ebr) => { !impl_generics.region_param(ebr, self).pure_wrt_drop } // Error: not a region param @@ -452,6 +464,47 @@ impl<'tcx> TyCtxt<'tcx> { result } + /// Checks whether each generic argument is simply a unique generic parameter. + pub fn uses_unique_generic_params( + self, + substs: SubstsRef<'tcx>, + ignore_regions: IgnoreRegions, + ) -> Result<(), NotUniqueParam<'tcx>> { + let mut seen = GrowableBitSet::default(); + for arg in substs { + match arg.unpack() { + GenericArgKind::Lifetime(lt) => { + if ignore_regions == IgnoreRegions::No { + let ty::ReEarlyBound(p) = lt.kind() else { + return Err(NotUniqueParam::NotParam(lt.into())) + }; + if !seen.insert(p.index) { + return Err(NotUniqueParam::DuplicateParam(lt.into())); + } + } + } + GenericArgKind::Type(t) => match t.kind() { + ty::Param(p) => { + if !seen.insert(p.index) { + return Err(NotUniqueParam::DuplicateParam(t.into())); + } + } + _ => return Err(NotUniqueParam::NotParam(t.into())), + }, + GenericArgKind::Const(c) => match c.val() { + ty::ConstKind::Param(p) => { + if !seen.insert(p.index) { + return Err(NotUniqueParam::DuplicateParam(c.into())); + } + } + _ => return Err(NotUniqueParam::NotParam(c.into())), + }, + } + } + + Ok(()) + } + /// Returns `true` if `def_id` refers to a closure (e.g., `|x| x * 2`). Note /// that closures have a `DefId`, but the closure *expression* also /// has a `HirId` that is located within the context where the @@ -593,30 +646,33 @@ impl<'tcx> TyCtxt<'tcx> { if visitor.found_recursion { Err(expanded_type) } else { Ok(expanded_type) } } - pub fn bound_type_of(self, def_id: DefId) -> EarlyBinder> { - EarlyBinder(self.type_of(def_id)) + pub fn bound_type_of(self, def_id: DefId) -> ty::EarlyBinder> { + ty::EarlyBinder(self.type_of(def_id)) } - pub fn bound_fn_sig(self, def_id: DefId) -> EarlyBinder> { - EarlyBinder(self.fn_sig(def_id)) + pub fn bound_fn_sig(self, def_id: DefId) -> ty::EarlyBinder> { + ty::EarlyBinder(self.fn_sig(def_id)) } - pub fn bound_impl_trait_ref(self, def_id: DefId) -> Option>> { - self.impl_trait_ref(def_id).map(|i| EarlyBinder(i)) + pub fn bound_impl_trait_ref( + self, + def_id: DefId, + ) -> Option>> { + self.impl_trait_ref(def_id).map(|i| ty::EarlyBinder(i)) } pub fn bound_explicit_item_bounds( self, def_id: DefId, - ) -> EarlyBinder<&'tcx [(ty::Predicate<'tcx>, rustc_span::Span)]> { - EarlyBinder(self.explicit_item_bounds(def_id)) + ) -> ty::EarlyBinder<&'tcx [(ty::Predicate<'tcx>, rustc_span::Span)]> { + ty::EarlyBinder(self.explicit_item_bounds(def_id)) } pub fn bound_item_bounds( self, def_id: DefId, - ) -> EarlyBinder<&'tcx ty::List>> { - EarlyBinder(self.item_bounds(def_id)) + ) -> ty::EarlyBinder<&'tcx ty::List>> { + ty::EarlyBinder(self.item_bounds(def_id)) } } @@ -689,7 +745,7 @@ impl<'tcx> TypeFolder<'tcx> for OpaqueTypeExpander<'tcx> { impl<'tcx> Ty<'tcx> { /// Returns the maximum value for the given numeric type (including `char`s) /// or returns `None` if the type is not numeric. - pub fn numeric_max_val(self, tcx: TyCtxt<'tcx>) -> Option> { + pub fn numeric_max_val(self, tcx: TyCtxt<'tcx>) -> Option> { let val = match self.kind() { ty::Int(_) | ty::Uint(_) => { let (size, signed) = int_size_and_signed(tcx, self); @@ -704,12 +760,13 @@ impl<'tcx> Ty<'tcx> { }), _ => None, }; - val.map(|v| Const::from_bits(tcx, v, ty::ParamEnv::empty().and(self))) + + val.map(|v| ty::Const::from_bits(tcx, v, ty::ParamEnv::empty().and(self))) } /// Returns the minimum value for the given numeric type (including `char`s) /// or returns `None` if the type is not numeric. - pub fn numeric_min_val(self, tcx: TyCtxt<'tcx>) -> Option> { + pub fn numeric_min_val(self, tcx: TyCtxt<'tcx>) -> Option> { let val = match self.kind() { ty::Int(_) | ty::Uint(_) => { let (size, signed) = int_size_and_signed(tcx, self); @@ -723,7 +780,8 @@ impl<'tcx> Ty<'tcx> { }), _ => None, }; - val.map(|v| Const::from_bits(tcx, v, ty::ParamEnv::empty().and(self))) + + val.map(|v| ty::Const::from_bits(tcx, v, ty::ParamEnv::empty().and(self))) } /// Checks whether values of this type `T` are *moved* or *copied* @@ -927,35 +985,40 @@ impl<'tcx> Ty<'tcx> { pub fn is_structural_eq_shallow(self, tcx: TyCtxt<'tcx>) -> bool { match self.kind() { // Look for an impl of both `PartialStructuralEq` and `StructuralEq`. - Adt(..) => tcx.has_structural_eq_impls(self), + ty::Adt(..) => tcx.has_structural_eq_impls(self), // Primitive types that satisfy `Eq`. - Bool | Char | Int(_) | Uint(_) | Str | Never => true, + ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Str | ty::Never => true, // Composite types that satisfy `Eq` when all of their fields do. // // Because this function is "shallow", we return `true` for these composites regardless // of the type(s) contained within. - Ref(..) | Array(..) | Slice(_) | Tuple(..) => true, + ty::Ref(..) | ty::Array(..) | ty::Slice(_) | ty::Tuple(..) => true, // Raw pointers use bitwise comparison. - RawPtr(_) | FnPtr(_) => true, + ty::RawPtr(_) | ty::FnPtr(_) => true, // Floating point numbers are not `Eq`. - Float(_) => false, + ty::Float(_) => false, // Conservatively return `false` for all others... // Anonymous function types - FnDef(..) | Closure(..) | Dynamic(..) | Generator(..) => false, + ty::FnDef(..) | ty::Closure(..) | ty::Dynamic(..) | ty::Generator(..) => false, // Generic or inferred types // // FIXME(ecstaticmorse): Maybe we should `bug` here? This should probably only be // called for known, fully-monomorphized types. - Projection(_) | Opaque(..) | Param(_) | Bound(..) | Placeholder(_) | Infer(_) => false, + ty::Projection(_) + | ty::Opaque(..) + | ty::Param(_) + | ty::Bound(..) + | ty::Placeholder(_) + | ty::Infer(_) => false, - Foreign(_) | GeneratorWitness(..) | Error(_) => false, + ty::Foreign(_) | ty::GeneratorWitness(..) | ty::Error(_) => false, } } @@ -971,13 +1034,13 @@ impl<'tcx> Ty<'tcx> { /// - `&'a *const &'b u8 -> *const &'b u8` pub fn peel_refs(self) -> Ty<'tcx> { let mut ty = self; - while let Ref(_, inner_ty, _) = ty.kind() { + while let ty::Ref(_, inner_ty, _) = ty.kind() { ty = *inner_ty; } ty } - pub fn outer_exclusive_binder(self) -> DebruijnIndex { + pub fn outer_exclusive_binder(self) -> ty::DebruijnIndex { self.0.outer_exclusive_binder } } @@ -1174,8 +1237,8 @@ pub struct AlwaysRequiresDrop; /// with their underlying types. pub fn normalize_opaque_types<'tcx>( tcx: TyCtxt<'tcx>, - val: &'tcx List>, -) -> &'tcx List> { + val: &'tcx ty::List>, +) -> &'tcx ty::List> { let mut visitor = OpaqueTypeExpander { seen_opaque_tys: FxHashSet::default(), expanded_cache: FxHashMap::default(), @@ -1195,6 +1258,12 @@ pub fn is_doc_hidden(tcx: TyCtxt<'_>, def_id: DefId) -> bool { .any(|items| items.iter().any(|item| item.has_name(sym::hidden))) } +/// Determines whether an item is an intrinsic by Abi. +pub fn is_intrinsic(tcx: TyCtxt<'_>, def_id: DefId) -> bool { + matches!(tcx.fn_sig(def_id).abi(), Abi::RustIntrinsic | Abi::PlatformIntrinsic) +} + pub fn provide(providers: &mut ty::query::Providers) { - *providers = ty::query::Providers { normalize_opaque_types, is_doc_hidden, ..*providers } + *providers = + ty::query::Providers { normalize_opaque_types, is_doc_hidden, is_intrinsic, ..*providers } } diff --git a/compiler/rustc_middle/src/ty/vtable.rs b/compiler/rustc_middle/src/ty/vtable.rs index f766cad2b3d21..04a9fd1f71308 100644 --- a/compiler/rustc_middle/src/ty/vtable.rs +++ b/compiler/rustc_middle/src/ty/vtable.rs @@ -36,8 +36,11 @@ impl<'tcx> fmt::Debug for VtblEntry<'tcx> { } } -pub const COMMON_VTABLE_ENTRIES: &[VtblEntry<'_>] = - &[VtblEntry::MetadataDropInPlace, VtblEntry::MetadataSize, VtblEntry::MetadataAlign]; +// Needs to be associated with the `'tcx` lifetime +impl<'tcx> TyCtxt<'tcx> { + pub const COMMON_VTABLE_ENTRIES: &'tcx [VtblEntry<'tcx>] = + &[VtblEntry::MetadataDropInPlace, VtblEntry::MetadataSize, VtblEntry::MetadataAlign]; +} pub const COMMON_VTABLE_ENTRIES_DROPINPLACE: usize = 0; pub const COMMON_VTABLE_ENTRIES_SIZE: usize = 1; @@ -57,7 +60,7 @@ pub(super) fn vtable_allocation_provider<'tcx>( tcx.vtable_entries(trait_ref) } else { - COMMON_VTABLE_ENTRIES + TyCtxt::COMMON_VTABLE_ENTRIES }; let layout = tcx diff --git a/compiler/rustc_mir_build/src/build/block.rs b/compiler/rustc_mir_build/src/build/block.rs index 679043bdc30f9..a83328c0cabc6 100644 --- a/compiler/rustc_mir_build/src/build/block.rs +++ b/compiler/rustc_mir_build/src/build/block.rs @@ -6,7 +6,7 @@ use rustc_middle::{mir::*, ty}; use rustc_span::Span; impl<'a, 'tcx> Builder<'a, 'tcx> { - crate fn ast_block( + pub(crate) fn ast_block( &mut self, destination: Place<'tcx>, block: BasicBlock, diff --git a/compiler/rustc_mir_build/src/build/cfg.rs b/compiler/rustc_mir_build/src/build/cfg.rs index ac92b03e5f385..d7b4b1f731a67 100644 --- a/compiler/rustc_mir_build/src/build/cfg.rs +++ b/compiler/rustc_mir_build/src/build/cfg.rs @@ -5,33 +5,33 @@ use rustc_middle::mir::*; use rustc_middle::ty::TyCtxt; impl<'tcx> CFG<'tcx> { - crate fn block_data(&self, blk: BasicBlock) -> &BasicBlockData<'tcx> { + pub(crate) fn block_data(&self, blk: BasicBlock) -> &BasicBlockData<'tcx> { &self.basic_blocks[blk] } - crate fn block_data_mut(&mut self, blk: BasicBlock) -> &mut BasicBlockData<'tcx> { + pub(crate) fn block_data_mut(&mut self, blk: BasicBlock) -> &mut BasicBlockData<'tcx> { &mut self.basic_blocks[blk] } // llvm.org/PR32488 makes this function use an excess of stack space. Mark // it as #[inline(never)] to keep rustc's stack use in check. #[inline(never)] - crate fn start_new_block(&mut self) -> BasicBlock { + pub(crate) fn start_new_block(&mut self) -> BasicBlock { self.basic_blocks.push(BasicBlockData::new(None)) } - crate fn start_new_cleanup_block(&mut self) -> BasicBlock { + pub(crate) fn start_new_cleanup_block(&mut self) -> BasicBlock { let bb = self.start_new_block(); self.block_data_mut(bb).is_cleanup = true; bb } - crate fn push(&mut self, block: BasicBlock, statement: Statement<'tcx>) { + pub(crate) fn push(&mut self, block: BasicBlock, statement: Statement<'tcx>) { debug!("push({:?}, {:?})", block, statement); self.block_data_mut(block).statements.push(statement); } - crate fn push_assign( + pub(crate) fn push_assign( &mut self, block: BasicBlock, source_info: SourceInfo, @@ -44,7 +44,7 @@ impl<'tcx> CFG<'tcx> { ); } - crate fn push_assign_constant( + pub(crate) fn push_assign_constant( &mut self, block: BasicBlock, source_info: SourceInfo, @@ -59,7 +59,7 @@ impl<'tcx> CFG<'tcx> { ); } - crate fn push_assign_unit( + pub(crate) fn push_assign_unit( &mut self, block: BasicBlock, source_info: SourceInfo, @@ -78,7 +78,7 @@ impl<'tcx> CFG<'tcx> { ); } - crate fn push_fake_read( + pub(crate) fn push_fake_read( &mut self, block: BasicBlock, source_info: SourceInfo, @@ -90,7 +90,7 @@ impl<'tcx> CFG<'tcx> { self.push(block, stmt); } - crate fn terminate( + pub(crate) fn terminate( &mut self, block: BasicBlock, source_info: SourceInfo, @@ -107,7 +107,7 @@ impl<'tcx> CFG<'tcx> { } /// In the `origin` block, push a `goto -> target` terminator. - crate fn goto(&mut self, origin: BasicBlock, source_info: SourceInfo, target: BasicBlock) { + pub(crate) fn goto(&mut self, origin: BasicBlock, source_info: SourceInfo, target: BasicBlock) { self.terminate(origin, source_info, TerminatorKind::Goto { target }) } } diff --git a/compiler/rustc_mir_build/src/build/expr/as_constant.rs b/compiler/rustc_mir_build/src/build/expr/as_constant.rs index 3a6e59db90b91..035e94eecee23 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_constant.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_constant.rs @@ -1,21 +1,17 @@ //! See docs in build/expr/mod.rs -use crate::build::Builder; -use crate::thir::constant::parse_float; -use rustc_ast as ast; +use crate::build::{lit_to_mir_constant, Builder}; use rustc_hir::def_id::DefId; -use rustc_middle::mir::interpret::Allocation; use rustc_middle::mir::interpret::{ConstValue, LitToConstError, LitToConstInput, Scalar}; use rustc_middle::mir::*; use rustc_middle::thir::*; use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty, TyCtxt}; -use rustc_target::abi::Size; impl<'a, 'tcx> Builder<'a, 'tcx> { /// Compile `expr`, yielding a compile-time constant. Assumes that /// `expr` is a valid compile-time constant! - crate fn as_constant(&mut self, expr: &Expr<'tcx>) -> Constant<'tcx> { + pub(crate) fn as_constant(&mut self, expr: &Expr<'tcx>) -> Constant<'tcx> { let create_uneval_from_def_id = |tcx: TyCtxt<'tcx>, def_id: DefId, ty: Ty<'tcx>, substs: SubstsRef<'tcx>| { let uneval = ty::Unevaluated::new(ty::WithOptConstParam::unknown(def_id), substs); @@ -88,54 +84,3 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } } - -#[instrument(skip(tcx, lit_input))] -fn lit_to_mir_constant<'tcx>( - tcx: TyCtxt<'tcx>, - lit_input: LitToConstInput<'tcx>, -) -> Result, LitToConstError> { - let LitToConstInput { lit, ty, neg } = lit_input; - let trunc = |n| { - let param_ty = ty::ParamEnv::reveal_all().and(ty); - let width = tcx.layout_of(param_ty).map_err(|_| LitToConstError::Reported)?.size; - trace!("trunc {} with size {} and shift {}", n, width.bits(), 128 - width.bits()); - let result = width.truncate(n); - trace!("trunc result: {}", result); - Ok(ConstValue::Scalar(Scalar::from_uint(result, width))) - }; - - let value = match (lit, &ty.kind()) { - (ast::LitKind::Str(s, _), ty::Ref(_, inner_ty, _)) if inner_ty.is_str() => { - let s = s.as_str(); - let allocation = Allocation::from_bytes_byte_aligned_immutable(s.as_bytes()); - let allocation = tcx.intern_const_alloc(allocation); - ConstValue::Slice { data: allocation, start: 0, end: s.len() } - } - (ast::LitKind::ByteStr(data), ty::Ref(_, inner_ty, _)) - if matches!(inner_ty.kind(), ty::Slice(_)) => - { - let allocation = Allocation::from_bytes_byte_aligned_immutable(data as &[u8]); - let allocation = tcx.intern_const_alloc(allocation); - ConstValue::Slice { data: allocation, start: 0, end: data.len() } - } - (ast::LitKind::ByteStr(data), ty::Ref(_, inner_ty, _)) if inner_ty.is_array() => { - let id = tcx.allocate_bytes(data); - ConstValue::Scalar(Scalar::from_pointer(id.into(), &tcx)) - } - (ast::LitKind::Byte(n), ty::Uint(ty::UintTy::U8)) => { - ConstValue::Scalar(Scalar::from_uint(*n, Size::from_bytes(1))) - } - (ast::LitKind::Int(n, _), ty::Uint(_)) | (ast::LitKind::Int(n, _), ty::Int(_)) => { - trunc(if neg { (*n as i128).overflowing_neg().0 as u128 } else { *n })? - } - (ast::LitKind::Float(n, _), ty::Float(fty)) => { - parse_float(*n, *fty, neg).ok_or(LitToConstError::Reported)? - } - (ast::LitKind::Bool(b), ty::Bool) => ConstValue::Scalar(Scalar::from_bool(*b)), - (ast::LitKind::Char(c), ty::Char) => ConstValue::Scalar(Scalar::from_char(*c)), - (ast::LitKind::Err(_), _) => return Err(LitToConstError::Reported), - _ => return Err(LitToConstError::TypeError), - }; - - Ok(ConstantKind::Val(value, ty)) -} diff --git a/compiler/rustc_mir_build/src/build/expr/as_operand.rs b/compiler/rustc_mir_build/src/build/expr/as_operand.rs index 7eca49454ba38..e707c373f0dde 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_operand.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_operand.rs @@ -14,7 +14,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// after the current enclosing `ExprKind::Scope` has ended, so /// please do *not* return it from functions to avoid bad /// miscompiles. - crate fn as_local_operand( + pub(crate) fn as_local_operand( &mut self, block: BasicBlock, expr: &Expr<'tcx>, @@ -73,7 +73,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// value to the stack. /// /// See #68034 for more details. - crate fn as_local_call_operand( + pub(crate) fn as_local_call_operand( &mut self, block: BasicBlock, expr: &Expr<'tcx>, @@ -97,7 +97,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// Like `as_local_call_operand`, except that the argument will /// not be valid once `scope` ends. #[instrument(level = "debug", skip(self, scope))] - crate fn as_operand( + pub(crate) fn as_operand( &mut self, mut block: BasicBlock, scope: Option, @@ -132,7 +132,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - crate fn as_call_operand( + pub(crate) fn as_call_operand( &mut self, mut block: BasicBlock, scope: Option, 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 fa1bb0622bd11..045d6eb1c3021 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_place.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs @@ -21,7 +21,7 @@ use std::iter; /// The "outermost" place that holds this value. #[derive(Copy, Clone, Debug, PartialEq)] -crate enum PlaceBase { +pub(crate) enum PlaceBase { /// Denotes the start of a `Place`. Local(Local), @@ -71,7 +71,7 @@ crate enum PlaceBase { /// This is used internally when building a place for an expression like `a.b.c`. The fields `b` /// and `c` can be progressively pushed onto the place builder that is created when converting `a`. #[derive(Clone, Debug, PartialEq)] -crate struct PlaceBuilder<'tcx> { +pub(crate) struct PlaceBuilder<'tcx> { base: PlaceBase, projection: Vec>, } @@ -283,7 +283,7 @@ fn to_upvars_resolved_place_builder<'a, 'tcx>( } impl<'tcx> PlaceBuilder<'tcx> { - crate fn into_place<'a>( + pub(crate) fn into_place<'a>( self, tcx: TyCtxt<'tcx>, typeck_results: &'a ty::TypeckResults<'tcx>, @@ -314,7 +314,7 @@ impl<'tcx> PlaceBuilder<'tcx> { /// not captured. This can happen because the final mir that will be /// generated doesn't require a read for this place. Failures will only /// happen inside closures. - crate fn try_upvars_resolved<'a>( + pub(crate) fn try_upvars_resolved<'a>( self, tcx: TyCtxt<'tcx>, typeck_results: &'a ty::TypeckResults<'tcx>, @@ -322,19 +322,19 @@ impl<'tcx> PlaceBuilder<'tcx> { to_upvars_resolved_place_builder(self, tcx, typeck_results) } - crate fn base(&self) -> PlaceBase { + pub(crate) fn base(&self) -> PlaceBase { self.base } - crate fn field(self, f: Field, ty: Ty<'tcx>) -> Self { + pub(crate) fn field(self, f: Field, ty: Ty<'tcx>) -> Self { self.project(PlaceElem::Field(f, ty)) } - crate fn deref(self) -> Self { + pub(crate) fn deref(self) -> Self { self.project(PlaceElem::Deref) } - crate fn downcast(self, adt_def: AdtDef<'tcx>, variant_index: VariantIdx) -> Self { + pub(crate) fn downcast(self, adt_def: AdtDef<'tcx>, variant_index: VariantIdx) -> Self { self.project(PlaceElem::Downcast(Some(adt_def.variant(variant_index).name), variant_index)) } @@ -342,7 +342,7 @@ impl<'tcx> PlaceBuilder<'tcx> { self.project(PlaceElem::Index(index)) } - crate fn project(mut self, elem: PlaceElem<'tcx>) -> Self { + pub(crate) fn project(mut self, elem: PlaceElem<'tcx>) -> Self { self.projection.push(elem); self } @@ -373,7 +373,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// Extra care is needed if any user code is allowed to run between calling /// this method and using it, as is the case for `match` and index /// expressions. - crate fn as_place( + pub(crate) fn as_place( &mut self, mut block: BasicBlock, expr: &Expr<'tcx>, @@ -384,7 +384,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// This is used when constructing a compound `Place`, so that we can avoid creating /// intermediate `Place` values until we know the full set of projections. - crate fn as_place_builder( + pub(crate) fn as_place_builder( &mut self, block: BasicBlock, expr: &Expr<'tcx>, @@ -397,7 +397,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// place. The place itself may or may not be mutable: /// * If this expr is a place expr like a.b, then we will return that place. /// * Otherwise, a temporary is created: in that event, it will be an immutable temporary. - crate fn as_read_only_place( + pub(crate) fn as_read_only_place( &mut self, mut block: BasicBlock, expr: &Expr<'tcx>, 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 d807500f1fbdc..7d08b20631e47 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs @@ -11,6 +11,7 @@ use rustc_middle::mir::AssertKind; use rustc_middle::mir::Place; use rustc_middle::mir::*; use rustc_middle::thir::*; +use rustc_middle::ty::cast::CastTy; use rustc_middle::ty::{self, Ty, UpvarSubsts}; use rustc_span::Span; @@ -21,7 +22,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// The operand returned from this function will *not be valid* after /// an ExprKind::Scope is passed, so please do *not* return it from /// functions to avoid bad miscompiles. - crate fn as_local_rvalue( + pub(crate) fn as_local_rvalue( &mut self, block: BasicBlock, expr: &Expr<'tcx>, @@ -31,7 +32,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } /// Compile `expr`, yielding an rvalue. - crate fn as_rvalue( + pub(crate) fn as_rvalue( &mut self, mut block: BasicBlock, scope: Option, @@ -52,11 +53,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }) } ExprKind::Repeat { value, count } => { - let value_operand = unpack!( - block = - this.as_operand(block, scope, &this.thir[value], None, NeedsTemporary::No) - ); - block.and(Rvalue::Repeat(value_operand, count)) + if Some(0) == count.try_eval_usize(this.tcx, this.param_env) { + this.build_zero_repeat(block, value, scope, source_info) + } else { + let value_operand = unpack!( + block = this.as_operand( + block, + scope, + &this.thir[value], + None, + NeedsTemporary::No + ) + ); + block.and(Rvalue::Repeat(value_operand, count)) + } } ExprKind::Binary { op, lhs, rhs } => { let lhs = unpack!( @@ -141,7 +151,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { TerminatorKind::Call { func: exchange_malloc, args: vec![Operand::Move(size), Operand::Move(align)], - destination: Some((storage, success)), + destination: storage, + target: Some(success), cleanup: None, from_hir_call: false, fn_span: expr_span, @@ -178,11 +189,19 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block.and(Rvalue::Use(Operand::Move(Place::from(result)))) } ExprKind::Cast { source } => { + let source = &this.thir[source]; + let from_ty = CastTy::from_ty(source.ty); + let cast_ty = CastTy::from_ty(expr.ty); + let cast_kind = match (from_ty, cast_ty) { + (Some(CastTy::Ptr(_) | CastTy::FnPtr), Some(CastTy::Int(_))) => { + CastKind::PointerExposeAddress + } + (_, _) => CastKind::Misc, + }; let source = unpack!( - block = - this.as_operand(block, scope, &this.thir[source], None, NeedsTemporary::No) + block = this.as_operand(block, scope, source, None, NeedsTemporary::No) ); - block.and(Rvalue::Cast(CastKind::Misc, source, expr.ty)) + block.and(Rvalue::Cast(cast_kind, source, expr.ty)) } ExprKind::Pointer { cast, source } => { let source = unpack!( @@ -416,7 +435,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - crate fn build_binary_op( + pub(crate) fn build_binary_op( &mut self, mut block: BasicBlock, op: BinOp, @@ -515,6 +534,37 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } + fn build_zero_repeat( + &mut self, + mut block: BasicBlock, + value: ExprId, + scope: Option, + outer_source_info: SourceInfo, + ) -> BlockAnd> { + let this = self; + let value = &this.thir[value]; + let elem_ty = value.ty; + if let Some(Category::Constant) = Category::of(&value.kind) { + // Repeating a const does nothing + } else { + // For a non-const, we may need to generate an appropriate `Drop` + let value_operand = + unpack!(block = this.as_operand(block, scope, value, None, NeedsTemporary::No)); + if let Operand::Move(to_drop) = value_operand { + let success = this.cfg.start_new_block(); + this.cfg.terminate( + block, + outer_source_info, + TerminatorKind::Drop { place: to_drop, target: success, unwind: None }, + ); + this.diverge_from(block); + block = success; + } + this.record_operands_moved(&[value_operand]); + } + block.and(Rvalue::Aggregate(Box::new(AggregateKind::Array(elem_ty)), Vec::new())) + } + fn limit_capture_mutability( &mut self, upvar_span: Span, diff --git a/compiler/rustc_mir_build/src/build/expr/as_temp.rs b/compiler/rustc_mir_build/src/build/expr/as_temp.rs index 6067da2f69b48..724b72f8769b8 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_temp.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_temp.rs @@ -10,7 +10,7 @@ use rustc_middle::thir::*; impl<'a, 'tcx> Builder<'a, 'tcx> { /// Compile `expr` into a fresh temporary. This is used when building /// up rvalues so as to freeze the value that will be consumed. - crate fn as_temp( + pub(crate) fn as_temp( &mut self, block: BasicBlock, temp_lifetime: Option, diff --git a/compiler/rustc_mir_build/src/build/expr/category.rs b/compiler/rustc_mir_build/src/build/expr/category.rs index bcece39c6206e..b1a706439342e 100644 --- a/compiler/rustc_mir_build/src/build/expr/category.rs +++ b/compiler/rustc_mir_build/src/build/expr/category.rs @@ -1,7 +1,7 @@ use rustc_middle::thir::*; #[derive(Debug, PartialEq)] -crate enum Category { +pub(crate) enum Category { // An assignable memory location like `x`, `x.f`, `foo()[3]`, that // sort of thing. Something that could appear on the LHS of an `=` // sign. @@ -19,7 +19,7 @@ crate enum Category { // Rvalues fall into different "styles" that will determine which fn // is best suited to generate them. #[derive(Debug, PartialEq)] -crate enum RvalueFunc { +pub(crate) enum RvalueFunc { // Best generated by `into`. This is generally exprs that // cause branching, like `match`, but also includes calls. Into, @@ -31,7 +31,7 @@ crate enum RvalueFunc { /// Determines the category for a given expression. Note that scope /// and paren expressions have no category. impl Category { - crate fn of(ek: &ExprKind<'_>) -> Option { + pub(crate) fn of(ek: &ExprKind<'_>) -> Option { match *ek { ExprKind::Scope { .. } => None, diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs index 4399fdf8520a1..ccbb518e72d08 100644 --- a/compiler/rustc_mir_build/src/build/expr/into.rs +++ b/compiler/rustc_mir_build/src/build/expr/into.rs @@ -15,7 +15,7 @@ use std::iter; impl<'a, 'tcx> Builder<'a, 'tcx> { /// Compile `expr`, storing the result into `destination`, which /// is assumed to be uninitialized. - crate fn expr_into_dest( + pub(crate) fn expr_into_dest( &mut self, destination: Place<'tcx>, mut block: BasicBlock, @@ -255,18 +255,19 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { func: fun, args, cleanup: None, + destination, // The presence or absence of a return edge affects control-flow sensitive // MIR checks and ultimately whether code is accepted or not. We can only // omit the return edge if a return type is visibly uninhabited to a module // that makes the call. - destination: if this.tcx.is_ty_uninhabited_from( + target: if this.tcx.is_ty_uninhabited_from( this.parent_module, expr.ty, this.param_env, ) { None } else { - Some((destination, success)) + Some(success) }, from_hir_call, fn_span, @@ -434,11 +435,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } thir::InlineAsmOperand::SymFn { value, span } => { mir::InlineAsmOperand::SymFn { - value: Box::new(Constant { - span, - user_ty: None, - literal: value.into(), - }), + value: Box::new(Constant { span, user_ty: None, literal: value }), } } thir::InlineAsmOperand::SymStatic { def_id } => { diff --git a/compiler/rustc_mir_build/src/build/expr/mod.rs b/compiler/rustc_mir_build/src/build/expr/mod.rs index 7be435cda7db3..f5ae060d603f6 100644 --- a/compiler/rustc_mir_build/src/build/expr/mod.rs +++ b/compiler/rustc_mir_build/src/build/expr/mod.rs @@ -60,7 +60,7 @@ //! basically the point where the "by value" operations are bridged //! over to the "by reference" mode (`as_place`). -crate mod as_constant; +pub(crate) mod as_constant; mod as_operand; pub mod as_place; mod as_rvalue; diff --git a/compiler/rustc_mir_build/src/build/expr/stmt.rs b/compiler/rustc_mir_build/src/build/expr/stmt.rs index 46c616ff36241..a7e1331aabca3 100644 --- a/compiler/rustc_mir_build/src/build/expr/stmt.rs +++ b/compiler/rustc_mir_build/src/build/expr/stmt.rs @@ -10,7 +10,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// (e.g., `some().code(&here());`) then `opt_stmt_span` is the /// span of that statement (including its semicolon, if any). /// The scope is used if a statement temporary must be dropped. - crate fn stmt_expr( + pub(crate) fn stmt_expr( &mut self, mut block: BasicBlock, expr: &Expr<'tcx>, diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index fa5ec22926efc..15660365938a0 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -151,7 +151,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// /// * From each pre-binding block to the next pre-binding block. /// * From each otherwise block to the next pre-binding block. - crate fn match_expr( + #[tracing::instrument(level = "debug", skip(self, arms))] + pub(crate) fn match_expr( &mut self, destination: Place<'tcx>, span: Span, @@ -523,8 +524,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }, .. }, - ascription: - thir::Ascription { user_ty: pat_ascription_ty, variance: _, user_ty_span }, + ascription: thir::Ascription { annotation, variance: _ }, } => { let place = self.storage_live_binding(block, var, irrefutable_pat.span, OutsideGuard, true); @@ -535,18 +535,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let cause_let = FakeReadCause::ForLet(None); self.cfg.push_fake_read(block, pattern_source_info, cause_let, place); - let ty_source_info = self.source_info(user_ty_span); - let user_ty = pat_ascription_ty.user_ty( - &mut self.canonical_user_type_annotations, - place.ty(&self.local_decls, self.tcx).ty, - ty_source_info.span, - ); + let ty_source_info = self.source_info(annotation.span); + + let base = self.canonical_user_type_annotations.push(annotation); self.cfg.push( block, Statement { source_info: ty_source_info, kind: StatementKind::AscribeUserType( - Box::new((place, user_ty)), + Box::new((place, UserTypeProjection { base, projs: Vec::new() })), // We always use invariant as the variance here. This is because the // variance field from the ascription refers to the variance to use // when applying the type to the value being matched, but this @@ -577,7 +574,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - crate fn place_into_pattern( + pub(crate) fn place_into_pattern( &mut self, block: BasicBlock, irrefutable_pat: Pat<'tcx>, @@ -653,7 +650,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// scope for the bindings in these patterns, if such a scope had to be /// created. NOTE: Declaring the bindings should always be done in their /// drop scope. - crate fn declare_bindings( + pub(crate) fn declare_bindings( &mut self, mut visibility_scope: Option, scope_span: Span, @@ -690,7 +687,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { visibility_scope } - crate fn storage_live_binding( + pub(crate) fn storage_live_binding( &mut self, block: BasicBlock, var: HirId, @@ -709,7 +706,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Place::from(local_id) } - crate fn schedule_drop_for_binding(&mut self, var: HirId, span: Span, for_guard: ForGuard) { + pub(crate) fn schedule_drop_for_binding( + &mut self, + var: HirId, + span: Span, + for_guard: ForGuard, + ) { let local_id = self.var_local_id(var, for_guard); if let Some(region_scope) = self.region_scope_tree.var_scope(var.local_id) { self.schedule_drop(span, region_scope, local_id, DropKind::Value); @@ -784,7 +786,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { PatKind::AscribeUserType { ref subpattern, - ascription: thir::Ascription { ref user_ty, user_ty_span, variance: _ }, + ascription: thir::Ascription { ref annotation, variance: _ }, } => { // This corresponds to something like // @@ -794,16 +796,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // // Note that the variance doesn't apply here, as we are tracking the effect // of `user_ty` on any bindings contained with subpattern. - let annotation = CanonicalUserTypeAnnotation { - span: user_ty_span, - user_ty: user_ty.user_ty, - inferred_ty: subpattern.ty, - }; + let projection = UserTypeProjection { - base: self.canonical_user_type_annotations.push(annotation), + base: self.canonical_user_type_annotations.push(annotation.clone()), projs: Vec::new(), }; - let subpattern_user_ty = pattern_user_ty.push_projection(&projection, user_ty_span); + let subpattern_user_ty = + pattern_user_ty.push_projection(&projection, annotation.span); self.visit_primary_bindings(subpattern, subpattern_user_ty, f) } @@ -927,14 +926,13 @@ struct Binding<'tcx> { /// influence region inference. #[derive(Clone, Debug)] struct Ascription<'tcx> { - span: Span, source: Place<'tcx>, - user_ty: PatTyProj<'tcx>, + annotation: CanonicalUserTypeAnnotation<'tcx>, variance: ty::Variance, } #[derive(Clone, Debug)] -crate struct MatchPair<'pat, 'tcx> { +pub(crate) struct MatchPair<'pat, 'tcx> { // this place... place: PlaceBuilder<'tcx>, @@ -966,13 +964,13 @@ enum TestKind<'tcx> { /// /// For `bool` we always generate two edges, one for `true` and one for /// `false`. - options: FxIndexMap, u128>, + options: FxIndexMap, u128>, }, /// Test for equality with value, possibly after an unsizing coercion to /// `ty`, Eq { - value: ty::Const<'tcx>, + value: ConstantKind<'tcx>, // Integer types are handled by `SwitchInt`, and constants with ADT // types are converted back into patterns, so this can only be `&str`, // `&[T]`, `f32` or `f64`. @@ -991,7 +989,7 @@ enum TestKind<'tcx> { /// [`Test`] is just the test to perform; it does not include the value /// to be tested. #[derive(Debug)] -crate struct Test<'tcx> { +pub(crate) struct Test<'tcx> { span: Span, kind: TestKind<'tcx>, } @@ -999,7 +997,7 @@ crate struct Test<'tcx> { /// `ArmHasGuard` is a wrapper around a boolean flag. It indicates whether /// a match arm has a guard expression attached to it. #[derive(Copy, Clone, Debug)] -crate struct ArmHasGuard(crate bool); +pub(crate) struct ArmHasGuard(pub(crate) bool); /////////////////////////////////////////////////////////////////////////// // Main matching algorithm @@ -1769,7 +1767,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Pat binding - used for `let` and function parameters as well. impl<'a, 'tcx> Builder<'a, 'tcx> { - crate fn lower_let_expr( + pub(crate) fn lower_let_expr( &mut self, mut block: BasicBlock, expr: &Expr<'tcx>, @@ -1858,7 +1856,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { parent_bindings .iter() .flat_map(|(_, ascriptions)| ascriptions) - .chain(&candidate.ascriptions), + .cloned() + .chain(candidate.ascriptions), ); // rust-lang/rust#27282: The `autoref` business deserves some @@ -2062,32 +2061,24 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// Append `AscribeUserType` statements onto the end of `block` /// for each ascription - fn ascribe_types<'b>( + fn ascribe_types( &mut self, block: BasicBlock, - ascriptions: impl IntoIterator>, - ) where - 'tcx: 'b, - { + ascriptions: impl IntoIterator>, + ) { for ascription in ascriptions { - let source_info = self.source_info(ascription.span); - - debug!( - "adding user ascription at span {:?} of place {:?} and {:?}", - source_info.span, ascription.source, ascription.user_ty, - ); + let source_info = self.source_info(ascription.annotation.span); - let user_ty = ascription.user_ty.user_ty( - &mut self.canonical_user_type_annotations, - ascription.source.ty(&self.local_decls, self.tcx).ty, - source_info.span, - ); + let base = self.canonical_user_type_annotations.push(ascription.annotation); self.cfg.push( block, Statement { source_info, kind: StatementKind::AscribeUserType( - Box::new((ascription.source, user_ty)), + Box::new(( + ascription.source, + UserTypeProjection { base, projs: Vec::new() }, + )), ascription.variance, ), }, diff --git a/compiler/rustc_mir_build/src/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs index 7f53d9dd70502..b4a0c965d6b73 100644 --- a/compiler/rustc_mir_build/src/build/matches/simplify.rs +++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs @@ -152,15 +152,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { match *match_pair.pattern.kind { PatKind::AscribeUserType { ref subpattern, - ascription: thir::Ascription { variance, user_ty, user_ty_span }, + ascription: thir::Ascription { ref annotation, variance }, } => { // Apply the type ascription to the value at `match_pair.place`, which is the if let Ok(place_resolved) = match_pair.place.clone().try_upvars_resolved(self.tcx, self.typeck_results) { candidate.ascriptions.push(Ascription { - span: user_ty_span, - user_ty, + annotation: annotation.clone(), source: place_resolved.into_place(self.tcx, self.typeck_results), variance, }); @@ -228,9 +227,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { _ => (None, 0), }; if let Some((min, max, sz)) = range { - if let (Some(lo), Some(hi)) = - (lo.val().try_to_bits(sz), hi.val().try_to_bits(sz)) - { + if let (Some(lo), Some(hi)) = (lo.try_to_bits(sz), hi.try_to_bits(sz)) { // We want to compare ranges numerically, but the order of the bitwise // representation of signed integers does not match their numeric order. // Thus, to correct the ordering, we need to shift the range of signed diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs index d7993ce1cf4fa..3774a39503521 100644 --- a/compiler/rustc_mir_build/src/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -86,7 +86,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { test_place: &PlaceBuilder<'tcx>, candidate: &Candidate<'pat, 'tcx>, switch_ty: Ty<'tcx>, - options: &mut FxIndexMap, u128>, + options: &mut FxIndexMap, u128>, ) -> bool { let Some(match_pair) = candidate.match_pairs.iter().find(|mp| mp.place == *test_place) else { return false; @@ -264,7 +264,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ); } else if let [success, fail] = *make_target_blocks(self) { assert_eq!(value.ty(), ty); - let expect = self.literal_operand(test.span, value.into()); + let expect = self.literal_operand(test.span, value); let val = Operand::Copy(place); self.compare(block, success, fail, source_info, BinOp::Eq, expect, val); } else { @@ -277,8 +277,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let target_blocks = make_target_blocks(self); // Test `val` by computing `lo <= val && val <= hi`, using primitive comparisons. - let lo = self.literal_operand(test.span, lo.into()); - let hi = self.literal_operand(test.span, hi.into()); + let lo = self.literal_operand(test.span, lo); + let hi = self.literal_operand(test.span, hi); let val = Operand::Copy(place); let [success, fail] = *target_blocks else { @@ -366,11 +366,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block: BasicBlock, make_target_blocks: impl FnOnce(&mut Self) -> Vec, source_info: SourceInfo, - value: ty::Const<'tcx>, + value: ConstantKind<'tcx>, place: Place<'tcx>, mut ty: Ty<'tcx>, ) { - let mut expect = self.literal_operand(source_info.span, value.into()); + let mut expect = self.literal_operand(source_info.span, value); let mut val = Operand::Copy(place); // If we're using `b"..."` as a pattern, we need to insert an @@ -444,7 +444,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { literal: method, })), args: vec![val, expect], - destination: Some((eq_result, eq_block)), + destination: eq_result, + target: Some(eq_block), cleanup: None, from_hir_call: false, fn_span: source_info.span, @@ -760,7 +761,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { span_bug!(match_pair.pattern.span, "simplifyable pattern found: {:?}", match_pair.pattern) } - fn const_range_contains(&self, range: PatRange<'tcx>, value: ty::Const<'tcx>) -> Option { + fn const_range_contains( + &self, + range: PatRange<'tcx>, + value: ConstantKind<'tcx>, + ) -> Option { use std::cmp::Ordering::*; let tcx = self.tcx; @@ -777,7 +782,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fn values_not_contained_in_range( &self, range: PatRange<'tcx>, - options: &FxIndexMap, u128>, + options: &FxIndexMap, u128>, ) -> Option { for &val in options.keys() { if self.const_range_contains(range, val)? { diff --git a/compiler/rustc_mir_build/src/build/matches/util.rs b/compiler/rustc_mir_build/src/build/matches/util.rs index 88dd76e37c112..9a1e98d3bb18d 100644 --- a/compiler/rustc_mir_build/src/build/matches/util.rs +++ b/compiler/rustc_mir_build/src/build/matches/util.rs @@ -8,7 +8,7 @@ use smallvec::SmallVec; use std::convert::TryInto; impl<'a, 'tcx> Builder<'a, 'tcx> { - crate fn field_match_pairs<'pat>( + pub(crate) fn field_match_pairs<'pat>( &mut self, place: PlaceBuilder<'tcx>, subpatterns: &'pat [FieldPat<'tcx>], @@ -22,7 +22,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { .collect() } - crate fn prefix_slice_suffix<'pat>( + pub(crate) fn prefix_slice_suffix<'pat>( &mut self, match_pairs: &mut SmallVec<[MatchPair<'pat, 'tcx>; 1]>, place: &PlaceBuilder<'tcx>, @@ -79,7 +79,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// Creates a false edge to `imaginary_target` and a real edge to /// real_target. If `imaginary_target` is none, or is the same as the real /// target, a Goto is generated instead to simplify the generated MIR. - crate fn false_edges( + pub(crate) fn false_edges( &mut self, from_block: BasicBlock, real_target: BasicBlock, @@ -100,7 +100,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } impl<'pat, 'tcx> MatchPair<'pat, 'tcx> { - crate fn new(place: PlaceBuilder<'tcx>, pattern: &'pat Pat<'tcx>) -> MatchPair<'pat, 'tcx> { + pub(crate) fn new( + place: PlaceBuilder<'tcx>, + pattern: &'pat Pat<'tcx>, + ) -> MatchPair<'pat, 'tcx> { MatchPair { place, pattern } } } diff --git a/compiler/rustc_mir_build/src/build/misc.rs b/compiler/rustc_mir_build/src/build/misc.rs index 84762d602f8db..86f466ff7672e 100644 --- a/compiler/rustc_mir_build/src/build/misc.rs +++ b/compiler/rustc_mir_build/src/build/misc.rs @@ -3,7 +3,6 @@ use crate::build::Builder; -use rustc_middle::mir; use rustc_middle::mir::*; use rustc_middle::ty::{self, Ty}; use rustc_span::{Span, DUMMY_SP}; @@ -15,7 +14,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// /// N.B., **No cleanup is scheduled for this temporary.** You should /// call `schedule_drop` once the temporary is initialized. - crate fn temp(&mut self, ty: Ty<'tcx>, span: Span) -> Place<'tcx> { + pub(crate) fn temp(&mut self, ty: Ty<'tcx>, span: Span) -> Place<'tcx> { // Mark this local as internal to avoid temporaries with types not present in the // user's code resulting in ICEs from the generator transform. let temp = self.local_decls.push(LocalDecl::new(ty, span).internal()); @@ -26,10 +25,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// Convenience function for creating a literal operand, one /// without any user type annotation. - crate fn literal_operand( + pub(crate) fn literal_operand( &mut self, span: Span, - literal: mir::ConstantKind<'tcx>, + literal: ConstantKind<'tcx>, ) -> Operand<'tcx> { let constant = Box::new(Constant { span, user_ty: None, literal }); Operand::Constant(constant) @@ -37,13 +36,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Returns a zero literal operand for the appropriate type, works for // bool, char and integers. - crate fn zero_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> { + pub(crate) fn zero_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> { let literal = ConstantKind::from_bits(self.tcx, 0, ty::ParamEnv::empty().and(ty)); self.literal_operand(span, literal) } - crate fn push_usize( + pub(crate) fn push_usize( &mut self, block: BasicBlock, source_info: SourceInfo, @@ -64,7 +63,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { temp } - crate fn consume_by_copy_or_move(&self, place: Place<'tcx>) -> Operand<'tcx> { + pub(crate) fn consume_by_copy_or_move(&self, place: Place<'tcx>) -> Operand<'tcx> { let tcx = self.tcx; let ty = place.ty(&self.local_decls, tcx).ty; if !self.infcx.type_is_copy_modulo_regions(self.param_env, ty, DUMMY_SP) { diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index a9c8943ec1804..4ae74433df63d 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -1,7 +1,9 @@ use crate::build; use crate::build::expr::as_place::PlaceBuilder; use crate::build::scope::DropKind; +use crate::thir::constant::parse_float; use crate::thir::pattern::pat_from_hir; +use rustc_ast as ast; use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; @@ -11,17 +13,20 @@ use rustc_index::vec::{Idx, IndexVec}; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_middle::hir::place::PlaceBase as HirPlaceBase; use rustc_middle::middle::region; +use rustc_middle::mir::interpret::Allocation; +use rustc_middle::mir::interpret::{ConstValue, LitToConstError, LitToConstInput, Scalar}; use rustc_middle::mir::*; use rustc_middle::thir::{BindingMode, Expr, ExprId, LintLevel, PatKind, Thir}; use rustc_middle::ty::subst::Subst; use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeckResults}; use rustc_span::symbol::sym; use rustc_span::Span; +use rustc_target::abi::Size; use rustc_target::spec::abi::Abi; use super::lints; -crate fn mir_built<'tcx>( +pub(crate) fn mir_built<'tcx>( tcx: TyCtxt<'tcx>, def: ty::WithOptConstParam, ) -> &'tcx rustc_data_structures::steal::Steal> { @@ -260,6 +265,57 @@ fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam) -> Body<'_ }) } +#[instrument(skip(tcx, lit_input))] +pub(crate) fn lit_to_mir_constant<'tcx>( + tcx: TyCtxt<'tcx>, + lit_input: LitToConstInput<'tcx>, +) -> Result, LitToConstError> { + let LitToConstInput { lit, ty, neg } = lit_input; + let trunc = |n| { + let param_ty = ty::ParamEnv::reveal_all().and(ty); + let width = tcx.layout_of(param_ty).map_err(|_| LitToConstError::Reported)?.size; + trace!("trunc {} with size {} and shift {}", n, width.bits(), 128 - width.bits()); + let result = width.truncate(n); + trace!("trunc result: {}", result); + Ok(ConstValue::Scalar(Scalar::from_uint(result, width))) + }; + + let value = match (lit, &ty.kind()) { + (ast::LitKind::Str(s, _), ty::Ref(_, inner_ty, _)) if inner_ty.is_str() => { + let s = s.as_str(); + let allocation = Allocation::from_bytes_byte_aligned_immutable(s.as_bytes()); + let allocation = tcx.intern_const_alloc(allocation); + ConstValue::Slice { data: allocation, start: 0, end: s.len() } + } + (ast::LitKind::ByteStr(data), ty::Ref(_, inner_ty, _)) + if matches!(inner_ty.kind(), ty::Slice(_)) => + { + let allocation = Allocation::from_bytes_byte_aligned_immutable(data as &[u8]); + let allocation = tcx.intern_const_alloc(allocation); + ConstValue::Slice { data: allocation, start: 0, end: data.len() } + } + (ast::LitKind::ByteStr(data), ty::Ref(_, inner_ty, _)) if inner_ty.is_array() => { + let id = tcx.allocate_bytes(data); + ConstValue::Scalar(Scalar::from_pointer(id.into(), &tcx)) + } + (ast::LitKind::Byte(n), ty::Uint(ty::UintTy::U8)) => { + ConstValue::Scalar(Scalar::from_uint(*n, Size::from_bytes(1))) + } + (ast::LitKind::Int(n, _), ty::Uint(_)) | (ast::LitKind::Int(n, _), ty::Int(_)) => { + trunc(if neg { (*n as i128).overflowing_neg().0 as u128 } else { *n })? + } + (ast::LitKind::Float(n, _), ty::Float(fty)) => { + parse_float(*n, *fty, neg).ok_or(LitToConstError::Reported)? + } + (ast::LitKind::Bool(b), ty::Bool) => ConstValue::Scalar(Scalar::from_bool(*b)), + (ast::LitKind::Char(c), ty::Char) => ConstValue::Scalar(Scalar::from_char(*c)), + (ast::LitKind::Err(_), _) => return Err(LitToConstError::Reported), + _ => return Err(LitToConstError::TypeError), + }; + + Ok(ConstantKind::Val(value, ty)) +} + /////////////////////////////////////////////////////////////////////////// // BuildMir -- walks a crate, looking for fn items and methods to build MIR from diff --git a/compiler/rustc_mir_build/src/build/scope.rs b/compiler/rustc_mir_build/src/build/scope.rs index 465bd62406efe..b9fd8c50e6a04 100644 --- a/compiler/rustc_mir_build/src/build/scope.rs +++ b/compiler/rustc_mir_build/src/build/scope.rs @@ -177,7 +177,7 @@ struct IfThenScope { /// The target of an expression that breaks out of a scope #[derive(Clone, Copy, Debug)] -crate enum BreakableTarget { +pub(crate) enum BreakableTarget { Continue(region::Scope), Break(region::Scope), Return, @@ -445,7 +445,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // ========================== // Start a breakable scope, which tracks where `continue`, `break` and // `return` should branch to. - crate fn in_breakable_scope( + pub(crate) fn in_breakable_scope( &mut self, loop_block: Option, break_destination: Place<'tcx>, @@ -507,7 +507,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// - We don't need to keep a stack of scopes in the `Builder` because the /// 'else' paths will only leave the innermost scope. /// - This is also used for match guards. - crate fn in_if_then_scope( + pub(crate) fn in_if_then_scope( &mut self, region_scope: region::Scope, f: F, @@ -530,7 +530,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { (then_block, else_block) } - crate fn in_opt_scope( + pub(crate) fn in_opt_scope( &mut self, opt_scope: Option<(region::Scope, SourceInfo)>, f: F, @@ -553,7 +553,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// Convenience wrapper that pushes a scope and then executes `f` /// to build its contents, popping the scope afterwards. - crate fn in_scope( + pub(crate) fn in_scope( &mut self, region_scope: (region::Scope, SourceInfo), lint_level: LintLevel, @@ -597,14 +597,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// scope and call `pop_scope` afterwards. Note that these two /// calls must be paired; using `in_scope` as a convenience /// wrapper maybe preferable. - crate fn push_scope(&mut self, region_scope: (region::Scope, SourceInfo)) { + pub(crate) fn push_scope(&mut self, region_scope: (region::Scope, SourceInfo)) { self.scopes.push_scope(region_scope, self.source_scope); } /// Pops a scope, which should have region scope `region_scope`, /// adding any drops onto the end of `block` that are needed. /// This must match 1-to-1 with `push_scope`. - crate fn pop_scope( + pub(crate) fn pop_scope( &mut self, region_scope: (region::Scope, SourceInfo), mut block: BasicBlock, @@ -619,7 +619,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } /// Sets up the drops for breaking from `block` to `target`. - crate fn break_scope( + pub(crate) fn break_scope( &mut self, mut block: BasicBlock, value: Option<&Expr<'tcx>>, @@ -698,7 +698,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.cfg.start_new_block().unit() } - crate fn break_for_else( + pub(crate) fn break_for_else( &mut self, block: BasicBlock, target: region::Scope, @@ -756,7 +756,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } /// Creates a new source scope, nested in the current one. - crate fn new_source_scope( + pub(crate) fn new_source_scope( &mut self, span: Span, lint_level: LintLevel, @@ -791,7 +791,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } /// Given a span and the current source scope, make a SourceInfo. - crate fn source_info(&self, span: Span) -> SourceInfo { + pub(crate) fn source_info(&self, span: Span) -> SourceInfo { SourceInfo { span, scope: self.source_scope } } @@ -816,13 +816,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// We would allocate the box but then free it on the unwinding /// path; we would also emit a free on the 'success' path from /// panic, but that will turn out to be removed as dead-code. - crate fn local_scope(&self) -> region::Scope { + pub(crate) fn local_scope(&self) -> region::Scope { self.scopes.topmost() } // Scheduling drops // ================ - crate fn schedule_drop_storage_and_value( + pub(crate) fn schedule_drop_storage_and_value( &mut self, span: Span, region_scope: region::Scope, @@ -836,7 +836,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// /// When called with `DropKind::Storage`, `place` shouldn't be the return /// place, or a function parameter. - crate fn schedule_drop( + pub(crate) fn schedule_drop( &mut self, span: Span, region_scope: region::Scope, @@ -969,7 +969,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// spurious borrow-check errors -- the problem, ironically, is /// not the `DROP(_X)` itself, but the (spurious) unwind pathways /// that it creates. See #64391 for an example. - crate fn record_operands_moved(&mut self, operands: &[Operand<'tcx>]) { + pub(crate) fn record_operands_moved(&mut self, operands: &[Operand<'tcx>]) { let local_scope = self.local_scope(); let scope = self.scopes.scopes.last_mut().unwrap(); @@ -1026,12 +1026,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// /// This path terminates in Resume. The path isn't created until after all /// of the non-unwind paths in this item have been lowered. - crate fn diverge_from(&mut self, start: BasicBlock) { + pub(crate) fn diverge_from(&mut self, start: BasicBlock) { debug_assert!( matches!( self.cfg.block_data(start).terminator().kind, TerminatorKind::Assert { .. } | TerminatorKind::Call { .. } + | TerminatorKind::Drop { .. } | TerminatorKind::DropAndReplace { .. } | TerminatorKind::FalseUnwind { .. } | TerminatorKind::InlineAsm { .. } @@ -1048,7 +1049,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// [TerminatorKind::Yield]. /// /// This path terminates in GeneratorDrop. - crate fn generator_drop_cleanup(&mut self, yield_block: BasicBlock) { + pub(crate) fn generator_drop_cleanup(&mut self, yield_block: BasicBlock) { debug_assert!( matches!( self.cfg.block_data(yield_block).terminator().kind, @@ -1078,7 +1079,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } /// Utility function for *non*-scope code to build their own drops - crate fn build_drop_and_replace( + pub(crate) fn build_drop_and_replace( &mut self, block: BasicBlock, span: Span, @@ -1101,7 +1102,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// Creates an `Assert` terminator and return the success block. /// If the boolean condition operand is not the expected value, /// a runtime panic will be caused with the given message. - crate fn assert( + pub(crate) fn assert( &mut self, block: BasicBlock, cond: Operand<'tcx>, @@ -1126,7 +1127,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// /// This is only needed for `match` arm scopes, because they have one /// entrance per pattern, but only one exit. - crate fn clear_top_scope(&mut self, region_scope: region::Scope) { + pub(crate) fn clear_top_scope(&mut self, region_scope: region::Scope) { let top_scope = self.scopes.scopes.last_mut().unwrap(); assert_eq!(top_scope.region_scope, region_scope); @@ -1262,7 +1263,7 @@ impl<'a, 'tcx: 'a> Builder<'a, 'tcx> { } /// Build the unwind and generator drop trees. - crate fn build_drop_trees(&mut self) { + pub(crate) fn build_drop_trees(&mut self) { if self.generator_kind.is_some() { self.build_generator_drop_trees(); } else { diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index 6c14f207a7d14..94b2722dca86d 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -678,7 +678,7 @@ pub fn check_unsafety<'tcx>(tcx: TyCtxt<'tcx>, def: ty::WithOptConstParam(tcx: TyCtxt<'tcx>, def_id: LocalDefId) { +pub(crate) fn thir_check_unsafety<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) { if let Some(def) = ty::WithOptConstParam::try_lookup(def_id, tcx) { tcx.thir_check_unsafety_for_const_arg(def) } else { @@ -686,7 +686,7 @@ crate fn thir_check_unsafety<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) { } } -crate fn thir_check_unsafety_for_const_arg<'tcx>( +pub(crate) fn thir_check_unsafety_for_const_arg<'tcx>( tcx: TyCtxt<'tcx>, (did, param_did): (LocalDefId, DefId), ) { diff --git a/compiler/rustc_mir_build/src/lib.rs b/compiler/rustc_mir_build/src/lib.rs index 4ffee59a96274..11cd2a9aa4dea 100644 --- a/compiler/rustc_mir_build/src/lib.rs +++ b/compiler/rustc_mir_build/src/lib.rs @@ -4,7 +4,6 @@ #![allow(rustc::potential_query_instability)] #![feature(box_patterns)] #![feature(control_flow_enum)] -#![feature(crate_visibility_modifier)] #![feature(if_let_guard)] #![feature(let_chains)] #![feature(let_else)] @@ -27,6 +26,7 @@ use rustc_middle::ty::query::Providers; pub fn provide(providers: &mut Providers) { providers.check_match = thir::pattern::check_match; providers.lit_to_const = thir::constant::lit_to_const; + providers.lit_to_mir_constant = build::lit_to_mir_constant; providers.mir_built = build::mir_built; providers.thir_check_unsafety = check_unsafety::thir_check_unsafety; providers.thir_check_unsafety_for_const_arg = check_unsafety::thir_check_unsafety_for_const_arg; diff --git a/compiler/rustc_mir_build/src/lints.rs b/compiler/rustc_mir_build/src/lints.rs index bccff37987348..5470cc1262e84 100644 --- a/compiler/rustc_mir_build/src/lints.rs +++ b/compiler/rustc_mir_build/src/lints.rs @@ -9,7 +9,7 @@ use rustc_session::lint::builtin::UNCONDITIONAL_RECURSION; use rustc_span::Span; use std::ops::ControlFlow; -crate fn check<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) { +pub(crate) fn check<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) { let def_id = body.source.def_id().expect_local(); if let Some(fn_kind) = tcx.hir().get_by_def_id(def_id).fn_kind() { diff --git a/compiler/rustc_mir_build/src/thir/constant.rs b/compiler/rustc_mir_build/src/thir/constant.rs index 30d7fdb7fec36..d82e6688633d0 100644 --- a/compiler/rustc_mir_build/src/thir/constant.rs +++ b/compiler/rustc_mir_build/src/thir/constant.rs @@ -8,7 +8,7 @@ use rustc_span::symbol::Symbol; use rustc_target::abi::Size; // FIXME Once valtrees are available, get rid of this function and the query -crate fn lit_to_const<'tcx>( +pub(crate) fn lit_to_const<'tcx>( tcx: TyCtxt<'tcx>, lit_input: LitToConstInput<'tcx>, ) -> Result, LitToConstError> { diff --git a/compiler/rustc_mir_build/src/thir/cx/block.rs b/compiler/rustc_mir_build/src/thir/cx/block.rs index 2d9b5c1d98aab..59750d5d0b88e 100644 --- a/compiler/rustc_mir_build/src/thir/cx/block.rs +++ b/compiler/rustc_mir_build/src/thir/cx/block.rs @@ -6,9 +6,10 @@ use rustc_middle::thir::*; use rustc_middle::ty; use rustc_index::vec::Idx; +use rustc_middle::ty::CanonicalUserTypeAnnotation; impl<'tcx> Cx<'tcx> { - crate fn mirror_block(&mut self, block: &'tcx hir::Block<'tcx>) -> Block { + pub(crate) fn mirror_block(&mut self, block: &'tcx hir::Block<'tcx>) -> Block { // We have to eagerly lower the "spine" of the statements // in order to get the lexical scoping correctly. let stmts = self.mirror_stmts(block.hir_id.local_id, block.stmts); @@ -74,19 +75,24 @@ impl<'tcx> Cx<'tcx> { }; let mut pattern = self.pattern_from_hir(local.pat); + debug!(?pattern); if let Some(ty) = &local.ty { if let Some(&user_ty) = self.typeck_results.user_provided_types().get(ty.hir_id) { debug!("mirror_stmts: user_ty={:?}", user_ty); + let annotation = CanonicalUserTypeAnnotation { + user_ty, + span: ty.span, + inferred_ty: self.typeck_results.node_type(ty.hir_id), + }; pattern = Pat { ty: pattern.ty, span: pattern.span, kind: Box::new(PatKind::AscribeUserType { ascription: Ascription { - user_ty: PatTyProj::from_user_type(user_ty), - user_ty_span: ty.span, + annotation, variance: ty::Variance::Covariant, }, subpattern: pattern, diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 147c136e651dd..480c5b195cc2d 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -22,17 +22,18 @@ use rustc_span::Span; use rustc_target::abi::VariantIdx; impl<'tcx> Cx<'tcx> { - crate fn mirror_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) -> ExprId { + pub(crate) fn mirror_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) -> ExprId { // `mirror_expr` is recursing very deep. Make sure the stack doesn't overflow. ensure_sufficient_stack(|| self.mirror_expr_inner(expr)) } - crate fn mirror_exprs(&mut self, exprs: &'tcx [hir::Expr<'tcx>]) -> Box<[ExprId]> { + pub(crate) fn mirror_exprs(&mut self, exprs: &'tcx [hir::Expr<'tcx>]) -> Box<[ExprId]> { exprs.iter().map(|expr| self.mirror_expr_inner(expr)).collect() } pub(super) fn mirror_expr_inner(&mut self, hir_expr: &'tcx hir::Expr<'tcx>) -> ExprId { - let temp_lifetime = self.region_scope_tree.temporary_scope(hir_expr.hir_id.local_id); + let temp_lifetime = + self.rvalue_scopes.temporary_scope(self.region_scope_tree, hir_expr.hir_id.local_id); let expr_scope = region::Scope { id: hir_expr.hir_id.local_id, data: region::ScopeData::Node }; @@ -161,7 +162,8 @@ impl<'tcx> Cx<'tcx> { let tcx = self.tcx; let expr_ty = self.typeck_results().expr_ty(expr); let expr_span = expr.span; - let temp_lifetime = self.region_scope_tree.temporary_scope(expr.hir_id.local_id); + let temp_lifetime = + self.rvalue_scopes.temporary_scope(self.region_scope_tree, expr.hir_id.local_id); let kind = match expr.kind { // Here comes the interesting stuff: @@ -575,7 +577,9 @@ impl<'tcx> Cx<'tcx> { }, hir::ExprKind::Loop(ref body, ..) => { let block_ty = self.typeck_results().node_type(body.hir_id); - let temp_lifetime = self.region_scope_tree.temporary_scope(body.hir_id.local_id); + let temp_lifetime = self + .rvalue_scopes + .temporary_scope(self.region_scope_tree, body.hir_id.local_id); let block = self.mirror_block(body); let body = self.thir.exprs.push(Expr { ty: block_ty, @@ -776,7 +780,8 @@ impl<'tcx> Cx<'tcx> { span: Span, overloaded_callee: Option<(DefId, SubstsRef<'tcx>)>, ) -> Expr<'tcx> { - let temp_lifetime = self.region_scope_tree.temporary_scope(expr.hir_id.local_id); + let temp_lifetime = + self.rvalue_scopes.temporary_scope(self.region_scope_tree, expr.hir_id.local_id); let (def_id, substs, user_ty) = match overloaded_callee { Some((def_id, substs)) => (def_id, substs, None), None => { @@ -798,8 +803,8 @@ impl<'tcx> Cx<'tcx> { pattern: self.pattern_from_hir(&arm.pat), guard: arm.guard.as_ref().map(|g| match g { hir::Guard::If(ref e) => Guard::If(self.mirror_expr(e)), - hir::Guard::IfLet(ref pat, ref e) => { - Guard::IfLet(self.pattern_from_hir(pat), self.mirror_expr(e)) + hir::Guard::IfLet(ref l) => { + Guard::IfLet(self.pattern_from_hir(l.pat), self.mirror_expr(l.init)) } }), body: self.mirror_expr(arm.body), @@ -863,7 +868,9 @@ impl<'tcx> Cx<'tcx> { // a constant reference (or constant raw pointer for `static mut`) in MIR Res::Def(DefKind::Static(_), id) => { let ty = self.tcx.static_ptr_ty(id); - let temp_lifetime = self.region_scope_tree.temporary_scope(expr.hir_id.local_id); + let temp_lifetime = self + .rvalue_scopes + .temporary_scope(self.region_scope_tree, expr.hir_id.local_id); let kind = if self.tcx.is_thread_local_static(id) { ExprKind::ThreadLocalRef(id) } else { @@ -939,7 +946,8 @@ impl<'tcx> Cx<'tcx> { // construct the complete expression `foo()` for the overloaded call, // which will yield the &T type - let temp_lifetime = self.region_scope_tree.temporary_scope(expr.hir_id.local_id); + let temp_lifetime = + self.rvalue_scopes.temporary_scope(self.region_scope_tree, expr.hir_id.local_id); let fun = self.method_callee(expr, span, overloaded_callee); let fun = self.thir.exprs.push(fun); let fun_ty = self.thir[fun].ty; @@ -959,7 +967,9 @@ impl<'tcx> Cx<'tcx> { closure_expr: &'tcx hir::Expr<'tcx>, place: HirPlace<'tcx>, ) -> Expr<'tcx> { - let temp_lifetime = self.region_scope_tree.temporary_scope(closure_expr.hir_id.local_id); + let temp_lifetime = self + .rvalue_scopes + .temporary_scope(self.region_scope_tree, closure_expr.hir_id.local_id); let var_ty = place.base_ty; // The result of capture analysis in `rustc_typeck/check/upvar.rs`represents a captured path @@ -1014,7 +1024,9 @@ impl<'tcx> Cx<'tcx> { let upvar_capture = captured_place.info.capture_kind; let captured_place_expr = self.convert_captured_hir_place(closure_expr, captured_place.place.clone()); - let temp_lifetime = self.region_scope_tree.temporary_scope(closure_expr.hir_id.local_id); + let temp_lifetime = self + .rvalue_scopes + .temporary_scope(self.region_scope_tree, closure_expr.hir_id.local_id); match upvar_capture { ty::UpvarCapture::ByValue => captured_place_expr, diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs index f17fe38b292cb..d853a5e9ee797 100644 --- a/compiler/rustc_mir_build/src/thir/cx/mod.rs +++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs @@ -5,6 +5,7 @@ use crate::thir::pattern::pat_from_hir; use crate::thir::util::UserAnnotatedTyHelpers; +use rustc_ast as ast; use rustc_data_structures::steal::Steal; use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; @@ -12,11 +13,13 @@ use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::HirId; use rustc_hir::Node; use rustc_middle::middle::region; +use rustc_middle::mir::interpret::{LitToConstError, LitToConstInput}; +use rustc_middle::mir::ConstantKind; use rustc_middle::thir::*; -use rustc_middle::ty::{self, TyCtxt}; +use rustc_middle::ty::{self, RvalueScopes, Ty, TyCtxt}; use rustc_span::Span; -crate fn thir_body<'tcx>( +pub(crate) fn thir_body<'tcx>( tcx: TyCtxt<'tcx>, owner_def: ty::WithOptConstParam, ) -> Result<(&'tcx Steal>, ExprId), ErrorGuaranteed> { @@ -30,7 +33,7 @@ crate fn thir_body<'tcx>( Ok((tcx.alloc_steal_thir(cx.thir), expr)) } -crate fn thir_tree<'tcx>( +pub(crate) fn thir_tree<'tcx>( tcx: TyCtxt<'tcx>, owner_def: ty::WithOptConstParam, ) -> String { @@ -44,10 +47,11 @@ struct Cx<'tcx> { tcx: TyCtxt<'tcx>, thir: Thir<'tcx>, - crate param_env: ty::ParamEnv<'tcx>, + pub(crate) param_env: ty::ParamEnv<'tcx>, - crate region_scope_tree: &'tcx region::ScopeTree, - crate typeck_results: &'tcx ty::TypeckResults<'tcx>, + pub(crate) region_scope_tree: &'tcx region::ScopeTree, + pub(crate) typeck_results: &'tcx ty::TypeckResults<'tcx>, + pub(crate) rvalue_scopes: &'tcx RvalueScopes, /// When applying adjustments to the expression /// with the given `HirId`, use the given `Span`, @@ -70,12 +74,32 @@ impl<'tcx> Cx<'tcx> { param_env: tcx.param_env(def.did), region_scope_tree: tcx.region_scope_tree(def.did), typeck_results, + rvalue_scopes: &typeck_results.rvalue_scopes, body_owner: def.did.to_def_id(), adjustment_span: None, } } - crate fn pattern_from_hir(&mut self, p: &hir::Pat<'_>) -> Pat<'tcx> { + #[instrument(skip(self), level = "debug")] + pub(crate) fn const_eval_literal( + &mut self, + lit: &'tcx ast::LitKind, + ty: Ty<'tcx>, + sp: Span, + neg: bool, + ) -> ConstantKind<'tcx> { + match self.tcx.at(sp).lit_to_mir_constant(LitToConstInput { lit, ty, neg }) { + Ok(c) => c, + Err(LitToConstError::Reported) => { + // create a dummy value and continue compiling + ConstantKind::Ty(self.tcx.const_error(ty)) + } + Err(LitToConstError::TypeError) => bug!("const_eval_literal: had type error"), + } + } + + #[tracing::instrument(level = "debug", skip(self))] + pub(crate) fn pattern_from_hir(&mut self, p: &hir::Pat<'_>) -> Pat<'tcx> { let p = match self.tcx.hir().get(p.hir_id) { Node::Pat(p) | Node::Binding(p) => p, node => bug!("pattern became {:?}", node), diff --git a/compiler/rustc_mir_build/src/thir/mod.rs b/compiler/rustc_mir_build/src/thir/mod.rs index ddbe1b0b69c1e..e0e6ac26654ab 100644 --- a/compiler/rustc_mir_build/src/thir/mod.rs +++ b/compiler/rustc_mir_build/src/thir/mod.rs @@ -4,10 +4,10 @@ //! unit-tested and separated from the Rust source and compiler data //! structures. -crate mod constant; +pub(crate) mod constant; -crate mod cx; +pub(crate) mod cx; -crate mod pattern; +pub(crate) mod pattern; mod util; diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index 58e484e413dab..dc204eb47aefa 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -23,7 +23,7 @@ use rustc_session::Session; use rustc_span::source_map::Spanned; use rustc_span::{BytePos, DesugaringKind, ExpnKind, Span}; -crate fn check_match(tcx: TyCtxt<'_>, def_id: DefId) { +pub(crate) fn check_match(tcx: TyCtxt<'_>, def_id: DefId) { let body_id = match def_id.as_local() { None => return, Some(id) => tcx.hir().body_owned_by(tcx.hir().local_def_id_to_hir_id(id)), @@ -173,10 +173,10 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { for arm in hir_arms { // Check the arm for some things unrelated to exhaustiveness. self.check_patterns(&arm.pat, Refutable); - if let Some(hir::Guard::IfLet(ref pat, _)) = arm.guard { - self.check_patterns(pat, Refutable); - let tpat = self.lower_pattern(&mut cx, pat, &mut false); - self.check_let_reachability(&mut cx, pat.hir_id, tpat, tpat.span()); + if let Some(hir::Guard::IfLet(ref let_expr)) = arm.guard { + self.check_patterns(let_expr.pat, Refutable); + let tpat = self.lower_pattern(&mut cx, let_expr.pat, &mut false); + self.check_let_reachability(&mut cx, let_expr.pat.hir_id, tpat, tpat.span()); } } @@ -880,7 +880,7 @@ fn non_exhaustive_match<'p, 'tcx>( err.emit(); } -crate fn joined_uncovered_patterns<'p, 'tcx>( +pub(crate) fn joined_uncovered_patterns<'p, 'tcx>( cx: &MatchCheckCtxt<'p, 'tcx>, witnesses: &[DeconstructedPat<'p, 'tcx>], ) -> String { @@ -901,7 +901,7 @@ crate fn joined_uncovered_patterns<'p, 'tcx>( } } -crate fn pattern_not_covered_label( +pub(crate) fn pattern_not_covered_label( witnesses: &[DeconstructedPat<'_, '_>], joined_patterns: &str, ) -> String { @@ -1108,9 +1108,9 @@ fn let_source_parent(tcx: TyCtxt<'_>, parent: HirId, pat_id: Option) -> L match parent_node { hir::Node::Arm(hir::Arm { - guard: Some(hir::Guard::IfLet(&hir::Pat { hir_id, .. }, _)), + guard: Some(hir::Guard::IfLet(&hir::Let { pat: hir::Pat { hir_id, .. }, .. })), .. - }) if Some(hir_id) == pat_id => { + }) if Some(*hir_id) == pat_id => { return LetSource::IfLetGuard; } hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Let(..), span, .. }) => { diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index 2298cc7cddf47..f694e009ab957 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -1,7 +1,7 @@ use rustc_hir as hir; use rustc_index::vec::Idx; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; -use rustc_middle::mir::Field; +use rustc_middle::mir::{self, Field}; use rustc_middle::thir::{FieldPat, Pat, PatKind}; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt}; @@ -22,7 +22,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { #[instrument(level = "debug", skip(self))] pub(super) fn const_to_pat( &self, - cv: ty::Const<'tcx>, + cv: mir::ConstantKind<'tcx>, id: hir::HirId, span: Span, mir_structural_match_violation: bool, @@ -121,27 +121,27 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { fn search_for_structural_match_violation(&self, ty: Ty<'tcx>) -> Option { traits::search_for_structural_match_violation(self.span, self.tcx(), ty).map(|non_sm_ty| { - with_no_trimmed_paths!(match non_sm_ty { - traits::NonStructuralMatchTy::Adt(adt) => self.adt_derive_msg(adt), - traits::NonStructuralMatchTy::Dynamic => { + with_no_trimmed_paths!(match non_sm_ty.kind { + traits::NonStructuralMatchTyKind::Adt(adt) => self.adt_derive_msg(adt), + traits::NonStructuralMatchTyKind::Dynamic => { "trait objects cannot be used in patterns".to_string() } - traits::NonStructuralMatchTy::Opaque => { + traits::NonStructuralMatchTyKind::Opaque => { "opaque types cannot be used in patterns".to_string() } - traits::NonStructuralMatchTy::Closure => { + traits::NonStructuralMatchTyKind::Closure => { "closures cannot be used in patterns".to_string() } - traits::NonStructuralMatchTy::Generator => { + traits::NonStructuralMatchTyKind::Generator => { "generators cannot be used in patterns".to_string() } - traits::NonStructuralMatchTy::Param => { + traits::NonStructuralMatchTyKind::Param => { bug!("use of a constant whose type is a parameter inside a pattern") } - traits::NonStructuralMatchTy::Projection => { + traits::NonStructuralMatchTyKind::Projection => { bug!("use of a constant whose type is a projection inside a pattern") } - traits::NonStructuralMatchTy::Foreign => { + traits::NonStructuralMatchTyKind::Foreign => { bug!("use of a value of a foreign type inside a pattern") } }) @@ -152,7 +152,11 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { ty.is_structural_eq_shallow(self.infcx.tcx) } - fn to_pat(&mut self, cv: ty::Const<'tcx>, mir_structural_match_violation: bool) -> Pat<'tcx> { + fn to_pat( + &mut self, + cv: mir::ConstantKind<'tcx>, + mir_structural_match_violation: bool, + ) -> Pat<'tcx> { trace!(self.treat_byte_string_as_slice); // This method is just a wrapper handling a validity check; the heavy lifting is // performed by the recursive `recur` method, which is not meant to be @@ -246,7 +250,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { fn field_pats( &self, - vals: impl Iterator>, + vals: impl Iterator>, ) -> Result>, FallbackToConstRef> { vals.enumerate() .map(|(idx, val)| { @@ -257,9 +261,10 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { } // Recursive helper for `to_pat`; invoke that (instead of calling this directly). + #[instrument(skip(self), level = "debug")] fn recur( &self, - cv: ty::Const<'tcx>, + cv: mir::ConstantKind<'tcx>, mir_structural_match_violation: bool, ) -> Result, FallbackToConstRef> { let id = self.id; @@ -365,7 +370,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { PatKind::Wild } ty::Adt(adt_def, substs) if adt_def.is_enum() => { - let destructured = tcx.destructure_const(param_env.and(cv)); + let destructured = tcx.destructure_mir_constant(param_env, cv); PatKind::Variant { adt_def: *adt_def, substs, @@ -376,12 +381,12 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { } } ty::Tuple(_) | ty::Adt(_, _) => { - let destructured = tcx.destructure_const(param_env.and(cv)); + let destructured = tcx.destructure_mir_constant(param_env, cv); PatKind::Leaf { subpatterns: self.field_pats(destructured.fields.iter().copied())? } } ty::Array(..) => PatKind::Array { prefix: tcx - .destructure_const(param_env.and(cv)) + .destructure_mir_constant(param_env, cv) .fields .iter() .map(|val| self.recur(*val, false)) @@ -412,12 +417,12 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { // arrays. ty::Array(..) if !self.treat_byte_string_as_slice => { let old = self.behind_reference.replace(true); - let array = tcx.deref_const(self.param_env.and(cv)); + let array = tcx.deref_mir_constant(self.param_env.and(cv)); let val = PatKind::Deref { subpattern: Pat { kind: Box::new(PatKind::Array { prefix: tcx - .destructure_const(param_env.and(array)) + .destructure_mir_constant(param_env, array) .fields .iter() .map(|val| self.recur(*val, false)) @@ -438,12 +443,12 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { // pattern. ty::Slice(elem_ty) => { let old = self.behind_reference.replace(true); - let array = tcx.deref_const(self.param_env.and(cv)); + let array = tcx.deref_mir_constant(self.param_env.and(cv)); let val = PatKind::Deref { subpattern: Pat { kind: Box::new(PatKind::Slice { prefix: tcx - .destructure_const(param_env.and(array)) + .destructure_mir_constant(param_env, array) .fields .iter() .map(|val| self.recur(*val, false)) @@ -512,7 +517,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { // we fall back to a const pattern. If we do not do this, we may end up with // a !structural-match constant that is not of reference type, which makes it // very hard to invoke `PartialEq::eq` on it as a fallback. - let val = match self.recur(tcx.deref_const(self.param_env.and(cv)), false) { + let val = match self.recur(tcx.deref_mir_constant(self.param_env.and(cv)), false) { Ok(subpattern) => PatKind::Deref { subpattern }, Err(_) => PatKind::Constant { value: cv }, }; diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs index 60eead69a1b05..b7de3f28872e5 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs @@ -52,7 +52,7 @@ use rustc_data_structures::captures::Captures; use rustc_index::vec::Idx; use rustc_hir::{HirId, RangeEnd}; -use rustc_middle::mir::Field; +use rustc_middle::mir::{self, Field}; use rustc_middle::thir::{FieldPat, Pat, PatKind, PatRange}; use rustc_middle::ty::layout::IntegerExt; use rustc_middle::ty::{self, Ty, TyCtxt, VariantDef}; @@ -133,23 +133,35 @@ impl IntRange { } #[inline] - fn from_const<'tcx>( + fn from_constant<'tcx>( tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, - value: ty::Const<'tcx>, + value: mir::ConstantKind<'tcx>, ) -> Option { let ty = value.ty(); if let Some((target_size, bias)) = Self::integral_size_and_signed_bias(tcx, ty) { let val = (|| { - if let ty::ConstKind::Value(ConstValue::Scalar(scalar)) = value.val() { - // For this specific pattern we can skip a lot of effort and go - // straight to the result, after doing a bit of checking. (We - // could remove this branch and just fall through, which - // is more general but much slower.) - if let Ok(bits) = scalar.to_bits_or_ptr_internal(target_size).unwrap() { - return Some(bits); + match value { + mir::ConstantKind::Val(ConstValue::Scalar(scalar), _) => { + // For this specific pattern we can skip a lot of effort and go + // straight to the result, after doing a bit of checking. (We + // could remove this branch and just fall through, which + // is more general but much slower.) + if let Ok(Ok(bits)) = scalar.to_bits_or_ptr_internal(target_size) { + return Some(bits); + } else { + return None; + } } + mir::ConstantKind::Ty(c) => match c.val() { + ty::ConstKind::Value(_) => bug!( + "encountered ConstValue in mir::ConstantKind::Ty, whereas this is expected to be in ConstantKind::Val" + ), + _ => {} + }, + _ => {} } + // This is a more general form of the previous case. value.try_eval_bits(tcx, param_env, ty) })()?; @@ -234,8 +246,8 @@ impl IntRange { let (lo, hi) = (lo ^ bias, hi ^ bias); let env = ty::ParamEnv::empty().and(ty); - let lo_const = ty::Const::from_bits(tcx, lo, env); - let hi_const = ty::Const::from_bits(tcx, hi, env); + let lo_const = mir::ConstantKind::from_bits(tcx, lo, env); + let hi_const = mir::ConstantKind::from_bits(tcx, hi, env); let kind = if lo == hi { PatKind::Constant { value: lo_const } @@ -635,9 +647,9 @@ pub(super) enum Constructor<'tcx> { /// Ranges of integer literal values (`2`, `2..=5` or `2..5`). IntRange(IntRange), /// Ranges of floating-point literal values (`2.0..=5.2`). - FloatRange(ty::Const<'tcx>, ty::Const<'tcx>, RangeEnd), + FloatRange(mir::ConstantKind<'tcx>, mir::ConstantKind<'tcx>, RangeEnd), /// String literals. Strings are not quite the same as `&[u8]` so we treat them separately. - Str(ty::Const<'tcx>), + Str(mir::ConstantKind<'tcx>), /// Array and slice patterns. Slice(Slice), /// Constants that must not be matched structurally. They are treated as black @@ -1376,7 +1388,7 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> { } } PatKind::Constant { value } => { - if let Some(int_range) = IntRange::from_const(cx.tcx, cx.param_env, *value) { + if let Some(int_range) = IntRange::from_constant(cx.tcx, cx.param_env, *value) { ctor = IntRange(int_range); fields = Fields::empty(); } else { diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 5b0aa4309a8ed..e0dec1daf63c8 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -17,32 +17,33 @@ use rustc_hir::RangeEnd; use rustc_index::vec::Idx; use rustc_middle::mir::interpret::{get_slice_bytes, ConstValue}; use rustc_middle::mir::interpret::{ErrorHandled, LitToConstError, LitToConstInput}; -use rustc_middle::mir::UserTypeProjection; +use rustc_middle::mir::{self, UserTypeProjection}; use rustc_middle::mir::{BorrowKind, Field, Mutability}; -use rustc_middle::thir::{Ascription, BindingMode, FieldPat, Pat, PatKind, PatRange, PatTyProj}; +use rustc_middle::thir::{Ascription, BindingMode, FieldPat, Pat, PatKind, PatRange}; use rustc_middle::ty::subst::{GenericArg, SubstsRef}; +use rustc_middle::ty::CanonicalUserTypeAnnotation; use rustc_middle::ty::{self, AdtDef, ConstKind, DefIdTree, Region, Ty, TyCtxt, UserType}; use rustc_span::{Span, Symbol}; use std::cmp::Ordering; #[derive(Clone, Debug)] -crate enum PatternError { +pub(crate) enum PatternError { AssocConstInPattern(Span), ConstParamInPattern(Span), StaticInPattern(Span), NonConstPath(Span), } -crate struct PatCtxt<'a, 'tcx> { - crate tcx: TyCtxt<'tcx>, - crate param_env: ty::ParamEnv<'tcx>, - crate typeck_results: &'a ty::TypeckResults<'tcx>, - crate errors: Vec, +pub(crate) struct PatCtxt<'a, 'tcx> { + pub(crate) tcx: TyCtxt<'tcx>, + pub(crate) param_env: ty::ParamEnv<'tcx>, + pub(crate) typeck_results: &'a ty::TypeckResults<'tcx>, + pub(crate) errors: Vec, include_lint_checks: bool, } -crate fn pat_from_hir<'a, 'tcx>( +pub(crate) fn pat_from_hir<'a, 'tcx>( tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, typeck_results: &'a ty::TypeckResults<'tcx>, @@ -59,7 +60,7 @@ crate fn pat_from_hir<'a, 'tcx>( } impl<'a, 'tcx> PatCtxt<'a, 'tcx> { - crate fn new( + pub(crate) fn new( tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, typeck_results: &'a ty::TypeckResults<'tcx>, @@ -67,12 +68,12 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { PatCtxt { tcx, param_env, typeck_results, errors: vec![], include_lint_checks: false } } - crate fn include_lint_checks(&mut self) -> &mut Self { + pub(crate) fn include_lint_checks(&mut self) -> &mut Self { self.include_lint_checks = true; self } - crate fn lower_pattern(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Pat<'tcx> { + pub(crate) fn lower_pattern(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Pat<'tcx> { // When implicit dereferences have been inserted in this pattern, the unadjusted lowered // pattern has the type that results *after* dereferencing. For example, in this code: // @@ -121,8 +122,8 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { fn lower_pattern_range( &mut self, ty: Ty<'tcx>, - lo: ty::Const<'tcx>, - hi: ty::Const<'tcx>, + lo: mir::ConstantKind<'tcx>, + hi: mir::ConstantKind<'tcx>, end: RangeEnd, span: Span, ) -> PatKind<'tcx> { @@ -177,16 +178,18 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { ty: Ty<'tcx>, lo: Option<&PatKind<'tcx>>, hi: Option<&PatKind<'tcx>>, - ) -> Option<(ty::Const<'tcx>, ty::Const<'tcx>)> { + ) -> Option<(mir::ConstantKind<'tcx>, mir::ConstantKind<'tcx>)> { match (lo, hi) { (Some(PatKind::Constant { value: lo }), Some(PatKind::Constant { value: hi })) => { Some((*lo, *hi)) } (Some(PatKind::Constant { value: lo }), None) => { - Some((*lo, ty.numeric_max_val(self.tcx)?)) + let hi = ty.numeric_max_val(self.tcx)?; + Some((*lo, hi.into())) } (None, Some(PatKind::Constant { value: hi })) => { - Some((ty.numeric_min_val(self.tcx)?, *hi)) + let lo = ty.numeric_min_val(self.tcx)?; + Some((lo.into(), *hi)) } _ => None, } @@ -225,7 +228,8 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { for end in &[lo, hi] { if let Some((_, Some(ascription))) = end { let subpattern = Pat { span: pat.span, ty, kind: Box::new(kind) }; - kind = PatKind::AscribeUserType { ascription: *ascription, subpattern }; + kind = + PatKind::AscribeUserType { ascription: ascription.clone(), subpattern }; } } @@ -430,13 +434,14 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { if let Some(user_ty) = self.user_substs_applied_to_ty_of_hir_id(hir_id) { debug!("lower_variant_or_leaf: kind={:?} user_ty={:?} span={:?}", kind, user_ty, span); + let annotation = CanonicalUserTypeAnnotation { + user_ty, + span, + inferred_ty: self.typeck_results.node_type(hir_id), + }; kind = PatKind::AscribeUserType { subpattern: Pat { span, ty, kind: Box::new(kind) }, - ascription: Ascription { - user_ty: PatTyProj::from_user_type(user_ty), - user_ty_span: span, - variance: ty::Variance::Covariant, - }, + ascription: Ascription { annotation, variance: ty::Variance::Covariant }, }; } @@ -446,6 +451,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { /// Takes a HIR Path. If the path is a constant, evaluates it and feeds /// it to `const_to_pat`. Any other path (like enum variants without fields) /// is converted to the corresponding pattern via `lower_variant_or_leaf`. + #[instrument(skip(self), level = "debug")] fn lower_path(&mut self, qpath: &hir::QPath<'_>, id: hir::HirId, span: Span) -> Pat<'tcx> { let ty = self.typeck_results.node_type(id); let res = self.typeck_results.qpath_res(qpath, id); @@ -487,8 +493,8 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { debug!("mir_structural_match_violation({:?}) -> {}", qpath, mir_structural_match_violation); match self.tcx.const_eval_instance(param_env_reveal_all, instance, Some(span)) { - Ok(value) => { - let const_ = ty::Const::from_value(self.tcx, value, ty); + Ok(literal) => { + let const_ = mir::ConstantKind::Val(literal, ty); let pattern = self.const_to_pat(const_, id, span, mir_structural_match_violation); if !is_associated_const { @@ -496,18 +502,21 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { } let user_provided_types = self.typeck_results().user_provided_types(); - if let Some(u_ty) = user_provided_types.get(id) { - let user_ty = PatTyProj::from_user_type(*u_ty); + if let Some(&user_ty) = user_provided_types.get(id) { + let annotation = CanonicalUserTypeAnnotation { + user_ty, + span, + inferred_ty: self.typeck_results().node_type(id), + }; Pat { span, kind: Box::new(PatKind::AscribeUserType { subpattern: pattern, ascription: Ascription { + annotation, /// Note that use `Contravariant` here. See the /// `variance` field documentation for details. variance: ty::Variance::Contravariant, - user_ty, - user_ty_span: span, }, }), ty: const_.ty(), @@ -537,25 +546,30 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { span: Span, ) -> PatKind<'tcx> { let anon_const_def_id = self.tcx.hir().local_def_id(anon_const.hir_id); - let value = ty::Const::from_inline_const(self.tcx, anon_const_def_id); + let value = mir::ConstantKind::from_inline_const(self.tcx, anon_const_def_id); // Evaluate early like we do in `lower_path`. let value = value.eval(self.tcx, self.param_env); - match value.val() { - ConstKind::Param(_) => { - self.errors.push(PatternError::ConstParamInPattern(span)); - return PatKind::Wild; - } - ConstKind::Unevaluated(_) => { - // If we land here it means the const can't be evaluated because it's `TooGeneric`. - self.tcx.sess.span_err(span, "constant pattern depends on a generic parameter"); - return PatKind::Wild; + match value { + mir::ConstantKind::Ty(c) => { + match c.val() { + ConstKind::Param(_) => { + self.errors.push(PatternError::ConstParamInPattern(span)); + return PatKind::Wild; + } + ConstKind::Unevaluated(_) => { + // If we land here it means the const can't be evaluated because it's `TooGeneric`. + self.tcx + .sess + .span_err(span, "constant pattern depends on a generic parameter"); + return PatKind::Wild; + } + _ => bug!("Expected either ConstKind::Param or ConstKind::Unevaluated"), + } } - _ => (), + mir::ConstantKind::Val(_, _) => *self.const_to_pat(value, id, span, false).kind, } - - *self.const_to_pat(value, id, span, false).kind } /// Converts literals, paths and negation of literals to patterns. @@ -582,7 +596,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { let lit_input = LitToConstInput { lit: &lit.node, ty: self.typeck_results.expr_ty(expr), neg }; - match self.tcx.at(expr.span).lit_to_const(lit_input) { + match self.tcx.at(expr.span).lit_to_mir_constant(lit_input) { Ok(constant) => *self.const_to_pat(constant, expr.hir_id, lit.span, false).kind, Err(LitToConstError::Reported) => PatKind::Wild, Err(LitToConstError::TypeError) => bug!("lower_lit: had type error"), @@ -600,7 +614,7 @@ impl<'tcx> UserAnnotatedTyHelpers<'tcx> for PatCtxt<'_, 'tcx> { } } -crate trait PatternFoldable<'tcx>: Sized { +pub(crate) trait PatternFoldable<'tcx>: Sized { fn fold_with>(&self, folder: &mut F) -> Self { self.super_fold_with(folder) } @@ -608,7 +622,7 @@ crate trait PatternFoldable<'tcx>: Sized { fn super_fold_with>(&self, folder: &mut F) -> Self; } -crate trait PatternFolder<'tcx>: Sized { +pub(crate) trait PatternFolder<'tcx>: Sized { fn fold_pattern(&mut self, pattern: &Pat<'tcx>) -> Pat<'tcx> { pattern.super_fold_with(self) } @@ -637,7 +651,7 @@ impl<'tcx, T: PatternFoldable<'tcx>> PatternFoldable<'tcx> for Option { } } -macro_rules! CloneImpls { +macro_rules! ClonePatternFoldableImpls { (<$lt_tcx:tt> $($ty:ty),+) => { $( impl<$lt_tcx> PatternFoldable<$lt_tcx> for $ty { @@ -649,11 +663,11 @@ macro_rules! CloneImpls { } } -CloneImpls! { <'tcx> +ClonePatternFoldableImpls! { <'tcx> Span, Field, Mutability, Symbol, hir::HirId, usize, ty::Const<'tcx>, Region<'tcx>, Ty<'tcx>, BindingMode, AdtDef<'tcx>, SubstsRef<'tcx>, &'tcx GenericArg<'tcx>, UserType<'tcx>, - UserTypeProjection, PatTyProj<'tcx> + UserTypeProjection, CanonicalUserTypeAnnotation<'tcx> } impl<'tcx> PatternFoldable<'tcx> for FieldPat<'tcx> { @@ -686,14 +700,10 @@ impl<'tcx> PatternFoldable<'tcx> for PatKind<'tcx> { PatKind::Wild => PatKind::Wild, PatKind::AscribeUserType { ref subpattern, - ascription: Ascription { variance, ref user_ty, user_ty_span }, + ascription: Ascription { ref annotation, variance }, } => PatKind::AscribeUserType { subpattern: subpattern.fold_with(folder), - ascription: Ascription { - user_ty: user_ty.fold_with(folder), - variance, - user_ty_span, - }, + ascription: Ascription { annotation: annotation.fold_with(folder), variance }, }, PatKind::Binding { mutability, name, mode, var, ty, ref subpattern, is_primary } => { PatKind::Binding { @@ -738,10 +748,10 @@ impl<'tcx> PatternFoldable<'tcx> for PatKind<'tcx> { } #[instrument(skip(tcx), level = "debug")] -crate fn compare_const_vals<'tcx>( +pub(crate) fn compare_const_vals<'tcx>( tcx: TyCtxt<'tcx>, - a: ty::Const<'tcx>, - b: ty::Const<'tcx>, + a: mir::ConstantKind<'tcx>, + b: mir::ConstantKind<'tcx>, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>, ) -> Option { @@ -754,9 +764,7 @@ crate fn compare_const_vals<'tcx>( return fallback(); } - // Early return for equal constants (so e.g. references to ZSTs can be compared, even if they - // are just integer addresses). - if a.val() == b.val() { + if a == b { return from_bool(true); } @@ -788,9 +796,9 @@ crate fn compare_const_vals<'tcx>( } if let ty::Str = ty.kind() && let ( - ty::ConstKind::Value(a_val @ ConstValue::Slice { .. }), - ty::ConstKind::Value(b_val @ ConstValue::Slice { .. }), - ) = (a.val(), b.val()) + Some(a_val @ ConstValue::Slice { .. }), + Some(b_val @ ConstValue::Slice { .. }), + ) = (a.try_val(), b.try_val()) { let a_bytes = get_slice_bytes(&tcx, a_val); let b_bytes = get_slice_bytes(&tcx, b_val); diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs index 4e96cfd9bbd50..9e7a267ecbd7f 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs @@ -309,16 +309,16 @@ use smallvec::{smallvec, SmallVec}; use std::fmt; use std::iter::once; -crate struct MatchCheckCtxt<'p, 'tcx> { - crate tcx: TyCtxt<'tcx>, +pub(crate) struct MatchCheckCtxt<'p, 'tcx> { + pub(crate) tcx: TyCtxt<'tcx>, /// The module in which the match occurs. This is necessary for /// checking inhabited-ness of types because whether a type is (visibly) /// inhabited can depend on whether it was defined in the current module or /// not. E.g., `struct Foo { _private: ! }` cannot be seen to be empty /// outside its module and should not be matchable with an empty match statement. - crate module: DefId, - crate param_env: ty::ParamEnv<'tcx>, - crate pattern_arena: &'p TypedArena>, + pub(crate) module: DefId, + pub(crate) param_env: ty::ParamEnv<'tcx>, + pub(crate) pattern_arena: &'p TypedArena>, } impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> { @@ -691,7 +691,7 @@ enum ArmType { /// /// The final `Pair(Some(_), true)` is then the resulting witness. #[derive(Debug)] -crate struct Witness<'p, 'tcx>(Vec>); +pub(crate) struct Witness<'p, 'tcx>(Vec>); impl<'p, 'tcx> Witness<'p, 'tcx> { /// Asserts that the witness contains a single pattern, and returns it. @@ -908,16 +908,16 @@ fn is_useful<'p, 'tcx>( /// The arm of a match expression. #[derive(Clone, Copy, Debug)] -crate struct MatchArm<'p, 'tcx> { +pub(crate) struct MatchArm<'p, 'tcx> { /// The pattern must have been lowered through `check_match::MatchVisitor::lower_pattern`. - crate pat: &'p DeconstructedPat<'p, 'tcx>, - crate hir_id: HirId, - crate has_guard: bool, + pub(crate) pat: &'p DeconstructedPat<'p, 'tcx>, + pub(crate) hir_id: HirId, + pub(crate) has_guard: bool, } /// Indicates whether or not a given arm is reachable. #[derive(Clone, Debug)] -crate enum Reachability { +pub(crate) enum Reachability { /// The arm is reachable. This additionally carries a set of or-pattern branches that have been /// found to be unreachable despite the overall arm being reachable. Used only in the presence /// of or-patterns, otherwise it stays empty. @@ -927,12 +927,12 @@ crate enum Reachability { } /// The output of checking a match for exhaustiveness and arm reachability. -crate struct UsefulnessReport<'p, 'tcx> { +pub(crate) struct UsefulnessReport<'p, 'tcx> { /// For each arm of the input, whether that arm is reachable after the arms above it. - crate arm_usefulness: Vec<(MatchArm<'p, 'tcx>, Reachability)>, + pub(crate) arm_usefulness: Vec<(MatchArm<'p, 'tcx>, Reachability)>, /// If the match is exhaustive, this is empty. If not, this contains witnesses for the lack of /// exhaustiveness. - crate non_exhaustiveness_witnesses: Vec>, + pub(crate) non_exhaustiveness_witnesses: Vec>, } /// The entrypoint for the usefulness algorithm. Computes whether a match is exhaustive and which @@ -941,7 +941,7 @@ crate struct UsefulnessReport<'p, 'tcx> { /// Note: the input patterns must have been lowered through /// `check_match::MatchVisitor::lower_pattern`. #[instrument(skip(cx, arms), level = "debug")] -crate fn compute_match_usefulness<'p, 'tcx>( +pub(crate) fn compute_match_usefulness<'p, 'tcx>( cx: &MatchCheckCtxt<'p, 'tcx>, arms: &[MatchArm<'p, 'tcx>], scrut_hir_id: HirId, diff --git a/compiler/rustc_mir_build/src/thir/util.rs b/compiler/rustc_mir_build/src/thir/util.rs index 82f97f22ccec4..c58ed1ac0b891 100644 --- a/compiler/rustc_mir_build/src/thir/util.rs +++ b/compiler/rustc_mir_build/src/thir/util.rs @@ -1,7 +1,7 @@ use rustc_hir as hir; use rustc_middle::ty::{self, CanonicalUserType, TyCtxt, UserType}; -crate trait UserAnnotatedTyHelpers<'tcx> { +pub(crate) trait UserAnnotatedTyHelpers<'tcx> { fn tcx(&self) -> TyCtxt<'tcx>; fn typeck_results(&self) -> &ty::TypeckResults<'tcx>; diff --git a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs index f568121b2192c..027af5b9c1f2d 100644 --- a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs +++ b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs @@ -625,7 +625,8 @@ where kind: TerminatorKind::Call { func: Operand::function_handle(tcx, drop_fn, substs, self.source_info.span), args: vec![Operand::Move(Place::from(ref_place))], - destination: Some((unit_temp, succ)), + destination: unit_temp, + target: Some(succ), cleanup: unwind.into_option(), from_hir_call: true, fn_span: self.source_info.span, @@ -963,7 +964,8 @@ where let call = TerminatorKind::Call { func: Operand::function_handle(tcx, free_func, substs, self.source_info.span), args, - destination: Some((unit_temp, target)), + destination: unit_temp, + target: Some(target), cleanup: None, from_hir_call: false, fn_span: self.source_info.span, diff --git a/compiler/rustc_mir_dataflow/src/framework/direction.rs b/compiler/rustc_mir_dataflow/src/framework/direction.rs index 18795128b8571..3a492b45849c9 100644 --- a/compiler/rustc_mir_dataflow/src/framework/direction.rs +++ b/compiler/rustc_mir_dataflow/src/framework/direction.rs @@ -237,14 +237,12 @@ impl Direction for Backward { // Apply terminator-specific edge effects. // // FIXME(ecstaticmorse): Avoid cloning the exit state unconditionally. - mir::TerminatorKind::Call { destination: Some((return_place, dest)), .. } - if dest == bb => - { + mir::TerminatorKind::Call { destination, target: Some(dest), .. } if dest == bb => { let mut tmp = exit_state.clone(); analysis.apply_call_return_effect( &mut tmp, pred, - CallReturnPlaces::Call(return_place), + CallReturnPlaces::Call(destination), ); propagate(pred, &tmp); } @@ -304,8 +302,8 @@ impl Direction for Backward { } } -struct BackwardSwitchIntEdgeEffectsApplier<'a, D, F> { - body: &'a mir::Body<'a>, +struct BackwardSwitchIntEdgeEffectsApplier<'a, 'tcx, D, F> { + body: &'a mir::Body<'tcx>, pred: BasicBlock, exit_state: &'a mut D, bb: BasicBlock, @@ -314,7 +312,7 @@ struct BackwardSwitchIntEdgeEffectsApplier<'a, D, F> { effects_applied: bool, } -impl super::SwitchIntEdgeEffects for BackwardSwitchIntEdgeEffectsApplier<'_, D, F> +impl super::SwitchIntEdgeEffects for BackwardSwitchIntEdgeEffectsApplier<'_, '_, D, F> where D: Clone, F: FnMut(BasicBlock, &D), @@ -532,20 +530,28 @@ impl Direction for Forward { propagate(target, exit_state); } - Call { cleanup, destination, func: _, args: _, from_hir_call: _, fn_span: _ } => { + Call { + cleanup, + destination, + target, + func: _, + args: _, + from_hir_call: _, + fn_span: _, + } => { if let Some(unwind) = cleanup { if dead_unwinds.map_or(true, |dead| !dead.contains(bb)) { propagate(unwind, exit_state); } } - if let Some((dest_place, target)) = destination { + if let Some(target) = target { // N.B.: This must be done *last*, otherwise the unwind path will see the call // return effect. analysis.apply_call_return_effect( exit_state, bb, - CallReturnPlaces::Call(dest_place), + CallReturnPlaces::Call(destination), ); propagate(target, exit_state); } diff --git a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs index 599b4087c78e4..3834c232ab6ba 100644 --- a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs +++ b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs @@ -125,7 +125,7 @@ where } fn target(&self, edge: &Self::Edge) -> Self::Node { - self.body[edge.source].terminator().successors().nth(edge.index).copied().unwrap() + self.body[edge.source].terminator().successors().nth(edge.index).unwrap() } } @@ -218,7 +218,7 @@ where self.results.seek_to_block_end(block); if self.results.get() != &block_start_state || A::Direction::is_backward() { let after_terminator_name = match terminator.kind { - mir::TerminatorKind::Call { destination: Some(_), .. } => "(on unwind)", + mir::TerminatorKind::Call { target: Some(_), .. } => "(on unwind)", _ => "(on end)", }; @@ -231,14 +231,14 @@ where // for the basic block itself. That way, we could display terminator-specific effects for // backward dataflow analyses as well as effects for `SwitchInt` terminators. match terminator.kind { - mir::TerminatorKind::Call { destination: Some((return_place, _)), .. } => { + mir::TerminatorKind::Call { destination, .. } => { self.write_row(w, "", "(on successful return)", |this, w, fmt| { let state_on_unwind = this.results.get().clone(); this.results.apply_custom_effect(|analysis, state| { analysis.apply_call_return_effect( state, block, - CallReturnPlaces::Call(return_place), + CallReturnPlaces::Call(destination), ); }); diff --git a/compiler/rustc_mir_dataflow/src/framework/tests.rs b/compiler/rustc_mir_dataflow/src/framework/tests.rs index 3cc8d30259c0e..74c3b44f4250e 100644 --- a/compiler/rustc_mir_dataflow/src/framework/tests.rs +++ b/compiler/rustc_mir_dataflow/src/framework/tests.rs @@ -14,7 +14,7 @@ use super::*; /// /// This is the `Body` that will be used by the `MockAnalysis` below. The shape of its CFG is not /// important. -fn mock_body() -> mir::Body<'static> { +fn mock_body<'tcx>() -> mir::Body<'tcx> { let source_info = mir::SourceInfo::outermost(DUMMY_SP); let mut blocks = IndexVec::new(); @@ -37,7 +37,8 @@ fn mock_body() -> mir::Body<'static> { mir::TerminatorKind::Call { func: mir::Operand::Copy(dummy_place.clone()), args: vec![], - destination: Some((dummy_place.clone(), mir::START_BLOCK)), + destination: dummy_place.clone(), + target: Some(mir::START_BLOCK), cleanup: None, from_hir_call: false, fn_span: DUMMY_SP, @@ -50,7 +51,8 @@ fn mock_body() -> mir::Body<'static> { mir::TerminatorKind::Call { func: mir::Operand::Copy(dummy_place.clone()), args: vec![], - destination: Some((dummy_place.clone(), mir::START_BLOCK)), + destination: dummy_place.clone(), + target: Some(mir::START_BLOCK), cleanup: None, from_hir_call: false, fn_span: DUMMY_SP, diff --git a/compiler/rustc_mir_dataflow/src/impls/liveness.rs b/compiler/rustc_mir_dataflow/src/impls/liveness.rs index 5a788c153a477..7076fbe1bdb53 100644 --- a/compiler/rustc_mir_dataflow/src/impls/liveness.rs +++ b/compiler/rustc_mir_dataflow/src/impls/liveness.rs @@ -1,8 +1,8 @@ -use rustc_index::bit_set::BitSet; +use rustc_index::bit_set::{BitSet, ChunkedBitSet}; use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor}; -use rustc_middle::mir::{self, Local, Location}; +use rustc_middle::mir::{self, Local, Location, Place, StatementKind}; -use crate::{AnalysisDomain, Backward, CallReturnPlaces, GenKill, GenKillAnalysis}; +use crate::{Analysis, AnalysisDomain, Backward, CallReturnPlaces, GenKill, GenKillAnalysis}; /// A [live-variable dataflow analysis][liveness]. /// @@ -98,19 +98,16 @@ where T: GenKill, { fn visit_place(&mut self, place: &mir::Place<'tcx>, context: PlaceContext, location: Location) { - let mir::Place { projection, local } = *place; + let local = place.local; // We purposefully do not call `super_place` here to avoid calling `visit_local` for this // place with one of the `Projection` variants of `PlaceContext`. self.visit_projection(place.as_ref(), context, location); - match DefUse::for_place(context) { - // Treat derefs as a use of the base local. `*p = 4` is not a def of `p` but a use. - Some(_) if place.is_indirect() => self.0.gen(local), - - Some(DefUse::Def) if projection.is_empty() => self.0.kill(local), + match DefUse::for_place(*place, context) { + Some(DefUse::Def) => self.0.kill(local), Some(DefUse::Use) => self.0.gen(local), - _ => {} + None => {} } } @@ -118,10 +115,10 @@ where // Because we do not call `super_place` above, `visit_local` is only called for locals that // do not appear as part of a `Place` in the MIR. This handles cases like the implicit use // of the return place in a `Return` terminator or the index in an `Index` projection. - match DefUse::for_place(context) { + match DefUse::for_place(local.into(), context) { Some(DefUse::Def) => self.0.kill(local), Some(DefUse::Use) => self.0.gen(local), - _ => {} + None => {} } } } @@ -133,27 +130,37 @@ enum DefUse { } impl DefUse { - fn for_place(context: PlaceContext) -> Option { + fn for_place<'tcx>(place: Place<'tcx>, context: PlaceContext) -> Option { match context { PlaceContext::NonUse(_) => None, PlaceContext::MutatingUse(MutatingUseContext::Store | MutatingUseContext::Deinit) => { - Some(DefUse::Def) + if place.is_indirect() { + // Treat derefs as a use of the base local. `*p = 4` is not a def of `p` but a + // use. + Some(DefUse::Use) + } else if place.projection.is_empty() { + Some(DefUse::Def) + } else { + None + } } // Setting the discriminant is not a use because it does no reading, but it is also not // a def because it does not overwrite the whole place - PlaceContext::MutatingUse(MutatingUseContext::SetDiscriminant) => None, + PlaceContext::MutatingUse(MutatingUseContext::SetDiscriminant) => { + place.is_indirect().then_some(DefUse::Use) + } - // `MutatingUseContext::Call` and `MutatingUseContext::Yield` indicate that this is the - // destination place for a `Call` return or `Yield` resume respectively. Since this is - // only a `Def` when the function returns successfully, we handle this case separately - // in `call_return_effect` above. + // For the associated terminators, this is only a `Def` when the terminator returns + // "successfully." As such, we handle this case separately in `call_return_effect` + // above. However, if the place looks like `*_5`, this is still unconditionally a use of + // `_5`. PlaceContext::MutatingUse( MutatingUseContext::Call - | MutatingUseContext::AsmOutput - | MutatingUseContext::Yield, - ) => None, + | MutatingUseContext::Yield + | MutatingUseContext::AsmOutput, + ) => place.is_indirect().then_some(DefUse::Use), // All other contexts are uses... PlaceContext::MutatingUse( @@ -179,3 +186,127 @@ impl DefUse { } } } + +/// Like `MaybeLiveLocals`, but does not mark locals as live if they are used in a dead assignment. +/// +/// This is basically written for dead store elimination and nothing else. +/// +/// All of the caveats of `MaybeLiveLocals` apply. +pub struct MaybeTransitiveLiveLocals<'a> { + always_live: &'a BitSet, +} + +impl<'a> MaybeTransitiveLiveLocals<'a> { + /// The `always_alive` set is the set of locals to which all stores should unconditionally be + /// considered live. + /// + /// This should include at least all locals that are ever borrowed. + pub fn new(always_live: &'a BitSet) -> Self { + MaybeTransitiveLiveLocals { always_live } + } +} + +impl<'a, 'tcx> AnalysisDomain<'tcx> for MaybeTransitiveLiveLocals<'a> { + type Domain = ChunkedBitSet; + type Direction = Backward; + + const NAME: &'static str = "transitive liveness"; + + fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain { + // bottom = not live + ChunkedBitSet::new_empty(body.local_decls.len()) + } + + fn initialize_start_block(&self, _: &mir::Body<'tcx>, _: &mut Self::Domain) { + // No variables are live until we observe a use + } +} + +struct TransferWrapper<'a>(&'a mut ChunkedBitSet); + +impl<'a> GenKill for TransferWrapper<'a> { + fn gen(&mut self, l: Local) { + self.0.insert(l); + } + + fn kill(&mut self, l: Local) { + self.0.remove(l); + } +} + +impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> { + fn apply_statement_effect( + &self, + trans: &mut Self::Domain, + statement: &mir::Statement<'tcx>, + location: Location, + ) { + // Compute the place that we are storing to, if any + let destination = match &statement.kind { + StatementKind::Assign(assign) => { + if assign.1.is_pointer_int_cast() { + // Pointer to int casts may be side-effects due to exposing the provenance. + // While the model is undecided, we should be conservative. See + // + None + } else { + Some(assign.0) + } + } + StatementKind::SetDiscriminant { place, .. } | StatementKind::Deinit(place) => { + Some(**place) + } + StatementKind::FakeRead(_) + | StatementKind::StorageLive(_) + | StatementKind::StorageDead(_) + | StatementKind::Retag(..) + | StatementKind::AscribeUserType(..) + | StatementKind::Coverage(..) + | StatementKind::CopyNonOverlapping(..) + | StatementKind::Nop => None, + }; + if let Some(destination) = destination { + if !destination.is_indirect() + && !trans.contains(destination.local) + && !self.always_live.contains(destination.local) + { + // This store is dead + return; + } + } + TransferFunction(&mut TransferWrapper(trans)).visit_statement(statement, location); + } + + fn apply_terminator_effect( + &self, + trans: &mut Self::Domain, + terminator: &mir::Terminator<'tcx>, + location: Location, + ) { + TransferFunction(&mut TransferWrapper(trans)).visit_terminator(terminator, location); + } + + fn apply_call_return_effect( + &self, + trans: &mut Self::Domain, + _block: mir::BasicBlock, + return_places: CallReturnPlaces<'_, 'tcx>, + ) { + return_places.for_each(|place| { + if let Some(local) = place.as_local() { + trans.remove(local); + } + }); + } + + fn apply_yield_resume_effect( + &self, + trans: &mut Self::Domain, + _resume_block: mir::BasicBlock, + resume_place: mir::Place<'tcx>, + ) { + if let Some(local) = resume_place.as_local() { + trans.remove(local); + } + } +} diff --git a/compiler/rustc_mir_dataflow/src/impls/mod.rs b/compiler/rustc_mir_dataflow/src/impls/mod.rs index c9722a6df77db..41cf43fc8e186 100644 --- a/compiler/rustc_mir_dataflow/src/impls/mod.rs +++ b/compiler/rustc_mir_dataflow/src/impls/mod.rs @@ -26,6 +26,7 @@ mod storage_liveness; pub use self::borrowed_locals::MaybeBorrowedLocals; pub use self::init_locals::MaybeInitializedLocals; pub use self::liveness::MaybeLiveLocals; +pub use self::liveness::MaybeTransitiveLiveLocals; pub use self::storage_liveness::{MaybeRequiresStorage, MaybeStorageLive}; /// `MaybeInitializedPlaces` tracks all places that might be diff --git a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs index 2730e8bd49b76..356a6b7765e16 100644 --- a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs +++ b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs @@ -169,8 +169,8 @@ impl<'mir, 'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'mir, 'tc self.borrowed_locals.borrow().analysis().terminator_effect(trans, terminator, loc); match &terminator.kind { - TerminatorKind::Call { destination: Some((place, _)), .. } => { - trans.gen(place.local); + TerminatorKind::Call { destination, .. } => { + trans.gen(destination.local); } // Note that we do *not* gen the `resume_arg` of `Yield` terminators. The reason for @@ -198,8 +198,7 @@ impl<'mir, 'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'mir, 'tc // Nothing to do for these. Match exhaustively so this fails to compile when new // variants are added. - TerminatorKind::Call { destination: None, .. } - | TerminatorKind::Abort + TerminatorKind::Abort | TerminatorKind::Assert { .. } | TerminatorKind::Drop { .. } | TerminatorKind::DropAndReplace { .. } @@ -225,8 +224,8 @@ impl<'mir, 'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'mir, 'tc // and after the call returns successfully, but not after a panic. // Since `propagate_call_unwind` doesn't exist, we have to kill the // destination here, and then gen it again in `call_return_effect`. - TerminatorKind::Call { destination: Some((place, _)), .. } => { - trans.kill(place.local); + TerminatorKind::Call { destination, .. } => { + trans.kill(destination.local); } // The same applies to InlineAsm outputs. @@ -236,8 +235,7 @@ impl<'mir, 'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'mir, 'tc // Nothing to do for these. Match exhaustively so this fails to compile when new // variants are added. - TerminatorKind::Call { destination: None, .. } - | TerminatorKind::Yield { .. } + TerminatorKind::Yield { .. } | TerminatorKind::Abort | TerminatorKind::Assert { .. } | TerminatorKind::Drop { .. } diff --git a/compiler/rustc_mir_dataflow/src/lib.rs b/compiler/rustc_mir_dataflow/src/lib.rs index c1124a533bf2b..e4c130f0807dd 100644 --- a/compiler/rustc_mir_dataflow/src/lib.rs +++ b/compiler/rustc_mir_dataflow/src/lib.rs @@ -1,6 +1,5 @@ #![feature(associated_type_defaults)] #![feature(box_patterns)] -#![feature(box_syntax)] #![feature(exact_size_is_empty)] #![feature(let_else)] #![feature(min_specialization)] diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs index 73072464872c3..b08cb50f77aed 100644 --- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs +++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs @@ -376,7 +376,8 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { TerminatorKind::Call { ref func, ref args, - ref destination, + destination, + target, cleanup: _, from_hir_call: _, fn_span: _, @@ -385,7 +386,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { for arg in args { self.gather_operand(arg); } - if let Some((destination, _bb)) = *destination { + if let Some(_bb) = target { self.create_move_path(destination); self.gather_init(destination.as_ref(), InitKind::NonPanicPathOnly); } diff --git a/compiler/rustc_mir_dataflow/src/rustc_peek.rs b/compiler/rustc_mir_dataflow/src/rustc_peek.rs index cc9ee1016c6db..2f884887ad9fe 100644 --- a/compiler/rustc_mir_dataflow/src/rustc_peek.rs +++ b/compiler/rustc_mir_dataflow/src/rustc_peek.rs @@ -1,6 +1,5 @@ use rustc_span::symbol::sym; use rustc_span::Span; -use rustc_target::spec::abi::Abi; use rustc_index::bit_set::BitSet; use rustc_middle::mir::MirPass; @@ -193,9 +192,8 @@ impl PeekCall { &terminator.kind { if let ty::FnDef(def_id, substs) = *func.literal.ty().kind() { - let sig = tcx.fn_sig(def_id); let name = tcx.item_name(def_id); - if sig.abi() != Abi::RustIntrinsic || name != sym::rustc_peek { + if !tcx.is_intrinsic(def_id) || name != sym::rustc_peek { return None; } diff --git a/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs b/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs index ade6555f4d2c1..11980382ffdb2 100644 --- a/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs +++ b/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs @@ -1,4 +1,5 @@ use crate::MirPass; +use rustc_ast::InlineAsmOptions; use rustc_hir::def::DefKind; use rustc_middle::mir::*; use rustc_middle::ty::layout; @@ -85,6 +86,12 @@ impl<'tcx> MirPass<'tcx> for AbortUnwindingCalls { TerminatorKind::Assert { .. } | TerminatorKind::FalseUnwind { .. } => { layout::fn_can_unwind(tcx, None, Abi::Rust) } + TerminatorKind::InlineAsm { options, .. } => { + options.contains(InlineAsmOptions::MAY_UNWIND) + } + _ if terminator.unwind().is_some() => { + span_bug!(span, "unexpected terminator that may unwind {:?}", terminator) + } _ => continue, }; diff --git a/compiler/rustc_mir_transform/src/add_call_guards.rs b/compiler/rustc_mir_transform/src/add_call_guards.rs index cd6b671a0dbfd..10d522717344d 100644 --- a/compiler/rustc_mir_transform/src/add_call_guards.rs +++ b/compiler/rustc_mir_transform/src/add_call_guards.rs @@ -50,12 +50,7 @@ impl AddCallGuards { for block in body.basic_blocks_mut() { match block.terminator { Some(Terminator { - kind: - TerminatorKind::Call { - destination: Some((_, ref mut destination)), - cleanup, - .. - }, + kind: TerminatorKind::Call { target: Some(ref mut destination), cleanup, .. }, source_info, }) if pred_count[*destination] > 1 && (cleanup.is_some() || self == &AllCallEdges) => diff --git a/compiler/rustc_mir_transform/src/add_retag.rs b/compiler/rustc_mir_transform/src/add_retag.rs index a245da658b975..0495439385bee 100644 --- a/compiler/rustc_mir_transform/src/add_retag.rs +++ b/compiler/rustc_mir_transform/src/add_retag.rs @@ -130,11 +130,11 @@ impl<'tcx> MirPass<'tcx> for AddRetag { .iter_mut() .filter_map(|block_data| { match block_data.terminator().kind { - TerminatorKind::Call { destination: Some(ref destination), .. } - if needs_retag(&destination.0) => + TerminatorKind::Call { target: Some(target), destination, .. } + if needs_retag(&destination) => { // Remember the return destination for later - Some((block_data.terminator().source_info, destination.0, destination.1)) + Some((block_data.terminator().source_info, destination, target)) } // `Drop` is also a call, but it doesn't return anything so we are good. diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs index 54c3cc46b265f..b17485fd542d3 100644 --- a/compiler/rustc_mir_transform/src/const_prop.rs +++ b/compiler/rustc_mir_transform/src/const_prop.rs @@ -200,7 +200,8 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx> _instance: ty::Instance<'tcx>, _abi: Abi, _args: &[OpTy<'tcx>], - _ret: Option<(&PlaceTy<'tcx>, BasicBlock)>, + _destination: &PlaceTy<'tcx>, + _target: Option, _unwind: StackPopUnwind, ) -> InterpResult<'tcx, Option<(&'mir Body<'tcx>, ty::Instance<'tcx>)>> { Ok(None) @@ -210,7 +211,8 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx> _ecx: &mut InterpCx<'mir, 'tcx, Self>, _instance: ty::Instance<'tcx>, _args: &[OpTy<'tcx>], - _ret: Option<(&PlaceTy<'tcx>, BasicBlock)>, + _destination: &PlaceTy<'tcx>, + _target: Option, _unwind: StackPopUnwind, ) -> InterpResult<'tcx> { throw_machine_stop_str!("calling intrinsics isn't supported in ConstProp") @@ -384,24 +386,22 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { ConstPropMachine::new(only_propagate_inside_block_locals, can_const_prop), ); - let ret = ecx + let ret_layout = ecx .layout_of(EarlyBinder(body.return_ty()).subst(tcx, substs)) .ok() - // Don't bother allocating memory for ZST types which have no values - // or for large values. - .filter(|ret_layout| { - !ret_layout.is_zst() && ret_layout.size < Size::from_bytes(MAX_ALLOC_LIMIT) - }) - .map(|ret_layout| { - ecx.allocate(ret_layout, MemoryKind::Stack) - .expect("couldn't perform small allocation") - .into() - }); + // Don't bother allocating memory for large values. + .filter(|ret_layout| ret_layout.size < Size::from_bytes(MAX_ALLOC_LIMIT)) + .unwrap_or_else(|| ecx.layout_of(tcx.types.unit).unwrap()); + + let ret = ecx + .allocate(ret_layout, MemoryKind::Stack) + .expect("couldn't perform small allocation") + .into(); ecx.push_stack_frame( Instance::new(def_id, substs), dummy_body, - ret.as_ref(), + &ret, StackPopCleanup::Root { cleanup: false }, ) .expect("failed to push initial stack frame"); diff --git a/compiler/rustc_mir_transform/src/const_prop_lint.rs b/compiler/rustc_mir_transform/src/const_prop_lint.rs index 6c0df98bc2713..5fd9db3989d05 100644 --- a/compiler/rustc_mir_transform/src/const_prop_lint.rs +++ b/compiler/rustc_mir_transform/src/const_prop_lint.rs @@ -192,7 +192,8 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx> _instance: ty::Instance<'tcx>, _abi: Abi, _args: &[OpTy<'tcx>], - _ret: Option<(&PlaceTy<'tcx>, BasicBlock)>, + _destination: &PlaceTy<'tcx>, + _target: Option, _unwind: StackPopUnwind, ) -> InterpResult<'tcx, Option<(&'mir Body<'tcx>, ty::Instance<'tcx>)>> { Ok(None) @@ -202,7 +203,8 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx> _ecx: &mut InterpCx<'mir, 'tcx, Self>, _instance: ty::Instance<'tcx>, _args: &[OpTy<'tcx>], - _ret: Option<(&PlaceTy<'tcx>, BasicBlock)>, + _destination: &PlaceTy<'tcx>, + _target: Option, _unwind: StackPopUnwind, ) -> InterpResult<'tcx> { throw_machine_stop_str!("calling intrinsics isn't supported in ConstProp") @@ -377,24 +379,22 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { ConstPropMachine::new(only_propagate_inside_block_locals, can_const_prop), ); - let ret = ecx + let ret_layout = ecx .layout_of(EarlyBinder(body.return_ty()).subst(tcx, substs)) .ok() - // Don't bother allocating memory for ZST types which have no values - // or for large values. - .filter(|ret_layout| { - !ret_layout.is_zst() && ret_layout.size < Size::from_bytes(MAX_ALLOC_LIMIT) - }) - .map(|ret_layout| { - ecx.allocate(ret_layout, MemoryKind::Stack) - .expect("couldn't perform small allocation") - .into() - }); + // Don't bother allocating memory for large values. + .filter(|ret_layout| ret_layout.size < Size::from_bytes(MAX_ALLOC_LIMIT)) + .unwrap_or_else(|| ecx.layout_of(tcx.types.unit).unwrap()); + + let ret = ecx + .allocate(ret_layout, MemoryKind::Stack) + .expect("couldn't perform small allocation") + .into(); ecx.push_stack_frame( Instance::new(def_id, substs), dummy_body, - ret.as_ref(), + &ret, StackPopCleanup::Root { cleanup: false }, ) .expect("failed to push initial stack frame"); diff --git a/compiler/rustc_mir_transform/src/coverage/debug.rs b/compiler/rustc_mir_transform/src/coverage/debug.rs index 8e28ed2426bbb..434bf9d849e5a 100644 --- a/compiler/rustc_mir_transform/src/coverage/debug.rs +++ b/compiler/rustc_mir_transform/src/coverage/debug.rs @@ -701,7 +701,7 @@ pub(super) fn dump_coverage_graphviz<'tcx>( edge_labels.retain(|label| label != "unreachable"); let edge_counters = from_terminator .successors() - .map(|&successor_bb| graphviz_data.get_edge_counter(from_bcb, successor_bb)); + .map(|successor_bb| graphviz_data.get_edge_counter(from_bcb, successor_bb)); iter::zip(&edge_labels, edge_counters) .map(|(label, some_counter)| { if let Some(counter) = some_counter { diff --git a/compiler/rustc_mir_transform/src/coverage/graph.rs b/compiler/rustc_mir_transform/src/coverage/graph.rs index 6bb7e676e851c..510f1e64ed1c0 100644 --- a/compiler/rustc_mir_transform/src/coverage/graph.rs +++ b/compiler/rustc_mir_transform/src/coverage/graph.rs @@ -481,20 +481,20 @@ impl std::fmt::Debug for BcbBranch { // FIXME(#78544): MIR InstrumentCoverage: Improve coverage of `#[should_panic]` tests and // `catch_unwind()` handlers. fn bcb_filtered_successors<'a, 'tcx>( - body: &'tcx &'a mir::Body<'tcx>, - term_kind: &'tcx TerminatorKind<'tcx>, + body: &'a mir::Body<'tcx>, + term_kind: &'a TerminatorKind<'tcx>, ) -> Box + 'a> { - let mut successors = term_kind.successors(); Box::new( match &term_kind { // SwitchInt successors are never unwind, and all of them should be traversed. - TerminatorKind::SwitchInt { .. } => successors, + TerminatorKind::SwitchInt { ref targets, .. } => { + None.into_iter().chain(targets.all_targets().into_iter().copied()) + } // For all other kinds, return only the first successor, if any, and ignore unwinds. // NOTE: `chain(&[])` is required to coerce the `option::iter` (from // `next().into_iter()`) into the `mir::Successors` aliased type. - _ => successors.next().into_iter().chain(&[]), + _ => term_kind.successors().next().into_iter().chain((&[]).into_iter().copied()), } - .copied() .filter(move |&successor| body[successor].terminator().kind != TerminatorKind::Unreachable), ) } @@ -691,12 +691,9 @@ pub(super) fn find_loop_backedges( pub struct ShortCircuitPreorder< 'a, 'tcx, - F: Fn( - &'tcx &'a mir::Body<'tcx>, - &'tcx TerminatorKind<'tcx>, - ) -> Box + 'a>, + F: Fn(&'a mir::Body<'tcx>, &'a TerminatorKind<'tcx>) -> Box + 'a>, > { - body: &'tcx &'a mir::Body<'tcx>, + body: &'a mir::Body<'tcx>, visited: BitSet, worklist: Vec, filtered_successors: F, @@ -705,14 +702,11 @@ pub struct ShortCircuitPreorder< impl< 'a, 'tcx, - F: Fn( - &'tcx &'a mir::Body<'tcx>, - &'tcx TerminatorKind<'tcx>, - ) -> Box + 'a>, + F: Fn(&'a mir::Body<'tcx>, &'a TerminatorKind<'tcx>) -> Box + 'a>, > ShortCircuitPreorder<'a, 'tcx, F> { pub fn new( - body: &'tcx &'a mir::Body<'tcx>, + body: &'a mir::Body<'tcx>, filtered_successors: F, ) -> ShortCircuitPreorder<'a, 'tcx, F> { let worklist = vec![mir::START_BLOCK]; @@ -727,12 +721,9 @@ impl< } impl< - 'a: 'tcx, + 'a, 'tcx, - F: Fn( - &'tcx &'a mir::Body<'tcx>, - &'tcx TerminatorKind<'tcx>, - ) -> Box + 'a>, + F: Fn(&'a mir::Body<'tcx>, &'a TerminatorKind<'tcx>) -> Box + 'a>, > Iterator for ShortCircuitPreorder<'a, 'tcx, F> { type Item = (BasicBlock, &'a BasicBlockData<'tcx>); diff --git a/compiler/rustc_mir_transform/src/coverage/tests.rs b/compiler/rustc_mir_transform/src/coverage/tests.rs index d787443f6aa4e..213bb6608e139 100644 --- a/compiler/rustc_mir_transform/src/coverage/tests.rs +++ b/compiler/rustc_mir_transform/src/coverage/tests.rs @@ -37,7 +37,7 @@ use rustc_data_structures::graph::WithSuccessors; use rustc_index::vec::{Idx, IndexVec}; use rustc_middle::mir::coverage::CoverageKind; use rustc_middle::mir::*; -use rustc_middle::ty::{self, BOOL_TY}; +use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::{self, BytePos, Pos, Span, DUMMY_SP}; // All `TEMP_BLOCK` targets should be replaced before calling `to_body() -> mir::Body`. @@ -47,6 +47,7 @@ struct MockBlocks<'tcx> { blocks: IndexVec>, dummy_place: Place<'tcx>, next_local: usize, + bool_ty: Ty<'tcx>, } impl<'tcx> MockBlocks<'tcx> { @@ -55,6 +56,7 @@ impl<'tcx> MockBlocks<'tcx> { blocks: IndexVec::new(), dummy_place: Place { local: RETURN_PLACE, projection: ty::List::empty() }, next_local: 0, + bool_ty: TyCtxt::BOOL_TY_FOR_UNIT_TESTING, } } @@ -84,7 +86,7 @@ impl<'tcx> MockBlocks<'tcx> { fn link(&mut self, from_block: BasicBlock, to_block: BasicBlock) { match self.blocks[from_block].terminator_mut().kind { TerminatorKind::Assert { ref mut target, .. } - | TerminatorKind::Call { destination: Some((_, ref mut target)), .. } + | TerminatorKind::Call { target: Some(ref mut target), .. } | TerminatorKind::Drop { ref mut target, .. } | TerminatorKind::DropAndReplace { ref mut target, .. } | TerminatorKind::FalseEdge { real_target: ref mut target, .. } @@ -139,7 +141,8 @@ impl<'tcx> MockBlocks<'tcx> { TerminatorKind::Call { func: Operand::Copy(self.dummy_place.clone()), args: vec![], - destination: Some((self.dummy_place.clone(), TEMP_BLOCK)), + destination: self.dummy_place.clone(), + target: Some(TEMP_BLOCK), cleanup: None, from_hir_call: false, fn_span: DUMMY_SP, @@ -154,7 +157,7 @@ impl<'tcx> MockBlocks<'tcx> { fn switchint(&mut self, some_from_block: Option) -> BasicBlock { let switchint_kind = TerminatorKind::SwitchInt { discr: Operand::Move(Place::from(self.new_temp())), - switch_ty: BOOL_TY, // just a dummy value + switch_ty: self.bool_ty, // just a dummy value targets: SwitchTargets::static_if(0, TEMP_BLOCK, TEMP_BLOCK), }; self.add_block_from(some_from_block, switchint_kind) @@ -182,7 +185,7 @@ fn debug_basic_blocks<'tcx>(mir_body: &Body<'tcx>) -> String { let sp = format!("(span:{},{})", span.lo().to_u32(), span.hi().to_u32()); match kind { TerminatorKind::Assert { target, .. } - | TerminatorKind::Call { destination: Some((_, target)), .. } + | TerminatorKind::Call { target: Some(target), .. } | TerminatorKind::Drop { target, .. } | TerminatorKind::DropAndReplace { target, .. } | TerminatorKind::FalseEdge { real_target: target, .. } diff --git a/compiler/rustc_mir_transform/src/dead_store_elimination.rs b/compiler/rustc_mir_transform/src/dead_store_elimination.rs new file mode 100644 index 0000000000000..8becac34ed7ee --- /dev/null +++ b/compiler/rustc_mir_transform/src/dead_store_elimination.rs @@ -0,0 +1,148 @@ +//! This module implements a dead store elimination (DSE) routine. +//! +//! This transformation was written specifically for the needs of dest prop. Although it is +//! perfectly sound to use it in any context that might need it, its behavior should not be changed +//! without analyzing the interaction this will have with dest prop. Specifically, in addition to +//! the soundness of this pass in general, dest prop needs it to satisfy two additional conditions: +//! +//! 1. It's idempotent, meaning that running this pass a second time immediately after running it a +//! first time will not cause any further changes. +//! 2. This idempotence persists across dest prop's main transform, in other words inserting any +//! number of iterations of dest prop between the first and second application of this transform +//! will still not cause any further changes. +//! + +use rustc_index::bit_set::BitSet; +use rustc_middle::{ + mir::{visit::Visitor, *}, + ty::TyCtxt, +}; +use rustc_mir_dataflow::{impls::MaybeTransitiveLiveLocals, Analysis}; + +/// Performs the optimization on the body +/// +/// The `borrowed` set must be a `BitSet` of all the locals that are ever borrowed in this body. It +/// can be generated via the [`get_borrowed_locals`] function. +pub fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, borrowed: &BitSet) { + let mut live = MaybeTransitiveLiveLocals::new(borrowed) + .into_engine(tcx, body) + .iterate_to_fixpoint() + .into_results_cursor(body); + + let mut patch = Vec::new(); + for (bb, bb_data) in traversal::preorder(body) { + for (statement_index, statement) in bb_data.statements.iter().enumerate().rev() { + let loc = Location { block: bb, statement_index }; + if let StatementKind::Assign(assign) = &statement.kind { + if assign.1.is_pointer_int_cast() { + continue; + } + } + match &statement.kind { + StatementKind::Assign(box (place, _)) + | StatementKind::SetDiscriminant { place: box place, .. } + | StatementKind::Deinit(box place) => { + if !place.is_indirect() && !borrowed.contains(place.local) { + live.seek_before_primary_effect(loc); + if !live.get().contains(place.local) { + patch.push(loc); + } + } + } + StatementKind::Retag(_, _) + | StatementKind::StorageLive(_) + | StatementKind::StorageDead(_) + | StatementKind::Coverage(_) + | StatementKind::CopyNonOverlapping(_) + | StatementKind::Nop => (), + + StatementKind::FakeRead(_) | StatementKind::AscribeUserType(_, _) => { + bug!("{:?} not found in this MIR phase!", &statement.kind) + } + } + } + } + + if patch.is_empty() { + return; + } + + let bbs = body.basic_blocks_mut(); + for Location { block, statement_index } in patch { + bbs[block].statements[statement_index].make_nop(); + } +} + +pub fn get_borrowed_locals(body: &Body<'_>) -> BitSet { + let mut b = BorrowedLocals(BitSet::new_empty(body.local_decls.len())); + b.visit_body(body); + b.0 +} + +struct BorrowedLocals(BitSet); + +impl<'tcx> Visitor<'tcx> for BorrowedLocals { + fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, loc: Location) { + self.super_rvalue(rvalue, loc); + match rvalue { + Rvalue::AddressOf(_, borrowed_place) | Rvalue::Ref(_, _, borrowed_place) => { + if !borrowed_place.is_indirect() { + self.0.insert(borrowed_place.local); + } + } + + Rvalue::Cast(..) + | Rvalue::ShallowInitBox(..) + | Rvalue::Use(..) + | Rvalue::Repeat(..) + | Rvalue::Len(..) + | Rvalue::BinaryOp(..) + | Rvalue::CheckedBinaryOp(..) + | Rvalue::NullaryOp(..) + | Rvalue::UnaryOp(..) + | Rvalue::Discriminant(..) + | Rvalue::Aggregate(..) + | Rvalue::ThreadLocalRef(..) => {} + } + } + + fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { + self.super_terminator(terminator, location); + + match terminator.kind { + TerminatorKind::Drop { place: dropped_place, .. } => { + if !dropped_place.is_indirect() { + self.0.insert(dropped_place.local); + } + } + + TerminatorKind::Abort + | TerminatorKind::DropAndReplace { .. } + | TerminatorKind::Assert { .. } + | TerminatorKind::Call { .. } + | TerminatorKind::FalseEdge { .. } + | TerminatorKind::FalseUnwind { .. } + | TerminatorKind::GeneratorDrop + | TerminatorKind::Goto { .. } + | TerminatorKind::Resume + | TerminatorKind::Return + | TerminatorKind::SwitchInt { .. } + | TerminatorKind::Unreachable + | TerminatorKind::Yield { .. } + | TerminatorKind::InlineAsm { .. } => {} + } + } +} + +pub struct DeadStoreElimination; + +impl<'tcx> MirPass<'tcx> for DeadStoreElimination { + fn is_enabled(&self, sess: &rustc_session::Session) -> bool { + sess.mir_opt_level() >= 2 + } + + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + let borrowed = get_borrowed_locals(body); + eliminate(tcx, body, &borrowed); + } +} diff --git a/compiler/rustc_mir_transform/src/deref_separator.rs b/compiler/rustc_mir_transform/src/deref_separator.rs index 57a95a67df70c..bfb3ad1be2734 100644 --- a/compiler/rustc_mir_transform/src/deref_separator.rs +++ b/compiler/rustc_mir_transform/src/deref_separator.rs @@ -1,9 +1,11 @@ use crate::MirPass; use rustc_index::vec::IndexVec; use rustc_middle::mir::patch::MirPatch; +use rustc_middle::mir::visit::NonUseContext::VarDebugInfo; use rustc_middle::mir::visit::{MutVisitor, PlaceContext}; use rustc_middle::mir::*; use rustc_middle::ty::TyCtxt; + pub struct Derefer; pub struct DerefChecker<'tcx> { @@ -17,63 +19,68 @@ impl<'tcx> MutVisitor<'tcx> for DerefChecker<'tcx> { self.tcx } - fn visit_place(&mut self, place: &mut Place<'tcx>, _: PlaceContext, loc: Location) { - let mut place_local = place.local; - let mut last_len = 0; - let mut last_deref_idx = 0; + fn visit_place(&mut self, place: &mut Place<'tcx>, cntxt: PlaceContext, loc: Location) { + if !place.projection.is_empty() + && cntxt != PlaceContext::NonUse(VarDebugInfo) + && place.projection[1..].contains(&ProjectionElem::Deref) + { + let mut place_local = place.local; + let mut last_len = 0; + let mut last_deref_idx = 0; - let mut prev_temp: Option = None; + let mut prev_temp: Option = None; - for (idx, (p_ref, p_elem)) in place.iter_projections().enumerate() { - if p_elem == ProjectionElem::Deref && !p_ref.projection.is_empty() { - last_deref_idx = idx; - } - } - - for (idx, (p_ref, p_elem)) in place.iter_projections().enumerate() { - if p_elem == ProjectionElem::Deref && !p_ref.projection.is_empty() { - let ty = p_ref.ty(&self.local_decls, self.tcx).ty; - let temp = self.patcher.new_local_with_info( - ty, - self.local_decls[p_ref.local].source_info.span, - Some(Box::new(LocalInfo::DerefTemp)), - ); - - self.patcher.add_statement(loc, StatementKind::StorageLive(temp)); - - // We are adding current p_ref's projections to our - // temp value, excluding projections we already covered. - let deref_place = Place::from(place_local) - .project_deeper(&p_ref.projection[last_len..], self.tcx); - - self.patcher.add_assign( - loc, - Place::from(temp), - Rvalue::Use(Operand::Move(deref_place)), - ); - place_local = temp; - last_len = p_ref.projection.len(); - - // Change `Place` only if we are actually at the Place's last deref - if idx == last_deref_idx { - let temp_place = - Place::from(temp).project_deeper(&place.projection[idx..], self.tcx); - *place = temp_place; + for (idx, elem) in place.projection[0..].iter().enumerate() { + if *elem == ProjectionElem::Deref { + last_deref_idx = idx; } - - // We are destroying the previous temp since it's no longer used. - if let Some(prev_temp) = prev_temp { - self.patcher.add_statement(loc, StatementKind::StorageDead(prev_temp)); + } + for (idx, (p_ref, p_elem)) in place.iter_projections().enumerate() { + if !p_ref.projection.is_empty() && p_elem == ProjectionElem::Deref { + let ty = p_ref.ty(&self.local_decls, self.tcx).ty; + let temp = self.patcher.new_local_with_info( + ty, + self.local_decls[p_ref.local].source_info.span, + Some(Box::new(LocalInfo::DerefTemp)), + ); + + self.patcher.add_statement(loc, StatementKind::StorageLive(temp)); + + // We are adding current p_ref's projections to our + // temp value, excluding projections we already covered. + let deref_place = Place::from(place_local) + .project_deeper(&p_ref.projection[last_len..], self.tcx); + + self.patcher.add_assign( + loc, + Place::from(temp), + Rvalue::Use(Operand::Move(deref_place)), + ); + place_local = temp; + last_len = p_ref.projection.len(); + + // Change `Place` only if we are actually at the Place's last deref + if idx == last_deref_idx { + let temp_place = + Place::from(temp).project_deeper(&place.projection[idx..], self.tcx); + *place = temp_place; + } + + // We are destroying the previous temp since it's no longer used. + if let Some(prev_temp) = prev_temp { + self.patcher.add_statement(loc, StatementKind::StorageDead(prev_temp)); + } + + prev_temp = Some(temp); } - - prev_temp = Some(temp); } - } - // Since we won't be able to reach final temp, we destroy it outside the loop. - if let Some(prev_temp) = prev_temp { - let last_loc = Location { block: loc.block, statement_index: loc.statement_index + 1 }; - self.patcher.add_statement(last_loc, StatementKind::StorageDead(prev_temp)); + // Since we won't be able to reach final temp, we destroy it outside the loop. + if let Some(prev_temp) = prev_temp { + let last_loc = + Location { block: loc.block, statement_index: loc.statement_index + 1 }; + self.patcher.add_statement(last_loc, StatementKind::StorageDead(prev_temp)); + } } } } @@ -92,5 +99,6 @@ pub fn deref_finder<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { impl<'tcx> MirPass<'tcx> for Derefer { fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { deref_finder(tcx, body); + body.phase = MirPhase::Derefered; } } diff --git a/compiler/rustc_mir_transform/src/dest_prop.rs b/compiler/rustc_mir_transform/src/dest_prop.rs index 3732a308e3ac3..182dd6f379cc1 100644 --- a/compiler/rustc_mir_transform/src/dest_prop.rs +++ b/compiler/rustc_mir_transform/src/dest_prop.rs @@ -575,7 +575,8 @@ impl<'a> Conflicts<'a> { TerminatorKind::Call { func, args, - destination: Some((dest_place, _)), + destination, + target: _, cleanup: _, from_hir_call: _, fn_span: _, @@ -583,9 +584,9 @@ impl<'a> Conflicts<'a> { // No arguments may overlap with the destination. for arg in args.iter().chain(Some(func)) { if let Some(place) = arg.place() { - if !place.is_indirect() && !dest_place.is_indirect() { + if !place.is_indirect() && !destination.is_indirect() { self.record_local_conflict( - dest_place.local, + destination.local, place.local, "call dest/arg overlap", ); @@ -691,7 +692,6 @@ impl<'a> Conflicts<'a> { } TerminatorKind::Goto { .. } - | TerminatorKind::Call { destination: None, .. } | TerminatorKind::SwitchInt { .. } | TerminatorKind::Resume | TerminatorKind::Abort diff --git a/compiler/rustc_mir_transform/src/elaborate_drops.rs b/compiler/rustc_mir_transform/src/elaborate_drops.rs index f78c7a084d89a..8a9f21073165b 100644 --- a/compiler/rustc_mir_transform/src/elaborate_drops.rs +++ b/compiler/rustc_mir_transform/src/elaborate_drops.rs @@ -494,15 +494,13 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { fn drop_flags_for_fn_rets(&mut self) { for (bb, data) in self.body.basic_blocks().iter_enumerated() { if let TerminatorKind::Call { - destination: Some((ref place, tgt)), - cleanup: Some(_), - .. + destination, target: Some(tgt), cleanup: Some(_), .. } = data.terminator().kind { assert!(!self.patch.is_patched(bb)); let loc = Location { block: tgt, statement_index: 0 }; - let path = self.move_data().rev_lookup.find(place.as_ref()); + let path = self.move_data().rev_lookup.find(destination.as_ref()); on_lookup_result_bits(self.tcx, self.body, self.move_data(), path, |child| { self.set_drop_flag(loc, child, DropFlagState::Present) }); @@ -576,14 +574,13 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { // There may be a critical edge after this call, // so mark the return as initialized *before* the // call. - if let TerminatorKind::Call { - destination: Some((ref place, _)), cleanup: None, .. - } = data.terminator().kind + if let TerminatorKind::Call { destination, target: Some(_), cleanup: None, .. } = + data.terminator().kind { assert!(!self.patch.is_patched(bb)); let loc = Location { block: bb, statement_index: data.statements.len() }; - let path = self.move_data().rev_lookup.find(place.as_ref()); + let path = self.move_data().rev_lookup.find(destination.as_ref()); on_lookup_result_bits(self.tcx, self.body, self.move_data(), path, |child| { self.set_drop_flag(loc, child, DropFlagState::Present) }); diff --git a/compiler/rustc_mir_transform/src/function_item_references.rs b/compiler/rustc_mir_transform/src/function_item_references.rs index 1f9bd90d11f68..2e4fe1e3e5dd8 100644 --- a/compiler/rustc_mir_transform/src/function_item_references.rs +++ b/compiler/rustc_mir_transform/src/function_item_references.rs @@ -37,6 +37,7 @@ impl<'tcx> Visitor<'tcx> for FunctionItemRefChecker<'_, 'tcx> { func, args, destination: _, + target: _, cleanup: _, from_hir_call: _, fn_span: _, diff --git a/compiler/rustc_mir_transform/src/generator.rs b/compiler/rustc_mir_transform/src/generator.rs index b7dec57b75768..9eb77f6021373 100644 --- a/compiler/rustc_mir_transform/src/generator.rs +++ b/compiler/rustc_mir_transform/src/generator.rs @@ -49,6 +49,7 @@ //! For generators with state 1 (returned) and state 2 (poisoned) it does nothing. //! Otherwise it drops all the values in scope at the last suspension point. +use crate::deref_separator::deref_finder; use crate::simplify; use crate::util::expand_aggregate; use crate::MirPass; @@ -1042,8 +1043,7 @@ fn can_unwind<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) -> bool { | TerminatorKind::Unreachable | TerminatorKind::GeneratorDrop | TerminatorKind::FalseEdge { .. } - | TerminatorKind::FalseUnwind { .. } - | TerminatorKind::InlineAsm { .. } => {} + | TerminatorKind::FalseUnwind { .. } => {} // Resume will *continue* unwinding, but if there's no other unwinding terminator it // will never be reached. @@ -1057,6 +1057,7 @@ fn can_unwind<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) -> bool { TerminatorKind::Drop { .. } | TerminatorKind::DropAndReplace { .. } | TerminatorKind::Call { .. } + | TerminatorKind::InlineAsm { .. } | TerminatorKind::Assert { .. } => return true, } } @@ -1368,6 +1369,9 @@ impl<'tcx> MirPass<'tcx> for StateTransform { // Create the Generator::resume function create_generator_resume_function(tcx, transform, body, can_return); + + // Run derefer to fix Derefs that are not in the first place + deref_finder(tcx, body); } } @@ -1459,12 +1463,13 @@ impl<'tcx> Visitor<'tcx> for EnsureGeneratorFieldAssignmentsNeverAlias<'_> { TerminatorKind::Call { func, args, - destination: Some((dest, _)), + destination, + target: Some(_), cleanup: _, from_hir_call: _, fn_span: _, } => { - self.check_assigned_place(*dest, |this| { + self.check_assigned_place(*destination, |this| { this.visit_operand(func, location); for arg in args { this.visit_operand(arg, location); diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index 012ce73075575..9526c0acc66d6 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -1,5 +1,5 @@ //! Inlining pass for MIR functions - +use crate::deref_separator::deref_finder; use rustc_attr::InlineAttr; use rustc_index::bit_set::BitSet; use rustc_index::vec::Idx; @@ -17,7 +17,7 @@ use crate::MirPass; use std::iter; use std::ops::{Range, RangeFrom}; -crate mod cycle; +pub(crate) mod cycle; const INSTR_COST: usize = 5; const CALL_PENALTY: usize = 25; @@ -53,6 +53,7 @@ impl<'tcx> MirPass<'tcx> for Inline { debug!("running simplify cfg on {:?}", body.source); CfgSimplifier::new(body).simplify(); remove_dead_blocks(tcx, body); + deref_finder(tcx, body); } } } @@ -248,7 +249,7 @@ impl<'tcx> Inliner<'tcx> { ) -> Option> { // Only consider direct calls to functions let terminator = bb_data.terminator(); - if let TerminatorKind::Call { ref func, ref destination, .. } = terminator.kind { + if let TerminatorKind::Call { ref func, target, .. } = terminator.kind { let func_ty = func.ty(caller_body, self.tcx); if let ty::FnDef(def_id, substs) = *func_ty.kind() { // To resolve an instance its substs have to be fully normalized. @@ -266,7 +267,7 @@ impl<'tcx> Inliner<'tcx> { callee, fn_sig, block: bb, - target: destination.map(|(_, target)| target), + target, source_info: terminator.source_info, }); } @@ -395,7 +396,7 @@ impl<'tcx> Inliner<'tcx> { } } - TerminatorKind::Unreachable | TerminatorKind::Call { destination: None, .. } + TerminatorKind::Unreachable | TerminatorKind::Call { target: None, .. } if first_block => { // If the function always diverges, don't inline @@ -418,8 +419,7 @@ impl<'tcx> Inliner<'tcx> { } } // Don't give intrinsics the extra penalty for calls - let f = tcx.fn_sig(def_id); - if f.abi() == Abi::RustIntrinsic || f.abi() == Abi::PlatformIntrinsic { + if tcx.is_intrinsic(def_id) { cost += INSTR_COST; } else { cost += CALL_PENALTY; @@ -450,7 +450,7 @@ impl<'tcx> Inliner<'tcx> { } if !is_drop { - for &succ in term.successors() { + for succ in term.successors() { work_list.push(succ); } } @@ -513,27 +513,22 @@ impl<'tcx> Inliner<'tcx> { false } - let dest = if let Some((destination_place, _)) = destination { - if dest_needs_borrow(destination_place) { - trace!("creating temp for return destination"); - let dest = Rvalue::Ref( - self.tcx.lifetimes.re_erased, - BorrowKind::Mut { allow_two_phase_borrow: false }, - destination_place, - ); - let dest_ty = dest.ty(caller_body, self.tcx); - let temp = Place::from(self.new_call_temp(caller_body, &callsite, dest_ty)); - caller_body[callsite.block].statements.push(Statement { - source_info: callsite.source_info, - kind: StatementKind::Assign(Box::new((temp, dest))), - }); - self.tcx.mk_place_deref(temp) - } else { - destination_place - } + let dest = if dest_needs_borrow(destination) { + trace!("creating temp for return destination"); + let dest = Rvalue::Ref( + self.tcx.lifetimes.re_erased, + BorrowKind::Mut { allow_two_phase_borrow: false }, + destination, + ); + let dest_ty = dest.ty(caller_body, self.tcx); + let temp = Place::from(self.new_call_temp(caller_body, &callsite, dest_ty)); + caller_body[callsite.block].statements.push(Statement { + source_info: callsite.source_info, + kind: StatementKind::Assign(Box::new((temp, dest))), + }); + self.tcx.mk_place_deref(temp) } else { - trace!("creating temp for return place"); - Place::from(self.new_call_temp(caller_body, &callsite, callee_body.return_ty())) + destination }; // Copy the arguments if needed. @@ -555,7 +550,8 @@ impl<'tcx> Inliner<'tcx> { new_scopes: SourceScope::new(caller_body.source_scopes.len()).., new_blocks: BasicBlock::new(caller_body.basic_blocks().len()).., destination: dest, - return_block: callsite.target, + callsite_scope: caller_body.source_scopes[callsite.source_info.scope].clone(), + callsite, cleanup_block: cleanup, in_cleanup_block: false, tcx: self.tcx, @@ -567,31 +563,6 @@ impl<'tcx> Inliner<'tcx> { // (or existing ones, in a few special cases) in the caller. integrator.visit_body(&mut callee_body); - for scope in &mut callee_body.source_scopes { - // FIXME(eddyb) move this into a `fn visit_scope_data` in `Integrator`. - if scope.parent_scope.is_none() { - let callsite_scope = &caller_body.source_scopes[callsite.source_info.scope]; - - // Attach the outermost callee scope as a child of the callsite - // scope, via the `parent_scope` and `inlined_parent_scope` chains. - scope.parent_scope = Some(callsite.source_info.scope); - assert_eq!(scope.inlined_parent_scope, None); - scope.inlined_parent_scope = if callsite_scope.inlined.is_some() { - Some(callsite.source_info.scope) - } else { - callsite_scope.inlined_parent_scope - }; - - // Mark the outermost callee scope as an inlined one. - assert_eq!(scope.inlined, None); - scope.inlined = Some((callsite.callee, callsite.source_info.span)); - } else if scope.inlined_parent_scope.is_none() { - // Make it easy to find the scope with `inlined` set above. - scope.inlined_parent_scope = - Some(integrator.map_scope(OUTERMOST_SOURCE_SCOPE)); - } - } - // If there are any locals without storage markers, give them storage only for the // duration of the call. for local in callee_body.vars_and_temps_iter() { @@ -787,7 +758,8 @@ struct Integrator<'a, 'tcx> { new_scopes: RangeFrom, new_blocks: RangeFrom, destination: Place<'tcx>, - return_block: Option, + callsite_scope: SourceScopeData<'tcx>, + callsite: &'a CallSite<'tcx>, cleanup_block: Option, in_cleanup_block: bool, tcx: TyCtxt<'tcx>, @@ -833,6 +805,28 @@ impl<'tcx> MutVisitor<'tcx> for Integrator<'_, 'tcx> { *local = self.map_local(*local); } + fn visit_source_scope_data(&mut self, scope_data: &mut SourceScopeData<'tcx>) { + self.super_source_scope_data(scope_data); + if scope_data.parent_scope.is_none() { + // Attach the outermost callee scope as a child of the callsite + // scope, via the `parent_scope` and `inlined_parent_scope` chains. + scope_data.parent_scope = Some(self.callsite.source_info.scope); + assert_eq!(scope_data.inlined_parent_scope, None); + scope_data.inlined_parent_scope = if self.callsite_scope.inlined.is_some() { + Some(self.callsite.source_info.scope) + } else { + self.callsite_scope.inlined_parent_scope + }; + + // Mark the outermost callee scope as an inlined one. + assert_eq!(scope_data.inlined, None); + scope_data.inlined = Some((self.callsite.callee, self.callsite.source_info.span)); + } else if scope_data.inlined_parent_scope.is_none() { + // Make it easy to find the scope with `inlined` set above. + scope_data.inlined_parent_scope = Some(self.map_scope(OUTERMOST_SOURCE_SCOPE)); + } + } + fn visit_source_scope(&mut self, scope: &mut SourceScope) { *scope = self.map_scope(*scope); } @@ -916,8 +910,8 @@ impl<'tcx> MutVisitor<'tcx> for Integrator<'_, 'tcx> { *unwind = self.cleanup_block; } } - TerminatorKind::Call { ref mut destination, ref mut cleanup, .. } => { - if let Some((_, ref mut tgt)) = *destination { + TerminatorKind::Call { ref mut target, ref mut cleanup, .. } => { + if let Some(ref mut tgt) = *target { *tgt = self.map_block(*tgt); } if let Some(tgt) = *cleanup { @@ -939,7 +933,7 @@ impl<'tcx> MutVisitor<'tcx> for Integrator<'_, 'tcx> { } } TerminatorKind::Return => { - terminator.kind = if let Some(tgt) = self.return_block { + terminator.kind = if let Some(tgt) = self.callsite.target { TerminatorKind::Goto { target: tgt } } else { TerminatorKind::Unreachable diff --git a/compiler/rustc_mir_transform/src/inline/cycle.rs b/compiler/rustc_mir_transform/src/inline/cycle.rs index bee6aeebcf845..fd7de2bd1dcf8 100644 --- a/compiler/rustc_mir_transform/src/inline/cycle.rs +++ b/compiler/rustc_mir_transform/src/inline/cycle.rs @@ -9,7 +9,7 @@ use rustc_session::Limit; // FIXME: check whether it is cheaper to precompute the entire call graph instead of invoking // this query ridiculously often. #[instrument(level = "debug", skip(tcx, root, target))] -crate fn mir_callgraph_reachable<'tcx>( +pub(crate) fn mir_callgraph_reachable<'tcx>( tcx: TyCtxt<'tcx>, (root, target): (ty::Instance<'tcx>, LocalDefId), ) -> bool { @@ -136,7 +136,7 @@ crate fn mir_callgraph_reachable<'tcx>( ) } -crate fn mir_inliner_callees<'tcx>( +pub(crate) fn mir_inliner_callees<'tcx>( tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>, ) -> &'tcx [(DefId, SubstsRef<'tcx>)] { diff --git a/compiler/rustc_mir_transform/src/instcombine.rs b/compiler/rustc_mir_transform/src/instcombine.rs index d1c4a4b21d0a2..4fbb764337863 100644 --- a/compiler/rustc_mir_transform/src/instcombine.rs +++ b/compiler/rustc_mir_transform/src/instcombine.rs @@ -141,7 +141,7 @@ impl<'tcx> InstCombineContext<'tcx, '_> { terminator: &mut Terminator<'tcx>, statements: &mut Vec>, ) { - let TerminatorKind::Call { func, args, destination, .. } = &mut terminator.kind + let TerminatorKind::Call { func, args, destination, target, .. } = &mut terminator.kind else { return }; // It's definitely not a clone if there are multiple arguments @@ -149,7 +149,7 @@ impl<'tcx> InstCombineContext<'tcx, '_> { return; } - let Some((destination_place, destination_block)) = *destination + let Some(destination_block) = *target else { return }; // Only bother looking more if it's easy to know what we're calling @@ -192,12 +192,12 @@ impl<'tcx> InstCombineContext<'tcx, '_> { statements.push(Statement { source_info: terminator.source_info, - kind: StatementKind::Assign(box ( - destination_place, + kind: StatementKind::Assign(Box::new(( + *destination, Rvalue::Use(Operand::Copy( arg_place.project_deeper(&[ProjectionElem::Deref], self.tcx), )), - )), + ))), }); terminator.kind = TerminatorKind::Goto { target: destination_block }; } diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 40cc6dafe6177..0e57c3c697999 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -1,7 +1,5 @@ #![allow(rustc::potential_query_instability)] #![feature(box_patterns)] -#![feature(box_syntax)] -#![feature(crate_visibility_modifier)] #![feature(let_chains)] #![feature(let_else)] #![feature(map_try_insert)] @@ -51,6 +49,7 @@ mod const_goto; mod const_prop; mod const_prop_lint; mod coverage; +mod dead_store_elimination; mod deaggregator; mod deduplicate_blocks; mod deref_separator; @@ -170,7 +169,7 @@ fn mir_keys(tcx: TyCtxt<'_>, (): ()) -> FxIndexSet { intravisit::walk_struct_def(self, v) } } - tcx.hir().visit_all_item_likes(&mut GatherCtors { tcx, set: &mut set }.as_deep_visitor()); + tcx.hir().deep_visit_all_item_likes(&mut GatherCtors { tcx, set: &mut set }); set } @@ -483,17 +482,18 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { &const_prop::ConstProp, // // Const-prop runs unconditionally, but doesn't mutate the MIR at mir-opt-level=0. + &const_debuginfo::ConstDebugInfo, &o1(simplify_branches::SimplifyConstCondition::new("after-const-prop")), &early_otherwise_branch::EarlyOtherwiseBranch, &simplify_comparison_integral::SimplifyComparisonIntegral, &simplify_try::SimplifyArmIdentity, &simplify_try::SimplifyBranchSame, + &dead_store_elimination::DeadStoreElimination, &dest_prop::DestinationPropagation, &o1(simplify_branches::SimplifyConstCondition::new("final")), &o1(remove_noop_landing_pads::RemoveNoopLandingPads), &o1(simplify::SimplifyCfg::new("final")), &nrvo::RenameReturnPlace, - &const_debuginfo::ConstDebugInfo, &simplify::SimplifyLocals, &multiple_return_terminators::MultipleReturnTerminators, &deduplicate_blocks::DeduplicateBlocks, diff --git a/compiler/rustc_mir_transform/src/lower_intrinsics.rs b/compiler/rustc_mir_transform/src/lower_intrinsics.rs index 684d988ee9ed2..65801069560b3 100644 --- a/compiler/rustc_mir_transform/src/lower_intrinsics.rs +++ b/compiler/rustc_mir_transform/src/lower_intrinsics.rs @@ -6,7 +6,6 @@ use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::symbol::{sym, Symbol}; use rustc_span::Span; -use rustc_target::spec::abi::Abi; pub struct LowerIntrinsics; @@ -15,7 +14,9 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics { let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut(); for block in basic_blocks { let terminator = block.terminator.as_mut().unwrap(); - if let TerminatorKind::Call { func, args, destination, .. } = &mut terminator.kind { + if let TerminatorKind::Call { func, args, destination, target, .. } = + &mut terminator.kind + { let func_ty = func.ty(local_decls, tcx); let Some((intrinsic_name, substs)) = resolve_rust_intrinsic(tcx, func_ty) else { continue; @@ -25,11 +26,11 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics { terminator.kind = TerminatorKind::Unreachable; } sym::forget => { - if let Some((destination, target)) = *destination { + if let Some(target) = *target { block.statements.push(Statement { source_info: terminator.source_info, kind: StatementKind::Assign(Box::new(( - destination, + *destination, Rvalue::Use(Operand::Constant(Box::new(Constant { span: terminator.source_info.span, user_ty: None, @@ -41,7 +42,7 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics { } } sym::copy_nonoverlapping => { - let target = destination.unwrap().1; + let target = target.unwrap(); let mut args = args.drain(..); block.statements.push(Statement { source_info: terminator.source_info, @@ -62,7 +63,7 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics { terminator.kind = TerminatorKind::Goto { target }; } sym::wrapping_add | sym::wrapping_sub | sym::wrapping_mul => { - if let Some((destination, target)) = *destination { + if let Some(target) = *target { let lhs; let rhs; { @@ -79,7 +80,7 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics { block.statements.push(Statement { source_info: terminator.source_info, kind: StatementKind::Assign(Box::new(( - destination, + *destination, Rvalue::BinaryOp(bin_op, Box::new((lhs, rhs))), ))), }); @@ -92,7 +93,7 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics { // during codegen. Issue #35310. } sym::size_of | sym::min_align_of => { - if let Some((destination, target)) = *destination { + if let Some(target) = *target { let tp_ty = substs.type_at(0); let null_op = match intrinsic_name { sym::size_of => NullOp::SizeOf, @@ -102,7 +103,7 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics { block.statements.push(Statement { source_info: terminator.source_info, kind: StatementKind::Assign(Box::new(( - destination, + *destination, Rvalue::NullaryOp(null_op, tp_ty), ))), }); @@ -110,14 +111,12 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics { } } sym::discriminant_value => { - if let (Some((destination, target)), Some(arg)) = - (*destination, args[0].place()) - { + if let (Some(target), Some(arg)) = (*target, args[0].place()) { let arg = tcx.mk_place_deref(arg); block.statements.push(Statement { source_info: terminator.source_info, kind: StatementKind::Assign(Box::new(( - destination, + *destination, Rvalue::Discriminant(arg), ))), }); @@ -139,8 +138,7 @@ fn resolve_rust_intrinsic<'tcx>( func_ty: Ty<'tcx>, ) -> Option<(Symbol, SubstsRef<'tcx>)> { if let ty::FnDef(def_id, substs) = *func_ty.kind() { - let fn_sig = func_ty.fn_sig(tcx); - if let Abi::RustIntrinsic | Abi::PlatformIntrinsic = fn_sig.abi() { + if tcx.is_intrinsic(def_id) { return Some((tcx.item_name(def_id), substs)); } } diff --git a/compiler/rustc_mir_transform/src/lower_slice_len.rs b/compiler/rustc_mir_transform/src/lower_slice_len.rs index 43d1d62a21efb..07163cfe57510 100644 --- a/compiler/rustc_mir_transform/src/lower_slice_len.rs +++ b/compiler/rustc_mir_transform/src/lower_slice_len.rs @@ -52,7 +52,8 @@ fn lower_slice_len_call<'tcx>( TerminatorKind::Call { func, args, - destination: Some((dest, bb)), + destination, + target: Some(bb), cleanup: None, from_hir_call: true, .. @@ -73,7 +74,8 @@ fn lower_slice_len_call<'tcx>( // make new RValue for Len let deref_arg = tcx.mk_place_deref(arg); let r_value = Rvalue::Len(deref_arg); - let len_statement_kind = StatementKind::Assign(Box::new((*dest, r_value))); + let len_statement_kind = + StatementKind::Assign(Box::new((*destination, r_value))); let add_statement = Statement { kind: len_statement_kind, source_info: terminator.source_info }; diff --git a/compiler/rustc_mir_transform/src/normalize_array_len.rs b/compiler/rustc_mir_transform/src/normalize_array_len.rs index cdfd49ef478a4..0f45711baa3ac 100644 --- a/compiler/rustc_mir_transform/src/normalize_array_len.rs +++ b/compiler/rustc_mir_transform/src/normalize_array_len.rs @@ -125,7 +125,7 @@ impl<'tcx> Patcher<'_, 'tcx> { let assign_to = Place::from(local); let rvalue = Rvalue::Use(operand); make_copy_statement.kind = - StatementKind::Assign(box (assign_to, rvalue)); + StatementKind::Assign(Box::new((assign_to, rvalue))); statements.push(make_copy_statement); // to reorder we have to copy and make NOP @@ -165,7 +165,8 @@ impl<'tcx> Patcher<'_, 'tcx> { if add_deref { place = self.tcx.mk_place_deref(place); } - len_statement.kind = StatementKind::Assign(box (*into, Rvalue::Len(place))); + len_statement.kind = + StatementKind::Assign(Box::new((*into, Rvalue::Len(place)))); statements.push(len_statement); // make temporary dead diff --git a/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs b/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs index 4d214b0356ca7..f925d13b2fb91 100644 --- a/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs +++ b/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs @@ -65,7 +65,7 @@ impl RemoveNoopLandingPads { | TerminatorKind::SwitchInt { .. } | TerminatorKind::FalseEdge { .. } | TerminatorKind::FalseUnwind { .. } => { - terminator.successors().all(|&succ| nop_landing_pads.contains(succ)) + terminator.successors().all(|succ| nop_landing_pads.contains(succ)) } TerminatorKind::GeneratorDrop | TerminatorKind::Yield { .. } diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index 016b3bc098073..78a4ece2ecbb3 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -450,7 +450,8 @@ impl<'tcx> CloneShimBuilder<'tcx> { TerminatorKind::Call { func, args: vec![Operand::Move(ref_loc)], - destination: Some((dest, next)), + destination: dest, + target: Some(next), cleanup: Some(cleanup), from_hir_call: true, fn_span: self.span, @@ -676,7 +677,8 @@ fn build_call_shim<'tcx>( TerminatorKind::Call { func: callee, args, - destination: Some((Place::return_place(), BasicBlock::new(1))), + destination: Place::return_place(), + target: Some(BasicBlock::new(1)), cleanup: if let Some(Adjustment::RefMut) = rcvr_adjustment { Some(BasicBlock::new(3)) } else { diff --git a/compiler/rustc_mir_transform/src/simplify.rs b/compiler/rustc_mir_transform/src/simplify.rs index b42e3909cf386..72e0834392576 100644 --- a/compiler/rustc_mir_transform/src/simplify.rs +++ b/compiler/rustc_mir_transform/src/simplify.rs @@ -81,7 +81,7 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> { for (_, data) in traversal::preorder(body) { if let Some(ref term) = data.terminator { - for &tgt in term.successors() { + for tgt in term.successors() { pred_count[tgt] += 1; } } @@ -235,8 +235,8 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> { }; let first_succ = { - if let Some(&first_succ) = terminator.successors().next() { - if terminator.successors().all(|s| *s == first_succ) { + if let Some(first_succ) = terminator.successors().next() { + if terminator.successors().all(|s| s == first_succ) { let count = terminator.successors().count(); self.pred_count[first_succ] -= (count - 1) as u32; first_succ diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index ee02151152c6f..a9ca89217972e 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -201,7 +201,6 @@ use rustc_session::lint::builtin::LARGE_ASSIGNMENTS; use rustc_session::Limit; use rustc_span::source_map::{dummy_spanned, respan, Span, Spanned, DUMMY_SP}; use rustc_target::abi::Size; -use smallvec::SmallVec; use std::iter; use std::ops::Range; use std::path::PathBuf; @@ -226,6 +225,44 @@ pub struct InliningMap<'tcx> { inlines: GrowableBitSet, } +/// Struct to store mono items in each collecting and if they should +/// be inlined. We call `instantiation_mode` to get their inlining +/// status when inserting new elements, which avoids calling it in +/// `inlining_map.lock_mut()`. See the `collect_items_rec` implementation +/// below. +struct MonoItems<'tcx> { + // If this is false, we do not need to compute whether items + // will need to be inlined. + compute_inlining: bool, + + // The TyCtxt used to determine whether the a item should + // be inlined. + tcx: TyCtxt<'tcx>, + + // The collected mono items. The bool field in each element + // indicates whether this element should be inlined. + items: Vec<(Spanned>, bool /*inlined*/)>, +} + +impl<'tcx> MonoItems<'tcx> { + #[inline] + fn push(&mut self, item: Spanned>) { + self.extend([item]); + } + + #[inline] + fn extend>>>(&mut self, iter: T) { + self.items.extend(iter.into_iter().map(|mono_item| { + let inlined = if !self.compute_inlining { + false + } else { + mono_item.node.instantiation_mode(self.tcx) == InstantiationMode::LocalCopy + }; + (mono_item, inlined) + })) + } +} + impl<'tcx> InliningMap<'tcx> { fn new() -> InliningMap<'tcx> { InliningMap { @@ -235,7 +272,13 @@ impl<'tcx> InliningMap<'tcx> { } } - fn record_accesses(&mut self, source: MonoItem<'tcx>, new_targets: &[(MonoItem<'tcx>, bool)]) { + fn record_accesses<'a>( + &mut self, + source: MonoItem<'tcx>, + new_targets: &'a [(Spanned>, bool)], + ) where + 'tcx: 'a, + { let start_index = self.targets.len(); let new_items_count = new_targets.len(); let new_items_count_total = new_items_count + self.targets.len(); @@ -243,9 +286,9 @@ impl<'tcx> InliningMap<'tcx> { self.targets.reserve(new_items_count); self.inlines.ensure(new_items_count_total); - for (i, (target, inline)) in new_targets.iter().enumerate() { - self.targets.push(*target); - if *inline { + for (i, (Spanned { node: mono_item, .. }, inlined)) in new_targets.into_iter().enumerate() { + self.targets.push(*mono_item); + if *inlined { self.inlines.insert(i + start_index); } } @@ -321,7 +364,7 @@ pub fn collect_crate_mono_items( // start monomorphizing from. fn collect_roots(tcx: TyCtxt<'_>, mode: MonoItemCollectionMode) -> Vec> { debug!("collecting roots"); - let mut roots = Vec::new(); + let mut roots = MonoItems { compute_inlining: false, tcx, items: Vec::new() }; { let entry_fn = tcx.entry_fn(()); @@ -347,8 +390,11 @@ fn collect_roots(tcx: TyCtxt<'_>, mode: MonoItemCollectionMode) -> Vec( } debug!("BEGIN collect_items_rec({})", starting_point.node); - let mut neighbors = Vec::new(); + let mut neighbors = MonoItems { compute_inlining: true, tcx, items: Vec::new() }; let recursion_depth_reset; // @@ -483,10 +529,9 @@ fn collect_items_rec<'tcx>( &format!("the above error was encountered while instantiating `{}`", formatted_item), ); } + inlining_map.lock_mut().record_accesses(starting_point.node, &neighbors.items); - record_accesses(tcx, starting_point.node, neighbors.iter().map(|i| &i.node), inlining_map); - - for neighbour in neighbors { + for (neighbour, _) in neighbors.items { collect_items_rec(tcx, neighbour, visited, recursion_depths, recursion_limit, inlining_map); } @@ -497,25 +542,6 @@ fn collect_items_rec<'tcx>( debug!("END collect_items_rec({})", starting_point.node); } -fn record_accesses<'a, 'tcx: 'a>( - tcx: TyCtxt<'tcx>, - caller: MonoItem<'tcx>, - callees: impl Iterator>, - inlining_map: MTRef<'_, MTLock>>, -) { - let is_inlining_candidate = |mono_item: &MonoItem<'tcx>| { - mono_item.instantiation_mode(tcx) == InstantiationMode::LocalCopy - }; - - // We collect this into a `SmallVec` to avoid calling `is_inlining_candidate` in the lock. - // FIXME: Call `is_inlining_candidate` when pushing to `neighbors` in `collect_items_rec` - // instead to avoid creating this `SmallVec`. - let accesses: SmallVec<[_; 128]> = - callees.map(|mono_item| (*mono_item, is_inlining_candidate(mono_item))).collect(); - - inlining_map.lock_mut().record_accesses(caller, &accesses); -} - /// Format instance name that is already known to be too long for rustc. /// Show only the first and last 32 characters to avoid blasting /// the user's terminal with thousands of lines of type-name. @@ -627,7 +653,7 @@ fn check_type_length_limit<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) { struct MirNeighborCollector<'a, 'tcx> { tcx: TyCtxt<'tcx>, body: &'a mir::Body<'tcx>, - output: &'a mut Vec>>, + output: &'a mut MonoItems<'tcx>, instance: Instance<'tcx>, } @@ -905,7 +931,7 @@ fn visit_drop_use<'tcx>( ty: Ty<'tcx>, is_direct_call: bool, source: Span, - output: &mut Vec>>, + output: &mut MonoItems<'tcx>, ) { let instance = Instance::resolve_drop_in_place(tcx, ty); visit_instance_use(tcx, instance, is_direct_call, source, output); @@ -916,7 +942,7 @@ fn visit_fn_use<'tcx>( ty: Ty<'tcx>, is_direct_call: bool, source: Span, - output: &mut Vec>>, + output: &mut MonoItems<'tcx>, ) { if let ty::FnDef(def_id, substs) = *ty.kind() { let instance = if is_direct_call { @@ -934,7 +960,7 @@ fn visit_instance_use<'tcx>( instance: ty::Instance<'tcx>, is_direct_call: bool, source: Span, - output: &mut Vec>>, + output: &mut MonoItems<'tcx>, ) { debug!("visit_item_use({:?}, is_direct_call={:?})", instance, is_direct_call); if !should_codegen_locally(tcx, &instance) { @@ -1117,7 +1143,7 @@ fn create_mono_items_for_vtable_methods<'tcx>( trait_ty: Ty<'tcx>, impl_ty: Ty<'tcx>, source: Span, - output: &mut Vec>>, + output: &mut MonoItems<'tcx>, ) { assert!(!trait_ty.has_escaping_bound_vars() && !impl_ty.has_escaping_bound_vars()); @@ -1159,7 +1185,7 @@ fn create_mono_items_for_vtable_methods<'tcx>( struct RootCollector<'a, 'tcx> { tcx: TyCtxt<'tcx>, mode: MonoItemCollectionMode, - output: &'a mut Vec>>, + output: &'a mut MonoItems<'tcx>, entry_fn: Option<(DefId, EntryFnType)>, } @@ -1305,7 +1331,7 @@ fn item_requires_monomorphization(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { fn create_mono_items_for_default_impls<'tcx>( tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>, - output: &mut Vec>>, + output: &mut MonoItems<'tcx>, ) { match item.kind { hir::ItemKind::Impl(ref impl_) => { @@ -1361,11 +1387,7 @@ fn create_mono_items_for_default_impls<'tcx>( } /// Scans the miri alloc in order to find function calls, closures, and drop-glue. -fn collect_miri<'tcx>( - tcx: TyCtxt<'tcx>, - alloc_id: AllocId, - output: &mut Vec>>, -) { +fn collect_miri<'tcx>(tcx: TyCtxt<'tcx>, alloc_id: AllocId, output: &mut MonoItems<'tcx>) { match tcx.global_alloc(alloc_id) { GlobalAlloc::Static(def_id) => { assert!(!tcx.is_thread_local_static(def_id)); @@ -1396,7 +1418,7 @@ fn collect_miri<'tcx>( fn collect_neighbours<'tcx>( tcx: TyCtxt<'tcx>, instance: Instance<'tcx>, - output: &mut Vec>>, + output: &mut MonoItems<'tcx>, ) { debug!("collect_neighbours: {:?}", instance.def_id()); let body = tcx.instance_mir(instance.def); @@ -1407,7 +1429,7 @@ fn collect_neighbours<'tcx>( fn collect_const_value<'tcx>( tcx: TyCtxt<'tcx>, value: ConstValue<'tcx>, - output: &mut Vec>>, + output: &mut MonoItems<'tcx>, ) { match value { ConstValue::Scalar(Scalar::Ptr(ptr, _size)) => collect_miri(tcx, ptr.provenance, output), diff --git a/compiler/rustc_monomorphize/src/lib.rs b/compiler/rustc_monomorphize/src/lib.rs index f0333d6c6dace..ef4560b5ec48e 100644 --- a/compiler/rustc_monomorphize/src/lib.rs +++ b/compiler/rustc_monomorphize/src/lib.rs @@ -1,5 +1,4 @@ #![feature(array_windows)] -#![feature(crate_visibility_modifier)] #![feature(control_flow_enum)] #![feature(let_else)] #![recursion_limit = "256"] diff --git a/compiler/rustc_monomorphize/src/util.rs b/compiler/rustc_monomorphize/src/util.rs index 04baa01832be6..d3aaad4601561 100644 --- a/compiler/rustc_monomorphize/src/util.rs +++ b/compiler/rustc_monomorphize/src/util.rs @@ -7,7 +7,7 @@ use std::io::prelude::*; /// /// During the same compile all closures dump the information in the same file /// "closure_profile_XXXXX.csv", which is created in the directory where the compiler is invoked. -crate fn dump_closure_profile<'tcx>(tcx: TyCtxt<'tcx>, closure_instance: Instance<'tcx>) { +pub(crate) fn dump_closure_profile<'tcx>(tcx: TyCtxt<'tcx>, closure_instance: Instance<'tcx>) { let Ok(mut file) = OpenOptions::new() .create(true) .append(true) diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index ee54dd44f7194..e9701ec2d7f45 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -31,7 +31,7 @@ pub struct UnmatchedBrace { pub candidate_span: Option, } -crate fn parse_token_trees<'a>( +pub(crate) fn parse_token_trees<'a>( sess: &'a ParseSess, src: &'a str, start_pos: BytePos, diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index 423cddd88eeca..df1765952ceac 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -2,7 +2,6 @@ #![feature(array_windows)] #![feature(box_patterns)] -#![feature(crate_visibility_modifier)] #![feature(if_let_guard)] #![feature(let_chains)] #![feature(let_else)] @@ -13,20 +12,16 @@ extern crate tracing; use rustc_ast as ast; -use rustc_ast::token::{self, Nonterminal, Token, TokenKind}; -use rustc_ast::tokenstream::{self, AttributesData, CanSynthesizeMissingTokens, LazyTokenStream}; -use rustc_ast::tokenstream::{AttrAnnotatedTokenStream, AttrAnnotatedTokenTree}; -use rustc_ast::tokenstream::{Spacing, TokenStream}; +use rustc_ast::token; +use rustc_ast::tokenstream::TokenStream; use rustc_ast::Attribute; use rustc_ast::{AttrItem, MetaItem}; -use rustc_ast::{HasAttrs, HasSpan, HasTokens}; -use rustc_ast_pretty::pprust::{self, AstPrettyPrint}; +use rustc_ast_pretty::pprust; use rustc_data_structures::sync::Lrc; use rustc_errors::{Applicability, Diagnostic, FatalError, Level, PResult}; use rustc_session::parse::ParseSess; use rustc_span::{FileName, SourceFile, Span}; -use std::fmt; use std::path::Path; pub const MACRO_ARGUMENTS: Option<&str> = Some("macro arguments"); @@ -241,111 +236,10 @@ pub fn parse_in<'a, T>( Ok(result) } -// NOTE(Centril): The following probably shouldn't be here but it acknowledges the -// fact that architecturally, we are using parsing (read on below to understand why). - -pub fn to_token_stream( - node: &(impl HasAttrs + HasSpan + HasTokens + AstPrettyPrint + fmt::Debug), - sess: &ParseSess, - synthesize_tokens: CanSynthesizeMissingTokens, -) -> TokenStream { - if let Some(tokens) = prepend_attrs(&node.attrs(), node.tokens()) { - return tokens; - } else if matches!(synthesize_tokens, CanSynthesizeMissingTokens::Yes) { - return fake_token_stream(sess, node); - } else { - panic!("Missing tokens for nt {:?} at {:?}: {:?}", node, node.span(), node.pretty_print()); - } -} - -pub fn nt_to_tokenstream( - nt: &Nonterminal, - sess: &ParseSess, - synthesize_tokens: CanSynthesizeMissingTokens, -) -> TokenStream { - // A `Nonterminal` is often a parsed AST item. At this point we now - // need to convert the parsed AST to an actual token stream, e.g. - // un-parse it basically. - // - // Unfortunately there's not really a great way to do that in a - // guaranteed lossless fashion right now. The fallback here is to just - // stringify the AST node and reparse it, but this loses all span - // information. - // - // As a result, some AST nodes are annotated with the token stream they - // came from. Here we attempt to extract these lossless token streams - // before we fall back to the stringification. - - let convert_tokens = - |tokens: Option<&LazyTokenStream>| Some(tokens?.create_token_stream().to_tokenstream()); - - let tokens = match *nt { - Nonterminal::NtItem(ref item) => prepend_attrs(&item.attrs, item.tokens.as_ref()), - Nonterminal::NtBlock(ref block) => convert_tokens(block.tokens.as_ref()), - Nonterminal::NtStmt(ref stmt) if let ast::StmtKind::Empty = stmt.kind => { - let tokens = AttrAnnotatedTokenStream::new(vec![( - tokenstream::AttrAnnotatedTokenTree::Token(Token::new( - TokenKind::Semi, - stmt.span, - )), - Spacing::Alone, - )]); - prepend_attrs(&stmt.attrs(), Some(&LazyTokenStream::new(tokens))) - } - Nonterminal::NtStmt(ref stmt) => prepend_attrs(&stmt.attrs(), stmt.tokens()), - Nonterminal::NtPat(ref pat) => convert_tokens(pat.tokens.as_ref()), - Nonterminal::NtTy(ref ty) => convert_tokens(ty.tokens.as_ref()), - Nonterminal::NtIdent(ident, is_raw) => { - Some(tokenstream::TokenTree::token(token::Ident(ident.name, is_raw), ident.span).into()) - } - Nonterminal::NtLifetime(ident) => { - Some(tokenstream::TokenTree::token(token::Lifetime(ident.name), ident.span).into()) - } - Nonterminal::NtMeta(ref attr) => convert_tokens(attr.tokens.as_ref()), - Nonterminal::NtPath(ref path) => convert_tokens(path.tokens.as_ref()), - Nonterminal::NtVis(ref vis) => convert_tokens(vis.tokens.as_ref()), - Nonterminal::NtExpr(ref expr) | Nonterminal::NtLiteral(ref expr) => { - prepend_attrs(&expr.attrs, expr.tokens.as_ref()) - } - }; - - if let Some(tokens) = tokens { - return tokens; - } else if matches!(synthesize_tokens, CanSynthesizeMissingTokens::Yes) { - return nt_fake_token_stream(sess, nt); - } else { - panic!( - "Missing tokens for nt {:?} at {:?}: {:?}", - nt, - nt.span(), - pprust::nonterminal_to_string(nt) - ); - } -} - -fn prepend_attrs(attrs: &[Attribute], tokens: Option<&LazyTokenStream>) -> Option { - let tokens = tokens?; - if attrs.is_empty() { - return Some(tokens.create_token_stream().to_tokenstream()); - } - let attr_data = AttributesData { attrs: attrs.to_vec().into(), tokens: tokens.clone() }; - let wrapped = AttrAnnotatedTokenStream::new(vec![( - AttrAnnotatedTokenTree::Attributes(attr_data), - Spacing::Alone, - )]); - Some(wrapped.to_tokenstream()) -} - -pub fn fake_token_stream(sess: &ParseSess, node: &(impl AstPrettyPrint + HasSpan)) -> TokenStream { - let source = node.pretty_print(); - let filename = FileName::macro_expansion_source_code(&source); - parse_stream_from_source_str(filename, source, sess, Some(node.span())) -} - -fn nt_fake_token_stream(sess: &ParseSess, nt: &Nonterminal) -> TokenStream { - let source = pprust::nonterminal_to_string(nt); +pub fn fake_token_stream_for_item(sess: &ParseSess, item: &ast::Item) -> TokenStream { + let source = pprust::item_to_string(item); let filename = FileName::macro_expansion_source_code(&source); - parse_stream_from_source_str(filename, source, sess, Some(nt.span())) + parse_stream_from_source_str(filename, source, sess, Some(item.span)) } pub fn fake_token_stream_for_crate(sess: &ParseSess, krate: &ast::Crate) -> TokenStream { diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs index 2f90a7c54aba6..3ae8bb07cd070 100644 --- a/compiler/rustc_parse/src/parser/attr.rs +++ b/compiler/rustc_parse/src/parser/attr.rs @@ -284,7 +284,7 @@ impl<'a> Parser<'a> { /// terminated by a semicolon. /// /// Matches `inner_attrs*`. - crate fn parse_inner_attributes(&mut self) -> PResult<'a, Vec> { + pub(crate) fn parse_inner_attributes(&mut self) -> PResult<'a, Vec> { let mut attrs: Vec = vec![]; loop { let start_pos: u32 = self.token_cursor.num_next_calls.try_into().unwrap(); @@ -322,7 +322,7 @@ impl<'a> Parser<'a> { Ok(attrs) } - crate fn parse_unsuffixed_lit(&mut self) -> PResult<'a, ast::Lit> { + pub(crate) fn parse_unsuffixed_lit(&mut self) -> PResult<'a, ast::Lit> { let lit = self.parse_lit()?; debug!("checking if {:?} is unusuffixed", lit); @@ -358,7 +358,7 @@ impl<'a> Parser<'a> { } /// Matches `COMMASEP(meta_item_inner)`. - crate fn parse_meta_seq_top(&mut self) -> PResult<'a, Vec> { + pub(crate) fn parse_meta_seq_top(&mut self) -> PResult<'a, Vec> { // Presumably, the majority of the time there will only be one attr. let mut nmis = Vec::with_capacity(1); while self.token.kind != token::Eof { @@ -401,7 +401,7 @@ impl<'a> Parser<'a> { Ok(ast::MetaItem { path, kind, span }) } - crate fn parse_meta_item_kind(&mut self) -> PResult<'a, ast::MetaItemKind> { + pub(crate) fn parse_meta_item_kind(&mut self) -> PResult<'a, ast::MetaItemKind> { Ok(if self.eat(&token::Eq) { ast::MetaItemKind::NameValue(self.parse_unsuffixed_lit()?) } else if self.check(&token::OpenDelim(Delimiter::Parenthesis)) { diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 369650edd57d0..ee8e41620019a 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -1,8 +1,7 @@ use super::pat::Expected; -use super::ty::{AllowPlus, RecoverQuestionMark}; use super::{ - BlockMode, CommaRecoveryMode, Parser, PathStyle, RecoverColon, RecoverComma, Restrictions, - SemiColonMode, SeqSep, TokenExpectType, TokenType, + BlockMode, CommaRecoveryMode, Parser, PathStyle, Restrictions, SemiColonMode, SeqSep, + TokenExpectType, TokenType, }; use crate::lexer::UnmatchedBrace; @@ -17,11 +16,11 @@ use rustc_ast::{ }; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashSet; -use rustc_errors::{pluralize, struct_span_err, Diagnostic, EmissionGuarantee, ErrorGuaranteed}; use rustc_errors::{ - Applicability, DiagnosticBuilder, DiagnosticMessage, Handler, MultiSpan, PResult, + fluent, Applicability, DiagnosticBuilder, DiagnosticMessage, Handler, MultiSpan, PResult, }; -use rustc_macros::SessionDiagnostic; +use rustc_errors::{pluralize, struct_span_err, Diagnostic, EmissionGuarantee, ErrorGuaranteed}; +use rustc_macros::{SessionDiagnostic, SessionSubdiagnostic}; use rustc_span::source_map::Spanned; use rustc_span::symbol::{kw, Ident}; use rustc_span::{Span, SpanSnippetError, DUMMY_SP}; @@ -132,7 +131,7 @@ impl RecoverQPath for Expr { } /// Control whether the closing delimiter should be consumed when calling `Parser::consume_block`. -crate enum ConsumeClosingDelim { +pub(crate) enum ConsumeClosingDelim { Yes, No, } @@ -252,6 +251,40 @@ struct AmbiguousPlus { pub span: Span, } +#[derive(SessionDiagnostic)] +#[error(code = "E0178", slug = "parser-maybe-recover-from-bad-type-plus")] +struct BadTypePlus { + pub ty: String, + #[primary_span] + pub span: Span, + #[subdiagnostic] + pub sub: BadTypePlusSub, +} + +#[derive(SessionSubdiagnostic)] +pub enum BadTypePlusSub { + #[suggestion( + slug = "parser-add-paren", + code = "{sum_with_parens}", + applicability = "machine-applicable" + )] + AddParen { + sum_with_parens: String, + #[primary_span] + span: Span, + }, + #[label(slug = "parser-forgot-paren")] + ForgotParen { + #[primary_span] + span: Span, + }, + #[label(slug = "parser-expect-path")] + ExpectPath { + #[primary_span] + span: Span, + }, +} + // SnapshotParser is used to create a snapshot of the parser // without causing duplicate errors being emitted when the `Parser` // is dropped. @@ -624,13 +657,10 @@ impl<'a> Parser<'a> { err.delay_as_bug(); self.struct_span_err( expr.span, - DiagnosticMessage::fluent("parser-struct-literal-body-without-path"), + fluent::parser::struct_literal_body_without_path, ) .multipart_suggestion( - DiagnosticMessage::fluent_attr( - "parser-struct-literal-body-without-path", - "suggestion", - ), + fluent::parser::suggestion, vec![ (expr.span.shrink_to_lo(), "{ SomeStruct ".to_string()), (expr.span.shrink_to_hi(), " }".to_string()), @@ -1202,26 +1232,14 @@ impl<'a> Parser<'a> { } } - pub(super) fn maybe_report_ambiguous_plus( - &mut self, - allow_plus: AllowPlus, - impl_dyn_multi: bool, - ty: &Ty, - ) { - if matches!(allow_plus, AllowPlus::No) && impl_dyn_multi { + pub(super) fn maybe_report_ambiguous_plus(&mut self, impl_dyn_multi: bool, ty: &Ty) { + if impl_dyn_multi { self.sess.emit_err(AmbiguousPlus { sum_ty: pprust::ty_to_string(&ty), span: ty.span }); } } /// Swift lets users write `Ty?` to mean `Option`. Parse the construct and recover from it. - pub(super) fn maybe_recover_from_question_mark( - &mut self, - ty: P, - recover_question_mark: RecoverQuestionMark, - ) -> P { - if let RecoverQuestionMark::No = recover_question_mark { - return ty; - } + pub(super) fn maybe_recover_from_question_mark(&mut self, ty: P) -> P { if self.token == token::Question { self.bump(); self.struct_span_err(self.prev_token.span, "invalid `?` in type") @@ -1241,13 +1259,9 @@ impl<'a> Parser<'a> { } } - pub(super) fn maybe_recover_from_bad_type_plus( - &mut self, - allow_plus: AllowPlus, - ty: &Ty, - ) -> PResult<'a, ()> { + pub(super) fn maybe_recover_from_bad_type_plus(&mut self, ty: &Ty) -> PResult<'a, ()> { // Do not add `+` to expected tokens. - if matches!(allow_plus, AllowPlus::No) || !self.token.is_like_plus() { + if !self.token.is_like_plus() { return Ok(()); } @@ -1255,15 +1269,7 @@ impl<'a> Parser<'a> { let bounds = self.parse_generic_bounds(None)?; let sum_span = ty.span.to(self.prev_token.span); - let mut err = struct_span_err!( - self.sess.span_diagnostic, - sum_span, - E0178, - "expected a path on the left-hand side of `+`, not `{}`", - pprust::ty_to_string(ty) - ); - - match ty.kind { + let sub = match ty.kind { TyKind::Rptr(ref lifetime, ref mut_ty) => { let sum_with_parens = pprust::to_string(|s| { s.s.word("&"); @@ -1274,21 +1280,15 @@ impl<'a> Parser<'a> { s.print_type_bounds(" +", &bounds); s.pclose() }); - err.span_suggestion( - sum_span, - "try adding parentheses", - sum_with_parens, - Applicability::MachineApplicable, - ); - } - TyKind::Ptr(..) | TyKind::BareFn(..) => { - err.span_label(sum_span, "perhaps you forgot parentheses?"); - } - _ => { - err.span_label(sum_span, "expected a path"); + + BadTypePlusSub::AddParen { sum_with_parens, span: sum_span } } - } - err.emit(); + TyKind::Ptr(..) | TyKind::BareFn(..) => BadTypePlusSub::ForgotParen { span: sum_span }, + _ => BadTypePlusSub::ExpectPath { span: sum_span }, + }; + + self.sess.emit_err(BadTypePlus { ty: pprust::ty_to_string(ty), span: sum_span, sub }); + Ok(()) } @@ -1427,10 +1427,9 @@ impl<'a> Parser<'a> { pub(super) fn maybe_recover_from_bad_qpath( &mut self, base: P, - allow_recovery: bool, ) -> PResult<'a, P> { // Do not add `::` to expected tokens. - if allow_recovery && self.token == token::ModSep { + if self.token == token::ModSep { if let Some(ty) = base.to_ty() { return self.maybe_recover_from_bad_qpath_stage_2(ty.span, ty); } @@ -1576,7 +1575,7 @@ impl<'a> Parser<'a> { _ => ExprKind::Await(expr), }; let expr = self.mk_expr(lo.to(sp), kind, attrs); - self.maybe_recover_from_bad_qpath(expr, true) + self.maybe_recover_from_bad_qpath(expr) } fn recover_await_macro(&mut self) -> PResult<'a, (Span, P, bool)> { @@ -2437,13 +2436,12 @@ impl<'a> Parser<'a> { /// Some special error handling for the "top-level" patterns in a match arm, /// `for` loop, `let`, &c. (in contrast to subpatterns within such). - crate fn maybe_recover_colon_colon_in_pat_typo( + pub(crate) fn maybe_recover_colon_colon_in_pat_typo( &mut self, mut first_pat: P, - ra: RecoverColon, expected: Expected, ) -> P { - if RecoverColon::Yes != ra || token::Colon != self.token.kind { + if token::Colon != self.token.kind { return first_pat; } if !matches!(first_pat.kind, PatKind::Ident(_, _, None) | PatKind::Path(..)) @@ -2553,7 +2551,7 @@ impl<'a> Parser<'a> { first_pat } - crate fn maybe_recover_unexpected_block_label(&mut self) -> bool { + pub(crate) fn maybe_recover_unexpected_block_label(&mut self) -> bool { let Some(label) = self.eat_label().filter(|_| { self.eat(&token::Colon) && self.token.kind == token::OpenDelim(Delimiter::Brace) }) else { @@ -2574,13 +2572,12 @@ impl<'a> Parser<'a> { /// Some special error handling for the "top-level" patterns in a match arm, /// `for` loop, `let`, &c. (in contrast to subpatterns within such). - crate fn maybe_recover_unexpected_comma( + pub(crate) fn maybe_recover_unexpected_comma( &mut self, lo: Span, - rc: RecoverComma, rt: CommaRecoveryMode, ) -> PResult<'a, ()> { - if rc == RecoverComma::No || self.token != token::Comma { + if self.token != token::Comma { return Ok(()); } @@ -2621,7 +2618,7 @@ impl<'a> Parser<'a> { Err(err) } - crate fn maybe_recover_bounds_doubled_colon(&mut self, ty: &Ty) -> PResult<'a, ()> { + pub(crate) fn maybe_recover_bounds_doubled_colon(&mut self, ty: &Ty) -> PResult<'a, ()> { let TyKind::Path(qself, path) = &ty.kind else { return Ok(()) }; let qself_position = qself.as_ref().map(|qself| qself.position); for (i, segments) in path.segments.windows(2).enumerate() { diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 6114e7aaa7bd7..63c7decbb2fe6 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1417,7 +1417,7 @@ impl<'a> Parser<'a> { match self.parse_opt_lit() { Some(literal) => { let expr = self.mk_expr(lo.to(self.prev_token.span), ExprKind::Lit(literal), attrs); - self.maybe_recover_from_bad_qpath(expr, true) + self.maybe_recover_from_bad_qpath(expr) } None => self.try_macro_suggestion(), } @@ -1444,7 +1444,7 @@ impl<'a> Parser<'a> { ExprKind::Tup(es) }; let expr = self.mk_expr(lo.to(self.prev_token.span), kind, attrs); - self.maybe_recover_from_bad_qpath(expr, true) + self.maybe_recover_from_bad_qpath(expr) } fn parse_array_or_repeat_expr( @@ -1481,7 +1481,7 @@ impl<'a> Parser<'a> { } }; let expr = self.mk_expr(lo.to(self.prev_token.span), kind, attrs); - self.maybe_recover_from_bad_qpath(expr, true) + self.maybe_recover_from_bad_qpath(expr) } fn parse_path_start_expr(&mut self, attrs: AttrVec) -> PResult<'a, P> { @@ -1519,7 +1519,7 @@ impl<'a> Parser<'a> { }; let expr = self.mk_expr(lo.to(hi), kind, attrs); - self.maybe_recover_from_bad_qpath(expr, true) + self.maybe_recover_from_bad_qpath(expr) } /// Parse `'label: $expr`. The label is already parsed. @@ -1604,7 +1604,7 @@ impl<'a> Parser<'a> { let lo = self.prev_token.span; let kind = ExprKind::Ret(self.parse_expr_opt()?); let expr = self.mk_expr(lo.to(self.prev_token.span), kind, attrs); - self.maybe_recover_from_bad_qpath(expr, true) + self.maybe_recover_from_bad_qpath(expr) } /// Parse `"do" "yeet" expr?`. @@ -1619,7 +1619,7 @@ impl<'a> Parser<'a> { let span = lo.to(self.prev_token.span); self.sess.gated_spans.gate(sym::yeet_expr, span); let expr = self.mk_expr(span, kind, attrs); - self.maybe_recover_from_bad_qpath(expr, true) + self.maybe_recover_from_bad_qpath(expr) } /// Parse `"break" (('label (:? expr)?) | expr?)` with `"break"` token already eaten. @@ -1679,7 +1679,7 @@ impl<'a> Parser<'a> { None }; let expr = self.mk_expr(lo.to(self.prev_token.span), ExprKind::Break(label, kind), attrs); - self.maybe_recover_from_bad_qpath(expr, true) + self.maybe_recover_from_bad_qpath(expr) } /// Parse `"yield" expr?`. @@ -1689,7 +1689,7 @@ impl<'a> Parser<'a> { let span = lo.to(self.prev_token.span); self.sess.gated_spans.gate(sym::generators, span); let expr = self.mk_expr(span, kind, attrs); - self.maybe_recover_from_bad_qpath(expr, true) + self.maybe_recover_from_bad_qpath(expr) } /// Returns a string literal if the next token is a string literal. @@ -2010,6 +2010,12 @@ impl<'a> Parser<'a> { Ok(self.mk_expr(blk.span, ExprKind::Block(blk, opt_label), attrs)) } + /// Parse a block which takes no attributes and has no label + fn parse_simple_block(&mut self) -> PResult<'a, P> { + let blk = self.parse_block()?; + Ok(self.mk_expr(blk.span, ExprKind::Block(blk, None), AttrVec::new())) + } + /// Recover on an explicitly quantified closure expression, e.g., `for<'a> |x: &'a u8| *x + 1`. fn recover_quantified_closure_expr(&mut self, attrs: AttrVec) -> PResult<'a, P> { let lo = self.token.span; @@ -2157,6 +2163,15 @@ impl<'a> Parser<'a> { let lo = self.prev_token.span; let cond = self.parse_cond_expr()?; + self.parse_if_after_cond(attrs, lo, cond) + } + + fn parse_if_after_cond( + &mut self, + attrs: AttrVec, + lo: Span, + cond: P, + ) -> PResult<'a, P> { let missing_then_block_binop_span = || { match cond.kind { ExprKind::Binary(Spanned { span: binop_span, .. }, _, ref right) @@ -2164,7 +2179,6 @@ impl<'a> Parser<'a> { _ => None } }; - // Verify that the parsed `if` condition makes sense as a condition. If it is a block, then // verify that the last statement is either an implicit return (no `;`) or an explicit // return. This won't catch blocks with an explicit `return`, but that would be caught by @@ -2256,15 +2270,46 @@ impl<'a> Parser<'a> { /// Parses an `else { ... }` expression (`else` token already eaten). fn parse_else_expr(&mut self) -> PResult<'a, P> { - let ctx_span = self.prev_token.span; // `else` + let else_span = self.prev_token.span; // `else` let attrs = self.parse_outer_attributes()?.take_for_recovery(); // For recovery. let expr = if self.eat_keyword(kw::If) { self.parse_if_expr(AttrVec::new())? + } else if self.check(&TokenKind::OpenDelim(Delimiter::Brace)) { + self.parse_simple_block()? } else { - let blk = self.parse_block()?; - self.mk_expr(blk.span, ExprKind::Block(blk, None), AttrVec::new()) + let snapshot = self.create_snapshot_for_diagnostic(); + let first_tok = super::token_descr(&self.token); + let first_tok_span = self.token.span; + match self.parse_expr() { + Ok(cond) + // If it's not a free-standing expression, and is followed by a block, + // then it's very likely the condition to an `else if`. + if self.check(&TokenKind::OpenDelim(Delimiter::Brace)) + && classify::expr_requires_semi_to_be_stmt(&cond) => + { + self.struct_span_err(first_tok_span, format!("expected `{{`, found {first_tok}")) + .span_label(else_span, "expected an `if` or a block after this `else`") + .span_suggestion( + cond.span.shrink_to_lo(), + "add an `if` if this is the condition of a chained `else if` statement", + "if ".to_string(), + Applicability::MaybeIncorrect, + ) + .emit(); + self.parse_if_after_cond(AttrVec::new(), cond.span.shrink_to_lo(), cond)? + } + Err(e) => { + e.cancel(); + self.restore_snapshot(snapshot); + self.parse_simple_block()? + }, + Ok(_) => { + self.restore_snapshot(snapshot); + self.parse_simple_block()? + }, + } }; - self.error_on_if_block_attrs(ctx_span, true, expr.span, &attrs); + self.error_on_if_block_attrs(else_span, true, expr.span, &attrs); Ok(expr) } @@ -2380,7 +2425,7 @@ impl<'a> Parser<'a> { Ok(self.mk_expr(lo.to(self.prev_token.span), ExprKind::Loop(body, opt_label), attrs)) } - crate fn eat_label(&mut self) -> Option