From 645a88374a8b9e9eb9a5d69b404b91d6e9bfb620 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Wed, 27 Jul 2022 20:09:46 +0900 Subject: [PATCH 01/19] Update mentions to `rustc_metadata::rmeta::Lazy` Signed-off-by: Yuki Okushi --- compiler/rustc_metadata/src/rmeta/decoder.rs | 2 +- compiler/rustc_metadata/src/rmeta/mod.rs | 18 +++++++++--------- compiler/rustc_metadata/src/rmeta/table.rs | 4 ++-- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 8fa703a776075..6b0b5ac7da9a1 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -83,7 +83,7 @@ pub(crate) struct CrateMetadata { // --- Some data pre-decoded from the metadata blob, usually for performance --- /// NOTE(eddyb) we pass `'static` to a `'tcx` parameter because this - /// lifetime is only used behind `Lazy`, and therefore acts like a + /// lifetime is only used behind `LazyValue`, `LazyArray`, or `LazyTable`, and therefore acts like a /// universal (`for<'tcx>`), that is paired up with whichever `TyCtxt` /// is being used to decode those values. root: CrateRoot, diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 0f291f9264777..23198a8536933 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -66,13 +66,13 @@ pub const METADATA_HEADER: &[u8] = &[b'r', b'u', b's', b't', 0, 0, 0, METADATA_V /// /// Metadata is effective a tree, encoded in post-order, /// and with the root's position written next to the header. -/// That means every single `Lazy` points to some previous +/// That means every single `LazyValue` points to some previous /// location in the metadata and is part of a larger node. /// -/// The first `Lazy` in a node is encoded as the backwards +/// The first `LazyValue` in a node is encoded as the backwards /// distance from the position where the containing node -/// starts and where the `Lazy` points to, while the rest -/// use the forward distance from the previous `Lazy`. +/// starts and where the `LazyValue` points to, while the rest +/// use the forward distance from the previous `LazyValue`. /// 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. @@ -94,12 +94,12 @@ impl LazyValue { /// A list of lazily-decoded values. /// -/// Unlike `Lazy>`, the length is encoded next to the +/// Unlike `LazyValue>`, the length is encoded next to the /// position, not at the position, which means that the length /// doesn't need to be known before encoding all the elements. /// /// If the length is 0, no position is encoded, but otherwise, -/// the encoding is that of `Lazy`, with the distinction that +/// the encoding is that of `LazyArray`, 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. struct LazyArray { @@ -167,17 +167,17 @@ impl Clone for LazyTable { } } -/// Encoding / decoding state for `Lazy`. +/// Encoding / decoding state for `Lazy`s (`LazyValue`, `LazyArray`, and `LazyTable`). #[derive(Copy, Clone, PartialEq, Eq, Debug)] enum LazyState { /// Outside of a metadata node. NoNode, - /// Inside a metadata node, and before any `Lazy`. + /// Inside a metadata node, and before any `Lazy`s. /// The position is that of the node itself. NodeStart(NonZeroUsize), - /// Inside a metadata node, with a previous `Lazy`. + /// Inside a metadata node, with a previous `Lazy`s. /// The position is where that previous `Lazy` would start. Previous(NonZeroUsize), } diff --git a/compiler/rustc_metadata/src/rmeta/table.rs b/compiler/rustc_metadata/src/rmeta/table.rs index 42759f0a652b3..21841ae2532a7 100644 --- a/compiler/rustc_metadata/src/rmeta/table.rs +++ b/compiler/rustc_metadata/src/rmeta/table.rs @@ -141,7 +141,7 @@ fixed_size_enum! { } } -// We directly encode `DefPathHash` because a `Lazy` would encur a 25% cost. +// We directly encode `DefPathHash` because a `LazyValue` would incur a 25% cost. impl FixedSizeEncoding for Option { type ByteArray = [u8; 16]; @@ -159,7 +159,7 @@ impl FixedSizeEncoding for Option { } } -// We directly encode RawDefId because using a `Lazy` would incur a 50% overhead in the worst case. +// We directly encode RawDefId because using a `LazyValue` would incur a 50% overhead in the worst case. impl FixedSizeEncoding for Option { type ByteArray = [u8; 8]; From e849f9be59d7c21a65af7d5f655b1691f5da3870 Mon Sep 17 00:00:00 2001 From: David Rheinsberg Date: Tue, 26 Jul 2022 14:39:01 +0200 Subject: [PATCH 02/19] doc/rustc: describe the uefi target platforms Add a `platform-support` entry to the rustc-docs for the different `*-unknown-uefi` targets. This describes in detail how this platform works, a few basic examples, and how to compile for the platform. Red Hat is sponsoring my work on this platform, so I am putting myself down as target maintainer. Co-maintainers are more than welcome to join me in the effort. Communication is going on off-list to coordinate the different efforts. Note that the ultimate goal is to move the UEFI targets to Tier-2 so bootloaders can be more easily supported in commercial products. This documentation is the first step towards that goal, but should be a viable documentation even for the current Tier-3 status of the targets. I also want to point out that there is an ongoing GSoC-effort to port the rust standard library to UEFI (by Ayush Singh). While this work is not necessarily required to get to Tier-2, we definitely should coordinate the efforts and update the documentation as soon as any such ports are merged. Note that the targets are already used by multiple commercial and non commercial production systems, including, but not limited to: * Tianocore-EDK2 (Official UEFI SDK by Intel) comes with rust support in its staging repository (not part of any release, yet). (https://github.com/tianocore/edk2-staging/tree) * Intel's research program "Project Mu" uses the rust UEFI targets to show possible future replacements for Tianocore-EDK2. * The Rust OS "Redox" uses the UEFI targets for its bootloader. (https://www.redox-os.org/) * The hugely popular in-depth documentation of OS development in Rust by Philipp Oppermann uses the UEFI targets. (https://os.phil-opp.com/) Signed-off-by: David Rheinsberg --- src/doc/rustc/src/SUMMARY.md | 1 + .../src/platform-support/unknown-uefi.md | 254 ++++++++++++++++++ 2 files changed, 255 insertions(+) create mode 100644 src/doc/rustc/src/platform-support/unknown-uefi.md diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md index f6348b2bddc88..736c30694cddb 100644 --- a/src/doc/rustc/src/SUMMARY.md +++ b/src/doc/rustc/src/SUMMARY.md @@ -28,6 +28,7 @@ - [riscv32imac-unknown-xous-elf](platform-support/riscv32imac-unknown-xous-elf.md) - [*-pc-windows-gnullvm](platform-support/pc-windows-gnullvm.md) - [*-unknown-openbsd](platform-support/openbsd.md) + - [\*-unknown-uefi](platform-support/unknown-uefi.md) - [wasm64-unknown-unknown](platform-support/wasm64-unknown-unknown.md) - [x86_64-unknown-none](platform-support/x86_64-unknown-none.md) - [Targets](targets/index.md) diff --git a/src/doc/rustc/src/platform-support/unknown-uefi.md b/src/doc/rustc/src/platform-support/unknown-uefi.md new file mode 100644 index 0000000000000..8f90d9c7453d0 --- /dev/null +++ b/src/doc/rustc/src/platform-support/unknown-uefi.md @@ -0,0 +1,254 @@ +# `*-unknown-uefi` + +**Tier: 3** + +Unified Extensible Firmware Interface (UEFI) targets for application, driver, +and core UEFI binaries. + +Available targets: + +- `aarch64-unknown-uefi` +- `i686-unknown-uefi` +- `x86_64-unknown-uefi` + +## Target maintainers + +- David Rheinsberg ([@dvdhrm](https://github.com/dvdhrm)) +- Nicholas Bishop ([@nicholasbishop](https://github.com/nicholasbishop)) + +## Requirements + +All UEFI targets can be used as `no-std` environments via cross-compilation. +Support for `std` is missing, but actively worked on. `alloc` is supported if +an allocator is provided by the user. No host tools are supported. + +The UEFI environment resembles the environment for Microsoft Windows, with some +minor differences. Therefore, cross-compiling for UEFI works with the same +tools as cross-compiling for Windows. The target binaries are PE32+ encoded, +the calling convention is different for each architecture, but matches what +Windows uses (if the architecture is supported by Windows). The special +`efiapi` Rust calling-convention chooses the right ABI for the target platform +(`extern "C"` is incorrect on Intel targets at least). The specification has an +elaborate section on the different supported calling-conventions, if more +details are desired. + +MMX, SSE, and other FP-units are disabled by default, to allow for compilation +of core UEFI code that runs before they are set up. This can be overridden for +individual compilations via rustc command-line flags. Not all firmwares +correctly configure those units, though, so careful inspection is required. + +As native to PE32+, binaries are position-dependent, but can be relocated at +runtime if their desired location is unavailable. The code must be statically +linked. Dynamic linking is not supported. Code is shared via UEFI interfaces, +rather than dynamic linking. Additionally, UEFI forbids running code on +anything but the boot CPU/thread, nor is interrupt-usage allowed (apart from +the timer interrupt). Device drivers are required to use polling methods. + +UEFI uses a single address-space to run all code in. Multiple applications can +be loaded simultaneously and are dispatched via cooperative multitasking on a +single stack. + +By default, the UEFI targets use the `link`-flavor of the LLVM linker `lld` to +link binaries into the final PE32+ file suffixed with `*.efi`. The PE subsystem +is set to `EFI_APPLICATION`, but can be modified by passing `/subsystem:<...>` +to the linker. Similarly, the entry-point is to to `efi_main` but can be +changed via `/entry:<...>`. The panic-strategy is set to `abort`, + +The UEFI specification is available online for free: +[UEFI Specification Directory](https://uefi.org/specifications) + +## Building rust for UEFI targets + +Rust can be built for the UEFI targets by enabling them in the `rustc` build +configuration. Note that you can only build the standard libraries. The +compiler and host tools currently cannot be compiled for UEFI targets. A sample +configuration would be: + +```toml +[build] +build-stage = 1 +target = ["x86_64-unknown-uefi"] +``` + +## Building Rust programs + +Rust does not yet ship pre-compiled artifacts for this target. To compile for +this target, you will either need to build Rust with the target enabled (see +"Building rust for UEFI targets" above), or build your own copy of `core` by +using `build-std`, `cargo-buildx`, or similar. + +A native build with the unstable `build-std`-feature can be achieved via: + +```sh +cargo +nightly build \ + -Zbuild-std=core,compiler_builtins \ + -Zbuild-std-features=compiler-builtins-mem \ + --target x86_64-unknown-uefi +``` + +Alternatively, you can install `cargo-xbuild` via +`cargo install --force cargo-xbuild` and build for the UEFI targets via: + +```sh +cargo \ + +nightly \ + xbuild \ + --target x86_64-unknown-uefi +``` + +## Testing + +UEFI applications can be copied into the ESP on any UEFI system and executed +via the firmware boot menu. The qemu suite allows emulating UEFI systems and +executing UEFI applications as well. See its documentation for details. + +The [uefi-run](https://github.com/Richard-W/uefi-run) rust tool is a simple +wrapper around `qemu` that can spawn UEFI applications in qemu. You can install +it via `cargo install uefi-run` and execute qemu applications as +`uefi-run ./application.efi`. + +## Cross-compilation toolchains and C code + +There are 3 common ways to compile native C code for UEFI targets: + +- Use the official SDK by Intel: + [Tianocore/EDK2](https://github.com/tianocore/edk2). This supports a + multitude of platforms, comes with the full specification transposed into C, + lots of examples and build-system integrations. This is also the only + officially supported platform by Intel, and is used by many major firmware + implementations. Any code compiled via the SDK is compatible to rust binaries + compiled for the UEFI targets. You can link them directly into your rust + binaries, or call into each other via UEFI protocols. +- Use the **GNU-EFI** suite. This approach is used by many UEFI applications + in the Linux/OSS ecosystem. The GCC compiler is used to compile ELF binaries, + and linked with a pre-loader that converts the ELF binary to PE32+ + **at runtime**. You can combine such binaries with the rust UEFI targets only + via UEFI protocols. Linking both into the same executable will fail, since + one is an ELF executable, and one a PE32+. If linking to **GNU-EFI** + executables is desired, you must compile your rust code natively for the same + GNU target as **GNU-EFI** and use their pre-loader. This requires careful + consideration about which calling-convention to use when calling into native + UEFI protocols, or calling into linked **GNU-EFI** code (similar to how these + differences need to be accounted for when writing **GNU-EFI** C code). +- Use native Windows targets. This means compiling your C code for the Windows + platform as if it was the UEFI platform. This works for static libraries, but + needs adjustments when linking into an UEFI executable. You can, however, + link such static libraries seemlessly into rust code compiled for UEFI + targets. Be wary of any includes that are not specifically suitable for UEFI + targets (especially the C standard library includes are not always + compatible). Freestanding compilations are recommended to avoid + incompatibilites. + +## Ecosystem + +The rust language has a long history of supporting UEFI targets. Many crates +have been developed to provide access to UEFI protocols and make UEFI +programming more ergonomic in rust. The following list is a short overview (in +alphabetical ordering): + +- **efi**: *Ergonomic Rust bindings for writing UEFI applications*. Provides + _rustified_ access to UEFI protocols, implements allocators and a safe + environment to write UEFI applications. +- **r-efi**: *UEFI Reference Specification Protocol Constants and Definitions*. + A pure transpose of the UEFI specification into rust. This provides the raw + definitions from the specification, without any extended helpers or + _rustification_. It serves as baseline to implement any more elaborate rust + UEFI layers. +- **uefi-rs**: *Safe and easy-to-use wrapper for building UEFI apps*. An + elaborate library providing safe abstractions for UEFI protocols and + features. It implements allocators and provides an execution environment to + UEFI applications written in rust. +- **uefi-run**: *Run UEFI applications*. A small wrapper around _qemu_ to spawn + UEFI applications in an emulated `x86_64` machine. + +## Example: Freestanding + +The following code is a valid UEFI application returning immediately upon +execution with an exit code of 0. A panic handler is provided. This is executed +by rust on panic. For simplicity, we simply end up in an infinite loop. + +Note that as of rust-1.31.0, all features used here are stabilized. No unstable +features are required, nor do we rely on nightly compilers. However, if you do +not compile rustc for the UEFI targets, you need a nightly compiler to support +the `-Z build-std` flag. + +This example can be compiled as binary crate via `cargo`: + +```sh +cargo +nightly build \ + -Zbuild-std=core,compiler_builtins \ + -Zbuild-std-features=compiler-builtins-mem \ + --target x86_64-unknown-uefi +``` + +```rust,ignore (platform-specific,eh-personality-is-unstable) +#![no_main] +#![no_std] + +#[panic_handler] +fn panic_handler(_info: &core::panic::PanicInfo) -> ! { + loop {} +} + +#[export_name = "efi_main"] +pub extern "C" fn main(_h: *mut core::ffi::c_void, _st: *mut core::ffi::c_void) -> usize { + 0 +} +``` + +## Example: Hello World + +This is an example UEFI application that prints "Hello World!", then waits for +key input before it exits. It serves as base example how to write UEFI +applications without any helper modules other than the standalone UEFI protocol +definitions provided by the `r-efi` crate. + +This extends the "Freestanding" example and builds upon its setup. See there +for instruction how to compile this as binary crate. + +Note that UEFI uses UTF-16 strings. Since rust literals are UTF-8, we have to +use an open-coded, zero-terminated, UTF-16 array as argument to +`output_string()`. Similarly to the panic handler, real applications should +rather use UTF-16 modules. + +```rust,ignore (platform-specific,eh-personality-is-unstable) +#![no_main] +#![no_std] + +use r_efi::efi; + +#[panic_handler] +fn panic_handler(_info: &core::panic::PanicInfo) -> ! { + loop {} +} + +#[export_name = "efi_main"] +pub extern "C" fn main(_h: efi::Handle, st: *mut efi::SystemTable) -> efi::Status { + let s = [ + 0x0048u16, 0x0065u16, 0x006cu16, 0x006cu16, 0x006fu16, // "Hello" + 0x0020u16, // " " + 0x0057u16, 0x006fu16, 0x0072u16, 0x006cu16, 0x0064u16, // "World" + 0x0021u16, // "!" + 0x000au16, // "\n" + 0x0000u16, // NUL + ]; + + // Print "Hello World!". + let r = + unsafe { ((*(*st).con_out).output_string)((*st).con_out, s.as_ptr() as *mut efi::Char16) }; + if r.is_error() { + return r; + } + + // Wait for key input, by waiting on the `wait_for_key` event hook. + let r = unsafe { + let mut x: usize = 0; + ((*(*st).boot_services).wait_for_event)(1, &mut (*(*st).con_in).wait_for_key, &mut x) + }; + if r.is_error() { + return r; + } + + efi::Status::SUCCESS +} +``` From 9d118c5dcae473dab98fc150f581fa8d31e06811 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 27 Jul 2022 14:24:47 +0200 Subject: [PATCH 03/19] Fix settings display on small screen size --- src/librustdoc/html/static/css/settings.css | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/librustdoc/html/static/css/settings.css b/src/librustdoc/html/static/css/settings.css index e531e6ce6bbde..e82ec04263718 100644 --- a/src/librustdoc/html/static/css/settings.css +++ b/src/librustdoc/html/static/css/settings.css @@ -41,9 +41,7 @@ .toggle { position: relative; - display: inline-block; width: 100%; - height: 27px; margin-right: 20px; display: flex; align-items: center; @@ -58,6 +56,7 @@ .slider { position: relative; width: 45px; + min-width: 45px; display: block; height: 28px; margin-right: 20px; From 1564305a9f5448750fe3998f9c5272d0e36092e9 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 27 Jul 2022 14:45:07 +0200 Subject: [PATCH 04/19] Add GUI test for settings in small device --- src/test/rustdoc-gui/settings.goml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/test/rustdoc-gui/settings.goml b/src/test/rustdoc-gui/settings.goml index 8a3365d3cc25e..d9cf5ee66140f 100644 --- a/src/test/rustdoc-gui/settings.goml +++ b/src/test/rustdoc-gui/settings.goml @@ -147,3 +147,12 @@ assert-false: "noscript section" javascript: false reload: assert-css: ("noscript section", {"display": "block"}) +javascript: true + +// Check for the display on small screen +show-text: true +reload: +size: (300, 1000) +click: "#settings-menu" +wait-for: "#settings" +assert-css: ("#settings .slider", {"width": "45px"}, ALL) From 0eb28abcc99476e1456874872545bf51bb2ff7a0 Mon Sep 17 00:00:00 2001 From: bstrie <865233+bstrie@users.noreply.github.com> Date: Wed, 27 Jul 2022 10:20:21 -0400 Subject: [PATCH 05/19] Allow using stable os::fd::raw items through unstable os::wasi module This fixes a regression from stable to nightly. Closes #99502. --- library/std/src/os/fd/raw.rs | 4 ++++ library/std/src/os/wasi/io/raw.rs | 15 +++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/library/std/src/os/fd/raw.rs b/library/std/src/os/fd/raw.rs index ff4e25b792ad0..081915ed148b3 100644 --- a/library/std/src/os/fd/raw.rs +++ b/library/std/src/os/fd/raw.rs @@ -14,6 +14,7 @@ use crate::os::wasi::io::OwnedFd; use crate::sys_common::{AsInner, IntoInner}; /// Raw file descriptors. +#[cfg_attr(not(bootstrap), rustc_allowed_through_unstable_modules)] #[stable(feature = "rust1", since = "1.0.0")] pub type RawFd = raw::c_int; @@ -22,6 +23,7 @@ pub type RawFd = raw::c_int; /// This is only available on unix and WASI platforms and must be imported in /// order to call the method. Windows platforms have a corresponding /// `AsRawHandle` and `AsRawSocket` set of traits. +#[cfg_attr(not(bootstrap), rustc_allowed_through_unstable_modules)] #[stable(feature = "rust1", since = "1.0.0")] pub trait AsRawFd { /// Extracts the raw file descriptor. @@ -57,6 +59,7 @@ pub trait AsRawFd { /// A trait to express the ability to construct an object from a raw file /// descriptor. +#[cfg_attr(not(bootstrap), rustc_allowed_through_unstable_modules)] #[stable(feature = "from_raw_os", since = "1.1.0")] pub trait FromRawFd { /// Constructs a new instance of `Self` from the given raw file @@ -100,6 +103,7 @@ pub trait FromRawFd { /// A trait to express the ability to consume an object and acquire ownership of /// its raw file descriptor. +#[cfg_attr(not(bootstrap), rustc_allowed_through_unstable_modules)] #[stable(feature = "into_raw_os", since = "1.4.0")] pub trait IntoRawFd { /// Consumes this object, returning the raw underlying file descriptor. diff --git a/library/std/src/os/wasi/io/raw.rs b/library/std/src/os/wasi/io/raw.rs index 0e0c5824e3404..da3b36adad409 100644 --- a/library/std/src/os/wasi/io/raw.rs +++ b/library/std/src/os/wasi/io/raw.rs @@ -2,4 +2,19 @@ #![unstable(feature = "wasi_ext", issue = "71213")] +// NOTE: despite the fact that this module is unstable, +// stable Rust had the capability to access the stable +// re-exported items from os::fd::raw through this +// unstable module. +// In PR #95956 the stability checker was changed to check +// all path segments of an item rather than just the last, +// which caused the aforementioned stable usage to regress +// (see issue #99502). +// As a result, the items in os::fd::raw were given the +// rustc_allowed_through_unstable_modules attribute. +// No regression tests were added to ensure this property, +// as CI is not configured to test wasm32-wasi. +// If this module is stabilized, +// you may want to remove those attributes +// (assuming no other unstable modules need them). pub use crate::os::fd::raw::*; From bc4a1dea416e1695cf77acd17ea743d4d802bae0 Mon Sep 17 00:00:00 2001 From: Jack Wrenn Date: Sat, 3 Jul 2021 12:18:13 -0400 Subject: [PATCH 06/19] Initial (incomplete) implementation of transmutability trait. This initial implementation handles transmutations between types with specified layouts, except when references are involved. Co-authored-by: Igor null --- Cargo.lock | 15 + compiler/rustc_hir/src/lang_items.rs | 3 + compiler/rustc_middle/src/traits/select.rs | 4 + compiler/rustc_middle/src/ty/mod.rs | 42 +- compiler/rustc_span/src/symbol.rs | 1 + compiler/rustc_target/src/abi/mod.rs | 3 +- compiler/rustc_trait_selection/Cargo.toml | 1 + .../src/traits/select/candidate_assembly.rs | 23 + .../src/traits/select/confirmation.rs | 52 ++ .../src/traits/select/mod.rs | 3 + compiler/rustc_transmute/Cargo.toml | 28 + compiler/rustc_transmute/src/layout/dfa.rs | 184 ++++ compiler/rustc_transmute/src/layout/mod.rs | 71 ++ compiler/rustc_transmute/src/layout/nfa.rs | 179 ++++ compiler/rustc_transmute/src/layout/tree.rs | 479 ++++++++++ .../rustc_transmute/src/layout/tree/tests.rs | 80 ++ compiler/rustc_transmute/src/lib.rs | 114 +++ .../src/maybe_transmutable/mod.rs | 320 +++++++ .../src/maybe_transmutable/query_context.rs | 93 ++ .../src/maybe_transmutable/tests.rs | 115 +++ library/core/src/mem/mod.rs | 4 + library/core/src/mem/transmutability.rs | 39 + .../abstraction/const_generic_fn.rs | 41 + .../arrays/should_have_correct_length.rs | 44 + .../arrays/should_inherit_alignment.rs | 55 ++ .../should_require_well_defined_layout.rs | 61 ++ .../should_require_well_defined_layout.stderr | 93 ++ ...mitive_reprs_should_have_correct_length.rs | 149 +++ ...ve_reprs_should_have_correct_length.stderr | 303 +++++++ .../should_require_well_defined_layout.rs | 117 +++ .../should_require_well_defined_layout.stderr | 93 ++ .../enums/should_order_correctly.rs | 32 + .../enums/should_pad_variants.rs | 40 + .../enums/should_pad_variants.stderr | 18 + .../enums/should_respect_endianness.rs | 33 + .../enums/should_respect_endianness.stderr | 18 + .../unknown_dst.rs | 21 + .../unknown_dst.stderr | 12 + .../unknown_src.rs | 21 + .../unknown_src.stderr | 12 + .../unknown_src_field.rs | 22 + .../unknown_src_field.stderr | 9 + .../ui/transmutability/primitives/bool.rs | 25 + .../ui/transmutability/primitives/bool.stderr | 18 + .../ui/transmutability/primitives/numbers.rs | 128 +++ .../transmutability/primitives/numbers.stderr | 858 ++++++++++++++++++ .../ui/transmutability/primitives/unit.rs | 24 + .../ui/transmutability/primitives/unit.stderr | 18 + src/test/ui/transmutability/references.rs | 20 + src/test/ui/transmutability/references.stderr | 18 + .../structs/repr/should_handle_align.rs | 36 + .../structs/repr/should_handle_packed.rs | 35 + .../should_require_well_defined_layout.rs | 76 ++ .../should_require_well_defined_layout.stderr | 183 ++++ .../structs/should_order_fields_correctly.rs | 31 + src/test/ui/transmutability/unions/boolish.rs | 31 + .../unions/repr/should_handle_align.rs | 40 + .../unions/repr/should_handle_packed.rs | 41 + .../should_require_well_defined_layout.rs | 37 + .../should_require_well_defined_layout.stderr | 33 + .../unions/should_pad_variants.rs | 40 + .../unions/should_pad_variants.stderr | 18 + ...mit_intersecting_if_validity_is_assumed.rs | 39 + .../unions/should_reject_contraction.rs | 36 + .../unions/should_reject_contraction.stderr | 18 + .../unions/should_reject_disjoint.rs | 36 + .../unions/should_reject_disjoint.stderr | 33 + .../unions/should_reject_intersecting.rs | 38 + .../unions/should_reject_intersecting.stderr | 33 + .../should_accept_if_dst_has_private_field.rs | 38 + ...hould_accept_if_dst_has_private_variant.rs | 39 + ...ept_if_dst_has_tricky_unreachable_field.rs | 46 + ...uld_accept_if_dst_has_unreachable_field.rs | 39 + ...accept_if_dst_has_unreachable_field.stderr | 12 + ...should_accept_if_dst_has_unreachable_ty.rs | 40 + ...ld_accept_if_dst_has_unreachable_ty.stderr | 15 + .../should_accept_if_src_has_private_field.rs | 38 + ...hould_accept_if_src_has_private_variant.rs | 39 + ...uld_accept_if_src_has_unreachable_field.rs | 38 + ...accept_if_src_has_unreachable_field.stderr | 12 + ...should_accept_if_src_has_unreachable_ty.rs | 39 + ...ld_accept_if_src_has_unreachable_ty.stderr | 15 + .../should_reject_if_dst_has_private_field.rs | 37 + ...uld_reject_if_dst_has_private_field.stderr | 18 + ...hould_reject_if_dst_has_private_variant.rs | 38 + ...d_reject_if_dst_has_private_variant.stderr | 18 + ...ect_if_dst_has_tricky_unreachable_field.rs | 52 ++ ...uld_reject_if_dst_has_unreachable_field.rs | 39 + ...reject_if_dst_has_unreachable_field.stderr | 18 + ...should_reject_if_dst_has_unreachable_ty.rs | 42 + ...ld_reject_if_dst_has_unreachable_ty.stderr | 31 + 91 files changed, 5691 insertions(+), 2 deletions(-) create mode 100644 compiler/rustc_transmute/Cargo.toml create mode 100644 compiler/rustc_transmute/src/layout/dfa.rs create mode 100644 compiler/rustc_transmute/src/layout/mod.rs create mode 100644 compiler/rustc_transmute/src/layout/nfa.rs create mode 100644 compiler/rustc_transmute/src/layout/tree.rs create mode 100644 compiler/rustc_transmute/src/layout/tree/tests.rs create mode 100644 compiler/rustc_transmute/src/lib.rs create mode 100644 compiler/rustc_transmute/src/maybe_transmutable/mod.rs create mode 100644 compiler/rustc_transmute/src/maybe_transmutable/query_context.rs create mode 100644 compiler/rustc_transmute/src/maybe_transmutable/tests.rs create mode 100644 library/core/src/mem/transmutability.rs create mode 100644 src/test/ui/transmutability/abstraction/const_generic_fn.rs create mode 100644 src/test/ui/transmutability/arrays/should_have_correct_length.rs create mode 100644 src/test/ui/transmutability/arrays/should_inherit_alignment.rs create mode 100644 src/test/ui/transmutability/arrays/should_require_well_defined_layout.rs create mode 100644 src/test/ui/transmutability/arrays/should_require_well_defined_layout.stderr create mode 100644 src/test/ui/transmutability/enums/repr/primitive_reprs_should_have_correct_length.rs create mode 100644 src/test/ui/transmutability/enums/repr/primitive_reprs_should_have_correct_length.stderr create mode 100644 src/test/ui/transmutability/enums/repr/should_require_well_defined_layout.rs create mode 100644 src/test/ui/transmutability/enums/repr/should_require_well_defined_layout.stderr create mode 100644 src/test/ui/transmutability/enums/should_order_correctly.rs create mode 100644 src/test/ui/transmutability/enums/should_pad_variants.rs create mode 100644 src/test/ui/transmutability/enums/should_pad_variants.stderr create mode 100644 src/test/ui/transmutability/enums/should_respect_endianness.rs create mode 100644 src/test/ui/transmutability/enums/should_respect_endianness.stderr create mode 100644 src/test/ui/transmutability/malformed-program-gracefulness/unknown_dst.rs create mode 100644 src/test/ui/transmutability/malformed-program-gracefulness/unknown_dst.stderr create mode 100644 src/test/ui/transmutability/malformed-program-gracefulness/unknown_src.rs create mode 100644 src/test/ui/transmutability/malformed-program-gracefulness/unknown_src.stderr create mode 100644 src/test/ui/transmutability/malformed-program-gracefulness/unknown_src_field.rs create mode 100644 src/test/ui/transmutability/malformed-program-gracefulness/unknown_src_field.stderr create mode 100644 src/test/ui/transmutability/primitives/bool.rs create mode 100644 src/test/ui/transmutability/primitives/bool.stderr create mode 100644 src/test/ui/transmutability/primitives/numbers.rs create mode 100644 src/test/ui/transmutability/primitives/numbers.stderr create mode 100644 src/test/ui/transmutability/primitives/unit.rs create mode 100644 src/test/ui/transmutability/primitives/unit.stderr create mode 100644 src/test/ui/transmutability/references.rs create mode 100644 src/test/ui/transmutability/references.stderr create mode 100644 src/test/ui/transmutability/structs/repr/should_handle_align.rs create mode 100644 src/test/ui/transmutability/structs/repr/should_handle_packed.rs create mode 100644 src/test/ui/transmutability/structs/repr/should_require_well_defined_layout.rs create mode 100644 src/test/ui/transmutability/structs/repr/should_require_well_defined_layout.stderr create mode 100644 src/test/ui/transmutability/structs/should_order_fields_correctly.rs create mode 100644 src/test/ui/transmutability/unions/boolish.rs create mode 100644 src/test/ui/transmutability/unions/repr/should_handle_align.rs create mode 100644 src/test/ui/transmutability/unions/repr/should_handle_packed.rs create mode 100644 src/test/ui/transmutability/unions/repr/should_require_well_defined_layout.rs create mode 100644 src/test/ui/transmutability/unions/repr/should_require_well_defined_layout.stderr create mode 100644 src/test/ui/transmutability/unions/should_pad_variants.rs create mode 100644 src/test/ui/transmutability/unions/should_pad_variants.stderr create mode 100644 src/test/ui/transmutability/unions/should_permit_intersecting_if_validity_is_assumed.rs create mode 100644 src/test/ui/transmutability/unions/should_reject_contraction.rs create mode 100644 src/test/ui/transmutability/unions/should_reject_contraction.stderr create mode 100644 src/test/ui/transmutability/unions/should_reject_disjoint.rs create mode 100644 src/test/ui/transmutability/unions/should_reject_disjoint.stderr create mode 100644 src/test/ui/transmutability/unions/should_reject_intersecting.rs create mode 100644 src/test/ui/transmutability/unions/should_reject_intersecting.stderr create mode 100644 src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_private_field.rs create mode 100644 src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_private_variant.rs create mode 100644 src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_tricky_unreachable_field.rs create mode 100644 src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_unreachable_field.rs create mode 100644 src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_unreachable_field.stderr create mode 100644 src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_unreachable_ty.rs create mode 100644 src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_unreachable_ty.stderr create mode 100644 src/test/ui/transmutability/visibility/should_accept_if_src_has_private_field.rs create mode 100644 src/test/ui/transmutability/visibility/should_accept_if_src_has_private_variant.rs create mode 100644 src/test/ui/transmutability/visibility/should_accept_if_src_has_unreachable_field.rs create mode 100644 src/test/ui/transmutability/visibility/should_accept_if_src_has_unreachable_field.stderr create mode 100644 src/test/ui/transmutability/visibility/should_accept_if_src_has_unreachable_ty.rs create mode 100644 src/test/ui/transmutability/visibility/should_accept_if_src_has_unreachable_ty.stderr create mode 100644 src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_field.rs create mode 100644 src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_field.stderr create mode 100644 src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_variant.rs create mode 100644 src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_variant.stderr create mode 100644 src/test/ui/transmutability/visibility/should_reject_if_dst_has_tricky_unreachable_field.rs create mode 100644 src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_field.rs create mode 100644 src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_field.stderr create mode 100644 src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_ty.rs create mode 100644 src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_ty.stderr diff --git a/Cargo.lock b/Cargo.lock index 2325d0f3bf263..16b67526cffa0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4553,6 +4553,7 @@ dependencies = [ "rustc_session", "rustc_span", "rustc_target", + "rustc_transmute", "smallvec", "tracing", ] @@ -4577,6 +4578,20 @@ dependencies = [ "tracing", ] +[[package]] +name = "rustc_transmute" +version = "0.1.0" +dependencies = [ + "itertools", + "rustc_data_structures", + "rustc_infer", + "rustc_macros", + "rustc_middle", + "rustc_span", + "rustc_target", + "tracing", +] + [[package]] name = "rustc_ty_utils" version = "0.0.0" diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 13b3e954e1f58..c337be12ae492 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -191,6 +191,9 @@ language_item_table! { CoerceUnsized, sym::coerce_unsized, coerce_unsized_trait, Target::Trait, GenericRequirement::Minimum(1); DispatchFromDyn, sym::dispatch_from_dyn, dispatch_from_dyn_trait, Target::Trait, GenericRequirement::Minimum(1); + // language items relating to transmutability + TransmuteTrait, sym::transmute_trait, transmute_trait, Target::Trait, GenericRequirement::Exact(6); + Add(Op), sym::add, add_trait, Target::Trait, GenericRequirement::Exact(1); Sub(Op), sym::sub, sub_trait, Target::Trait, GenericRequirement::Exact(1); Mul(Op), sym::mul, mul_trait, Target::Trait, GenericRequirement::Exact(1); diff --git a/compiler/rustc_middle/src/traits/select.rs b/compiler/rustc_middle/src/traits/select.rs index 0ca5a532b7542..e836ba47eed7a 100644 --- a/compiler/rustc_middle/src/traits/select.rs +++ b/compiler/rustc_middle/src/traits/select.rs @@ -109,6 +109,10 @@ pub enum SelectionCandidate<'tcx> { /// `false` if there are no *further* obligations. has_nested: bool, }, + + /// Implementation of transmutability trait. + TransmutabilityCandidate, + ParamCandidate(ty::PolyTraitPredicate<'tcx>), ImplCandidate(DefId), AutoImplCandidate(DefId), diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 31c523aaca9ae..5fda1e6538e91 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -48,7 +48,7 @@ pub use subst::*; pub use vtable::*; use std::fmt::Debug; -use std::hash::Hash; +use std::hash::{Hash, Hasher}; use std::ops::ControlFlow; use std::{fmt, str}; @@ -1724,6 +1724,26 @@ impl VariantDef { } } +/// There should be only one VariantDef for each `def_id`, therefore +/// it is fine to implement `PartialEq` only based on `def_id`. +impl PartialEq for VariantDef { + #[inline] + fn eq(&self, other: &Self) -> bool { + self.def_id == other.def_id + } +} + +impl Eq for VariantDef {} + +/// There should be only one VariantDef for each `def_id`, therefore +/// it is fine to implement `Hash` only based on `def_id`. +impl Hash for VariantDef { + #[inline] + fn hash(&self, s: &mut H) { + self.def_id.hash(s) + } +} + #[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)] pub enum VariantDiscr { /// Explicit value for this variant, i.e., `X = 123`. @@ -1744,6 +1764,26 @@ pub struct FieldDef { pub vis: Visibility, } +/// There should be only one FieldDef for each `did`, therefore +/// it is fine to implement `PartialEq` only based on `did`. +impl PartialEq for FieldDef { + #[inline] + fn eq(&self, other: &Self) -> bool { + self.did == other.did + } +} + +impl Eq for FieldDef {} + +/// There should be only one FieldDef for each `did`, therefore +/// it is fine to implement `Hash` only based on `did`. +impl Hash for FieldDef { + #[inline] + fn hash(&self, s: &mut H) { + self.did.hash(s) + } +} + bitflags! { #[derive(TyEncodable, TyDecodable, Default, HashStable)] pub struct ReprFlags: u8 { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index c75b6772487f9..632d2c13d74ef 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1462,6 +1462,7 @@ symbols! { trait_alias, trait_upcasting, transmute, + transmute_trait, transparent, transparent_enums, transparent_unions, diff --git a/compiler/rustc_target/src/abi/mod.rs b/compiler/rustc_target/src/abi/mod.rs index b35502d9ee42b..0758bf7c7cb07 100644 --- a/compiler/rustc_target/src/abi/mod.rs +++ b/compiler/rustc_target/src/abi/mod.rs @@ -508,6 +508,7 @@ impl fmt::Debug for Align { impl Align { pub const ONE: Align = Align { pow2: 0 }; + pub const MAX: Align = Align { pow2: 29 }; #[inline] pub fn from_bits(bits: u64) -> Result { @@ -540,7 +541,7 @@ impl Align { if bytes != 1 { return Err(not_power_of_2(align)); } - if pow2 > 29 { + if pow2 > Self::MAX.pow2 { return Err(too_large(align)); } diff --git a/compiler/rustc_trait_selection/Cargo.toml b/compiler/rustc_trait_selection/Cargo.toml index aebeb49e623b9..566f236f26a8c 100644 --- a/compiler/rustc_trait_selection/Cargo.toml +++ b/compiler/rustc_trait_selection/Cargo.toml @@ -23,4 +23,5 @@ rustc_query_system = { path = "../rustc_query_system" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } +rustc_transmute = { path = "../rustc_transmute", features = ["rustc"] } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 6e8581128dd8e..a18b835e70ce1 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -305,6 +305,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.assemble_candidates_for_unsizing(obligation, &mut candidates); } else if lang_items.destruct_trait() == Some(def_id) { self.assemble_const_destruct_candidates(obligation, &mut candidates); + } else if lang_items.transmute_trait() == Some(def_id) { + // User-defined transmutability impls are permitted. + self.assemble_candidates_from_impls(obligation, &mut candidates); + self.assemble_candidates_for_transmutability(obligation, &mut candidates); } else { if lang_items.clone_trait() == Some(def_id) { // Same builtin conditions as `Copy`, i.e., every type which has builtin support @@ -873,6 +877,25 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { }; } + #[tracing::instrument(level = "debug", skip(self, obligation, candidates))] + fn assemble_candidates_for_transmutability( + &mut self, + obligation: &TraitObligation<'tcx>, + candidates: &mut SelectionCandidateSet<'tcx>, + ) { + if obligation.has_param_types_or_consts() { + candidates.ambiguous = false; + return; + } + + if obligation.has_infer_types_or_consts() { + candidates.ambiguous = true; + return; + } + + candidates.vec.push(TransmutabilityCandidate); + } + #[tracing::instrument(level = "debug", skip(self, obligation, candidates))] fn assemble_candidates_for_trait_alias( &mut self, diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index d4c9fd1c5f9cd..a609fb2b17266 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -48,6 +48,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ImplSource::Builtin(data) } + TransmutabilityCandidate => { + let data = self.confirm_transmutability_candidate(obligation)?; + ImplSource::Builtin(data) + } + ParamCandidate(param) => { let obligations = self.confirm_param_candidate(obligation, param.map_bound(|t| t.trait_ref)); @@ -267,6 +272,53 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ImplSourceBuiltinData { nested: obligations } } + fn confirm_transmutability_candidate( + &mut self, + obligation: &TraitObligation<'tcx>, + ) -> Result>, SelectionError<'tcx>> { + debug!(?obligation, "confirm_transmutability_candidate"); + + let predicate = obligation.predicate; + + let type_at = |i| predicate.map_bound(|p| p.trait_ref.substs.type_at(i)); + let bool_at = |i| { + predicate + .skip_binder() + .trait_ref + .substs + .const_at(i) + .try_eval_bool(self.tcx(), obligation.param_env) + .unwrap() + }; + + let src_and_dst = predicate.map_bound(|p| rustc_transmute::Types { + src: p.trait_ref.substs.type_at(1), + dst: p.trait_ref.substs.type_at(0), + }); + + let scope = type_at(2).skip_binder(); + + let assume = rustc_transmute::Assume { + alignment: bool_at(3), + lifetimes: bool_at(4), + validity: bool_at(5), + visibility: bool_at(6), + }; + + let cause = obligation.cause.clone(); + + let mut transmute_env = rustc_transmute::TransmuteTypeEnv::new(self.infcx); + + let maybe_transmutable = transmute_env.is_transmutable(cause, src_and_dst, scope, assume); + + use rustc_transmute::Answer; + + match maybe_transmutable { + Answer::Yes => Ok(ImplSourceBuiltinData { nested: vec![] }), + _ => Err(Unimplemented), + } + } + /// This handles the case where an `auto trait Foo` impl is being used. /// The idea is that the impl applies to `X : Foo` if the following conditions are met: /// diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 17f34012d1dd3..9ca23228b9879 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -1630,6 +1630,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ); } + // FIXME(@jswrenn): this should probably be more sophisticated + (TransmutabilityCandidate, _) | (_, TransmutabilityCandidate) => false, + // (*) ( BuiltinCandidate { has_nested: false } diff --git a/compiler/rustc_transmute/Cargo.toml b/compiler/rustc_transmute/Cargo.toml new file mode 100644 index 0000000000000..9dc96e08a8e27 --- /dev/null +++ b/compiler/rustc_transmute/Cargo.toml @@ -0,0 +1,28 @@ +[package] +name = "rustc_transmute" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +tracing = "0.1" +rustc_data_structures = { path = "../rustc_data_structures", optional = true} +rustc_infer = { path = "../rustc_infer", optional = true} +rustc_macros = { path = "../rustc_macros", optional = true} +rustc_middle = { path = "../rustc_middle", optional = true} +rustc_span = { path = "../rustc_span", optional = true} +rustc_target = { path = "../rustc_target", optional = true} + +[features] +rustc = [ + "rustc_middle", + "rustc_data_structures", + "rustc_infer", + "rustc_macros", + "rustc_span", + "rustc_target", +] + +[dev-dependencies] +itertools = "0.10.1" \ No newline at end of file diff --git a/compiler/rustc_transmute/src/layout/dfa.rs b/compiler/rustc_transmute/src/layout/dfa.rs new file mode 100644 index 0000000000000..cdd3195712d26 --- /dev/null +++ b/compiler/rustc_transmute/src/layout/dfa.rs @@ -0,0 +1,184 @@ +use super::{nfa, Byte, Nfa, Ref}; +use crate::Map; +use std::fmt; +use std::sync::atomic::{AtomicU64, Ordering}; + +#[derive(PartialEq, Clone, Debug)] +pub(crate) struct Dfa +where + R: Ref, +{ + pub(crate) transitions: Map>, + pub(crate) start: State, + pub(crate) accepting: State, +} + +#[derive(PartialEq, Clone, Debug)] +pub(crate) struct Transitions +where + R: Ref, +{ + byte_transitions: Map, + ref_transitions: Map, +} + +impl Default for Transitions +where + R: Ref, +{ + fn default() -> Self { + Self { byte_transitions: Map::default(), ref_transitions: Map::default() } + } +} + +impl Transitions +where + R: Ref, +{ + fn insert(&mut self, transition: Transition, state: State) { + match transition { + Transition::Byte(b) => { + self.byte_transitions.insert(b, state); + } + Transition::Ref(r) => { + self.ref_transitions.insert(r, state); + } + } + } +} + +/// The states in a `Nfa` represent byte offsets. +#[derive(Hash, Eq, PartialEq, PartialOrd, Ord, Copy, Clone)] +pub(crate) struct State(u64); + +#[derive(Hash, Eq, PartialEq, Clone, Copy)] +pub(crate) enum Transition +where + R: Ref, +{ + Byte(Byte), + Ref(R), +} + +impl fmt::Debug for State { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "S_{}", self.0) + } +} + +impl fmt::Debug for Transition +where + R: Ref, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match &self { + Self::Byte(b) => b.fmt(f), + Self::Ref(r) => r.fmt(f), + } + } +} + +impl Dfa +where + R: Ref, +{ + pub(crate) fn unit() -> Self { + let transitions: Map> = Map::default(); + let start = State::new(); + let accepting = start; + + Self { transitions, start, accepting } + } + + #[cfg(test)] + pub(crate) fn bool() -> Self { + let mut transitions: Map> = Map::default(); + let start = State::new(); + let accepting = State::new(); + + transitions.entry(start).or_default().insert(Transition::Byte(Byte::Init(0x00)), accepting); + + transitions.entry(start).or_default().insert(Transition::Byte(Byte::Init(0x01)), accepting); + + Self { transitions, start, accepting } + } + + #[tracing::instrument] + #[cfg_attr(feature = "rustc", allow(rustc::potential_query_instability))] + pub(crate) fn from_nfa(nfa: Nfa) -> Self { + let Nfa { transitions: nfa_transitions, start: nfa_start, accepting: nfa_accepting } = nfa; + + let mut dfa_transitions: Map> = Map::default(); + let mut nfa_to_dfa: Map = Map::default(); + let dfa_start = State::new(); + nfa_to_dfa.insert(nfa_start, dfa_start); + + let mut queue = vec![(nfa_start, dfa_start)]; + + while let Some((nfa_state, dfa_state)) = queue.pop() { + if nfa_state == nfa_accepting { + continue; + } + + for (nfa_transition, next_nfa_states) in nfa_transitions[&nfa_state].iter() { + let dfa_transitions = + dfa_transitions.entry(dfa_state).or_insert_with(Default::default); + + let mapped_state = next_nfa_states.iter().find_map(|x| nfa_to_dfa.get(x).copied()); + + let next_dfa_state = match nfa_transition { + &nfa::Transition::Byte(b) => *dfa_transitions + .byte_transitions + .entry(b) + .or_insert_with(|| mapped_state.unwrap_or_else(State::new)), + &nfa::Transition::Ref(r) => *dfa_transitions + .ref_transitions + .entry(r) + .or_insert_with(|| mapped_state.unwrap_or_else(State::new)), + }; + + for &next_nfa_state in next_nfa_states { + nfa_to_dfa.entry(next_nfa_state).or_insert_with(|| { + queue.push((next_nfa_state, next_dfa_state)); + next_dfa_state + }); + } + } + } + + let dfa_accepting = nfa_to_dfa[&nfa_accepting]; + + Self { transitions: dfa_transitions, start: dfa_start, accepting: dfa_accepting } + } + + pub(crate) fn bytes_from(&self, start: State) -> Option<&Map> { + Some(&self.transitions.get(&start)?.byte_transitions) + } + + pub(crate) fn byte_from(&self, start: State, byte: Byte) -> Option { + self.transitions.get(&start)?.byte_transitions.get(&byte).copied() + } + + pub(crate) fn refs_from(&self, start: State) -> Option<&Map> { + Some(&self.transitions.get(&start)?.ref_transitions) + } +} + +impl State { + pub(crate) fn new() -> Self { + static COUNTER: AtomicU64 = AtomicU64::new(0); + Self(COUNTER.fetch_add(1, Ordering::SeqCst)) + } +} + +impl From> for Transition +where + R: Ref, +{ + fn from(nfa_transition: nfa::Transition) -> Self { + match nfa_transition { + nfa::Transition::Byte(byte) => Transition::Byte(byte), + nfa::Transition::Ref(r) => Transition::Ref(r), + } + } +} diff --git a/compiler/rustc_transmute/src/layout/mod.rs b/compiler/rustc_transmute/src/layout/mod.rs new file mode 100644 index 0000000000000..cbf92bdacd6f0 --- /dev/null +++ b/compiler/rustc_transmute/src/layout/mod.rs @@ -0,0 +1,71 @@ +use std::fmt::{self, Debug}; +use std::hash::Hash; + +pub(crate) mod tree; +pub(crate) use tree::Tree; + +pub(crate) mod nfa; +pub(crate) use nfa::Nfa; + +pub(crate) mod dfa; +pub(crate) use dfa::Dfa; + +#[derive(Debug)] +pub(crate) struct Uninhabited; + +/// An instance of a byte is either initialized to a particular value, or uninitialized. +#[derive(Hash, Eq, PartialEq, Clone, Copy)] +pub(crate) enum Byte { + Uninit, + Init(u8), +} + +impl fmt::Debug for Byte { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match &self { + Self::Uninit => f.write_str("??u8"), + Self::Init(b) => write!(f, "{:#04x}u8", b), + } + } +} + +pub(crate) trait Def: Debug + Hash + Eq + PartialEq + Copy + Clone {} +pub trait Ref: Debug + Hash + Eq + PartialEq + Copy + Clone {} + +impl Def for ! {} +impl Ref for ! {} + +#[cfg(feature = "rustc")] +pub(crate) mod rustc { + use rustc_middle::mir::Mutability; + use rustc_middle::ty; + use rustc_middle::ty::Region; + use rustc_middle::ty::Ty; + + /// A reference in the layout [`Nfa`]. + #[derive(Debug, Hash, Eq, PartialEq, PartialOrd, Ord, Clone, Copy)] + pub struct Ref<'tcx> { + lifetime: Region<'tcx>, + ty: Ty<'tcx>, + mutability: Mutability, + } + + impl<'tcx> super::Ref for Ref<'tcx> {} + + impl<'tcx> Ref<'tcx> { + pub fn min_align(&self) -> usize { + todo!() + } + } + + /// A visibility node in the layout [`Nfa`]. + #[derive(Debug, Hash, Eq, PartialEq, Clone, Copy)] + pub enum Def<'tcx> { + Adt(ty::AdtDef<'tcx>), + Variant(&'tcx ty::VariantDef), + Field(&'tcx ty::FieldDef), + Primitive, + } + + impl<'tcx> super::Def for Def<'tcx> {} +} diff --git a/compiler/rustc_transmute/src/layout/nfa.rs b/compiler/rustc_transmute/src/layout/nfa.rs new file mode 100644 index 0000000000000..817e426ba274e --- /dev/null +++ b/compiler/rustc_transmute/src/layout/nfa.rs @@ -0,0 +1,179 @@ +use super::{Byte, Ref, Tree, Uninhabited}; +use crate::{Map, Set}; +use std::fmt; +use std::sync::atomic::{AtomicU64, Ordering}; + +/// A non-deterministic finite automaton (NFA) that represents the layout of a type. +/// The transmutability of two given types is computed by comparing their `Nfa`s. +#[derive(PartialEq, Debug)] +pub(crate) struct Nfa +where + R: Ref, +{ + pub(crate) transitions: Map, Set>>, + pub(crate) start: State, + pub(crate) accepting: State, +} + +/// The states in a `Nfa` represent byte offsets. +#[derive(Hash, Eq, PartialEq, PartialOrd, Ord, Copy, Clone)] +pub(crate) struct State(u64); + +/// The transitions between states in a `Nfa` reflect bit validity. +#[derive(Hash, Eq, PartialEq, Clone, Copy)] +pub(crate) enum Transition +where + R: Ref, +{ + Byte(Byte), + Ref(R), +} + +impl fmt::Debug for State { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "S_{}", self.0) + } +} + +impl fmt::Debug for Transition +where + R: Ref, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match &self { + Self::Byte(b) => b.fmt(f), + Self::Ref(r) => r.fmt(f), + } + } +} + +impl Nfa +where + R: Ref, +{ + pub(crate) fn unit() -> Self { + let transitions: Map, Set>> = Map::default(); + let start = State::new(); + let accepting = start; + + Nfa { transitions, start, accepting } + } + + pub(crate) fn from_byte(byte: Byte) -> Self { + let mut transitions: Map, Set>> = Map::default(); + let start = State::new(); + let accepting = State::new(); + + let source = transitions.entry(start).or_default(); + let edge = source.entry(Transition::Byte(byte)).or_default(); + edge.insert(accepting); + + Nfa { transitions, start, accepting } + } + + pub(crate) fn from_ref(r: R) -> Self { + let mut transitions: Map, Set>> = Map::default(); + let start = State::new(); + let accepting = State::new(); + + let source = transitions.entry(start).or_default(); + let edge = source.entry(Transition::Ref(r)).or_default(); + edge.insert(accepting); + + Nfa { transitions, start, accepting } + } + + pub(crate) fn from_tree(tree: Tree) -> Result { + Ok(match tree { + Tree::Byte(b) => Self::from_byte(b), + Tree::Def(..) => unreachable!(), + Tree::Ref(r) => Self::from_ref(r), + Tree::Alt(alts) => { + let mut alts = alts.into_iter().map(Self::from_tree); + let mut nfa = alts.next().ok_or(Uninhabited)??; + for alt in alts { + nfa = nfa.union(&alt?); + } + nfa + } + Tree::Seq(elts) => { + let mut nfa = Self::unit(); + for elt in elts.into_iter().map(Self::from_tree) { + nfa = nfa.concat(elt?); + } + nfa + } + }) + } + + /// Concatenate two `Nfa`s. + pub(crate) fn concat(self, other: Self) -> Self { + if self.start == self.accepting { + return other; + } else if other.start == other.accepting { + return self; + } + + let start = self.start; + let accepting = other.accepting; + + let mut transitions: Map, Set>> = self.transitions; + + // the iteration order doesn't matter + #[cfg_attr(feature = "rustc", allow(rustc::potential_query_instability))] + for (source, transition) in other.transitions { + let fix_state = |state| if state == other.start { self.accepting } else { state }; + let entry = transitions.entry(fix_state(source)).or_default(); + for (edge, destinations) in transition { + let entry = entry.entry(edge.clone()).or_default(); + for destination in destinations { + entry.insert(fix_state(destination)); + } + } + } + + Self { transitions, start, accepting } + } + + /// Compute the union of two `Nfa`s. + pub(crate) fn union(&self, other: &Self) -> Self { + let start = self.start; + let accepting = self.accepting; + + let mut transitions: Map, Set>> = self.transitions.clone(); + + // the iteration order doesn't matter + #[cfg_attr(feature = "rustc", allow(rustc::potential_query_instability))] + for (&(mut source), transition) in other.transitions.iter() { + // if source is starting state of `other`, replace with starting state of `self` + if source == other.start { + source = self.start; + } + let entry = transitions.entry(source).or_default(); + for (edge, destinations) in transition { + let entry = entry.entry(edge.clone()).or_default(); + // the iteration order doesn't matter + #[cfg_attr(feature = "rustc", allow(rustc::potential_query_instability))] + for &(mut destination) in destinations { + // if dest is accepting state of `other`, replace with accepting state of `self` + if destination == other.accepting { + destination = self.accepting; + } + entry.insert(destination); + } + } + } + Self { transitions, start, accepting } + } + + pub(crate) fn edges_from(&self, start: State) -> Option<&Map, Set>> { + self.transitions.get(&start) + } +} + +impl State { + pub(crate) fn new() -> Self { + static COUNTER: AtomicU64 = AtomicU64::new(0); + Self(COUNTER.fetch_add(1, Ordering::SeqCst)) + } +} diff --git a/compiler/rustc_transmute/src/layout/tree.rs b/compiler/rustc_transmute/src/layout/tree.rs new file mode 100644 index 0000000000000..67b401855d4be --- /dev/null +++ b/compiler/rustc_transmute/src/layout/tree.rs @@ -0,0 +1,479 @@ +use super::{Byte, Def, Ref}; + +#[cfg(test)] +mod tests; + +/// A tree-based representation of a type layout. +/// +/// Invariants: +/// 1. All paths through the layout have the same length (in bytes). +/// +/// Nice-to-haves: +/// 1. An `Alt` is never directly nested beneath another `Alt`. +/// 2. A `Seq` is never directly nested beneath another `Seq`. +/// 3. `Seq`s and `Alt`s with a single member do not exist. +#[derive(Clone, Debug, Hash, PartialEq, Eq)] +pub(crate) enum Tree +where + D: Def, + R: Ref, +{ + /// A sequence of successive layouts. + Seq(Vec), + /// A choice between alternative layouts. + Alt(Vec), + /// A definition node. + Def(D), + /// A reference node. + Ref(R), + /// A byte node. + Byte(Byte), +} + +impl Tree +where + D: Def, + R: Ref, +{ + /// A `Tree` consisting only of a definition node. + pub(crate) fn def(def: D) -> Self { + Self::Def(def) + } + + /// A `Tree` representing an uninhabited type. + pub(crate) fn uninhabited() -> Self { + Self::Alt(vec![]) + } + + /// A `Tree` representing a zero-sized type. + pub(crate) fn unit() -> Self { + Self::Seq(Vec::new()) + } + + /// A `Tree` containing a single, uninitialized byte. + pub(crate) fn uninit() -> Self { + Self::Byte(Byte::Uninit) + } + + /// A `Tree` representing the layout of `bool`. + pub(crate) fn bool() -> Self { + Self::from_bits(0x00).or(Self::from_bits(0x01)) + } + + /// A `Tree` whose layout matches that of a `u8`. + pub(crate) fn u8() -> Self { + Self::Alt((0u8..=255).map(Self::from_bits).collect()) + } + + /// A `Tree` whose layout accepts exactly the given bit pattern. + pub(crate) fn from_bits(bits: u8) -> Self { + Self::Byte(Byte::Init(bits)) + } + + /// A `Tree` whose layout is a number of the given width. + pub(crate) fn number(width_in_bytes: usize) -> Self { + Self::Seq(vec![Self::u8(); width_in_bytes]) + } + + /// A `Tree` whose layout is entirely padding of the given width. + #[tracing::instrument] + pub(crate) fn padding(width_in_bytes: usize) -> Self { + Self::Seq(vec![Self::uninit(); width_in_bytes]) + } + + /// Remove all `Def` nodes, and all branches of the layout for which `f` produces false. + pub(crate) fn prune(self, f: &F) -> Tree + where + F: Fn(D) -> bool, + { + match self { + Self::Seq(elts) => elts + .into_iter() + .map(|elt| elt.prune(f)) + .try_fold(Tree::unit(), |elts, elt| { + if elt == Tree::uninhabited() { + Err(Tree::uninhabited()) + } else { + Ok(elts.then(elt)) + } + }) + .into_ok_or_err(), + Self::Alt(alts) => alts + .into_iter() + .map(|alt| alt.prune(f)) + .fold(Tree::uninhabited(), |alts, alt| alts.or(alt)), + Self::Byte(b) => Tree::Byte(b), + Self::Ref(r) => Tree::Ref(r), + Self::Def(d) => { + if !f(d) { + Tree::uninhabited() + } else { + Tree::unit() + } + } + } + } + + /// Produces `true` if `Tree` is an inhabited type; otherwise false. + pub(crate) fn is_inhabited(&self) -> bool { + match self { + Self::Seq(elts) => elts.into_iter().all(|elt| elt.is_inhabited()), + Self::Alt(alts) => alts.into_iter().any(|alt| alt.is_inhabited()), + Self::Byte(..) | Self::Ref(..) | Self::Def(..) => true, + } + } +} + +impl Tree +where + D: Def, + R: Ref, +{ + /// Produces a new `Tree` where `other` is sequenced after `self`. + pub(crate) fn then(self, other: Self) -> Self { + match (self, other) { + (Self::Seq(elts), other) | (other, Self::Seq(elts)) if elts.len() == 0 => other, + (Self::Seq(mut lhs), Self::Seq(mut rhs)) => { + lhs.append(&mut rhs); + Self::Seq(lhs) + } + (Self::Seq(mut lhs), rhs) => { + lhs.push(rhs); + Self::Seq(lhs) + } + (lhs, Self::Seq(mut rhs)) => { + rhs.insert(0, lhs); + Self::Seq(rhs) + } + (lhs, rhs) => Self::Seq(vec![lhs, rhs]), + } + } + + /// Produces a new `Tree` accepting either `self` or `other` as alternative layouts. + pub(crate) fn or(self, other: Self) -> Self { + match (self, other) { + (Self::Alt(alts), other) | (other, Self::Alt(alts)) if alts.len() == 0 => other, + (Self::Alt(mut lhs), Self::Alt(rhs)) => { + lhs.extend(rhs); + Self::Alt(lhs) + } + (Self::Alt(mut alts), alt) | (alt, Self::Alt(mut alts)) => { + alts.push(alt); + Self::Alt(alts) + } + (lhs, rhs) => Self::Alt(vec![lhs, rhs]), + } + } +} + +#[derive(Debug, Copy, Clone)] +pub(crate) enum Err { + /// The layout of the type is unspecified. + Unspecified, + /// This error will be surfaced elsewhere by rustc, so don't surface it. + Unknown, +} + +#[cfg(feature = "rustc")] +pub(crate) mod rustc { + use super::{Err, Tree}; + use crate::layout::rustc::{Def, Ref}; + + use rustc_middle::ty; + use rustc_middle::ty::layout::LayoutError; + use rustc_middle::ty::util::Discr; + use rustc_middle::ty::AdtDef; + use rustc_middle::ty::ParamEnv; + use rustc_middle::ty::SubstsRef; + use rustc_middle::ty::Ty; + use rustc_middle::ty::TyCtxt; + use rustc_middle::ty::VariantDef; + use rustc_target::abi::Align; + use std::alloc; + + impl<'tcx> From> for Err { + fn from(err: LayoutError<'tcx>) -> Self { + match err { + LayoutError::Unknown(..) => Self::Unknown, + err @ _ => unimplemented!("{:?}", err), + } + } + } + + trait LayoutExt { + fn clamp_align(&self, min_align: Align, max_align: Align) -> Self; + } + + impl LayoutExt for alloc::Layout { + fn clamp_align(&self, min_align: Align, max_align: Align) -> Self { + let min_align = min_align.bytes().try_into().unwrap(); + let max_align = max_align.bytes().try_into().unwrap(); + Self::from_size_align(self.size(), self.align().clamp(min_align, max_align)).unwrap() + } + } + + struct LayoutSummary { + total_align: Align, + total_size: usize, + discriminant_size: usize, + discriminant_align: Align, + } + + impl LayoutSummary { + fn from_ty<'tcx>(ty: Ty<'tcx>, ctx: TyCtxt<'tcx>) -> Result> { + use rustc_middle::ty::ParamEnvAnd; + use rustc_target::abi::{TyAndLayout, Variants}; + + let param_env = ParamEnv::reveal_all(); + let param_env_and_type = ParamEnvAnd { param_env, value: ty }; + let TyAndLayout { layout, .. } = ctx.layout_of(param_env_and_type)?; + + let total_size: usize = layout.size().bytes_usize(); + let total_align: Align = layout.align().abi; + let discriminant_align: Align; + let discriminant_size: usize; + + if let Variants::Multiple { tag, .. } = layout.variants() { + discriminant_align = tag.align(&ctx).abi; + discriminant_size = tag.size(&ctx).bytes_usize(); + } else { + discriminant_align = Align::ONE; + discriminant_size = 0; + }; + + Ok(Self { total_align, total_size, discriminant_align, discriminant_size }) + } + + fn into(&self) -> alloc::Layout { + alloc::Layout::from_size_align( + self.total_size, + self.total_align.bytes().try_into().unwrap(), + ) + .unwrap() + } + } + + impl<'tcx> Tree, Ref<'tcx>> { + pub fn from_ty(ty: Ty<'tcx>, tcx: TyCtxt<'tcx>) -> Result { + use rustc_middle::ty::FloatTy::*; + use rustc_middle::ty::IntTy::*; + use rustc_middle::ty::UintTy::*; + use rustc_target::abi::HasDataLayout; + + let target = tcx.data_layout(); + + match ty.kind() { + ty::Bool => Ok(Self::bool()), + + ty::Int(I8) | ty::Uint(U8) => Ok(Self::u8()), + ty::Int(I16) | ty::Uint(U16) => Ok(Self::number(2)), + ty::Int(I32) | ty::Uint(U32) | ty::Float(F32) => Ok(Self::number(4)), + ty::Int(I64) | ty::Uint(U64) | ty::Float(F64) => Ok(Self::number(8)), + ty::Int(I128) | ty::Uint(U128) => Ok(Self::number(16)), + ty::Int(Isize) | ty::Uint(Usize) => { + Ok(Self::number(target.pointer_size.bytes_usize())) + } + + ty::Tuple(members) => { + if members.len() == 0 { + Ok(Tree::unit()) + } else { + Err(Err::Unspecified) + } + } + + ty::Array(ty, len) => { + let len = len.try_eval_usize(tcx, ParamEnv::reveal_all()).unwrap(); + let elt = Tree::from_ty(*ty, tcx)?; + Ok(std::iter::repeat(elt) + .take(len as usize) + .fold(Tree::unit(), |tree, elt| tree.then(elt))) + } + + ty::Adt(adt_def, substs_ref) => { + use rustc_middle::ty::AdtKind; + + // If the layout is ill-specified, halt. + if !(adt_def.repr().c() || adt_def.repr().int.is_some()) { + return Err(Err::Unspecified); + } + + // Compute a summary of the type's layout. + let layout_summary = LayoutSummary::from_ty(ty, tcx)?; + + // The layout begins with this adt's visibility. + let vis = Self::def(Def::Adt(*adt_def)); + + // And is followed the layout(s) of its variants + Ok(vis.then(match adt_def.adt_kind() { + AdtKind::Struct => Self::from_repr_c_variant( + ty, + *adt_def, + substs_ref, + &layout_summary, + None, + adt_def.non_enum_variant(), + tcx, + )?, + AdtKind::Enum => { + tracing::trace!( + adt_def = ?adt_def, + "treeifying enum" + ); + let mut tree = Tree::uninhabited(); + + for (idx, discr) in adt_def.discriminants(tcx) { + tree = tree.or(Self::from_repr_c_variant( + ty, + *adt_def, + substs_ref, + &layout_summary, + Some(discr), + adt_def.variant(idx), + tcx, + )?); + } + + tree + } + AdtKind::Union => { + // is the layout well-defined? + if !adt_def.repr().c() { + return Err(Err::Unspecified); + } + + let ty_layout = layout_of(tcx, ty)?; + + let mut tree = Tree::uninhabited(); + + for field in adt_def.all_fields() { + let variant_ty = field.ty(tcx, substs_ref); + let variant_layout = layout_of(tcx, variant_ty)?; + let padding_needed = ty_layout.size() - variant_layout.size(); + let variant = Self::def(Def::Field(field)) + .then(Self::from_ty(variant_ty, tcx)?) + .then(Self::padding(padding_needed)); + + tree = tree.or(variant); + } + + tree + } + })) + } + _ => Err(Err::Unspecified), + } + } + + fn from_repr_c_variant( + ty: Ty<'tcx>, + adt_def: AdtDef<'tcx>, + substs_ref: SubstsRef<'tcx>, + layout_summary: &LayoutSummary, + discr: Option>, + variant_def: &'tcx VariantDef, + tcx: TyCtxt<'tcx>, + ) -> Result { + let mut tree = Tree::unit(); + + let repr = adt_def.repr(); + let min_align = repr.align.unwrap_or(Align::ONE); + let max_align = repr.pack.unwrap_or(Align::MAX); + + let clamp = + |align: Align| align.clamp(min_align, max_align).bytes().try_into().unwrap(); + + let variant_span = tracing::trace_span!( + "treeifying variant", + min_align = ?min_align, + max_align = ?max_align, + ) + .entered(); + + let mut variant_layout = alloc::Layout::from_size_align( + 0, + layout_summary.total_align.bytes().try_into().unwrap(), + ) + .unwrap(); + + // The layout of the variant is prefixed by the discriminant, if any. + if let Some(discr) = discr { + tracing::trace!(discr = ?discr, "treeifying discriminant"); + let discr_layout = alloc::Layout::from_size_align( + layout_summary.discriminant_size, + clamp(layout_summary.discriminant_align), + ) + .unwrap(); + tracing::trace!(discr_layout = ?discr_layout, "computed discriminant layout"); + variant_layout = variant_layout.extend(discr_layout).unwrap().0; + tree = tree.then(Self::from_disr(discr, tcx, layout_summary.discriminant_size)); + } + + // Next come fields. + let fields_span = tracing::trace_span!("treeifying fields").entered(); + for field_def in variant_def.fields.iter() { + let field_ty = field_def.ty(tcx, substs_ref); + let _span = tracing::trace_span!("treeifying field", field = ?field_ty).entered(); + + // begin with the field's visibility + tree = tree.then(Self::def(Def::Field(field_def))); + + // compute the field's layout charactaristics + let field_layout = layout_of(tcx, field_ty)?.clamp_align(min_align, max_align); + + // next comes the field's padding + let padding_needed = variant_layout.padding_needed_for(field_layout.align()); + if padding_needed > 0 { + tree = tree.then(Self::padding(padding_needed)); + } + + // finally, the field's layout + tree = tree.then(Self::from_ty(field_ty, tcx)?); + + // extend the variant layout with the field layout + variant_layout = variant_layout.extend(field_layout).unwrap().0; + } + drop(fields_span); + + // finally: padding + let padding_span = tracing::trace_span!("adding trailing padding").entered(); + let padding_needed = layout_summary.total_size - variant_layout.size(); + if padding_needed > 0 { + tree = tree.then(Self::padding(padding_needed)); + }; + drop(padding_span); + drop(variant_span); + Ok(tree) + } + + pub fn from_disr(discr: Discr<'tcx>, tcx: TyCtxt<'tcx>, size: usize) -> Self { + // FIXME(@jswrenn): I'm certain this is missing needed endian nuance. + let bytes = discr.val.to_ne_bytes(); + let bytes = &bytes[..size]; + Self::Seq(bytes.into_iter().copied().map(|b| Self::from_bits(b)).collect()) + } + } + + fn layout_of<'tcx>( + ctx: TyCtxt<'tcx>, + ty: Ty<'tcx>, + ) -> Result> { + use rustc_middle::ty::ParamEnvAnd; + use rustc_target::abi::TyAndLayout; + + let param_env = ParamEnv::reveal_all(); + let param_env_and_type = ParamEnvAnd { param_env, value: ty }; + let TyAndLayout { layout, .. } = ctx.layout_of(param_env_and_type)?; + let layout = alloc::Layout::from_size_align( + layout.size().bytes_usize(), + layout.align().abi.bytes().try_into().unwrap(), + ) + .unwrap(); + tracing::trace!( + ty = ?ty, + layout = ?layout, + "computed layout for type" + ); + Ok(layout) + } +} diff --git a/compiler/rustc_transmute/src/layout/tree/tests.rs b/compiler/rustc_transmute/src/layout/tree/tests.rs new file mode 100644 index 0000000000000..90515e92f7aef --- /dev/null +++ b/compiler/rustc_transmute/src/layout/tree/tests.rs @@ -0,0 +1,80 @@ +use super::Tree; + +#[derive(Debug, Hash, Eq, PartialEq, Clone, Copy)] +pub enum Def { + Visible, + Invisible, +} + +impl super::Def for Def {} + +mod prune { + use super::*; + + mod should_simplify { + use super::*; + + #[test] + fn seq_1() { + let layout: Tree = Tree::def(Def::Visible).then(Tree::from_bits(0x00)); + assert_eq!(layout.prune(&|d| matches!(d, Def::Visible)), Tree::from_bits(0x00)); + } + + #[test] + fn seq_2() { + let layout: Tree = + Tree::from_bits(0x00).then(Tree::def(Def::Visible)).then(Tree::from_bits(0x01)); + + assert_eq!( + layout.prune(&|d| matches!(d, Def::Visible)), + Tree::from_bits(0x00).then(Tree::from_bits(0x01)) + ); + } + } + + mod should_reject { + use super::*; + + #[test] + fn invisible_def() { + let layout: Tree = Tree::def(Def::Invisible); + assert_eq!(layout.prune(&|d| matches!(d, Def::Visible)), Tree::uninhabited()); + } + + #[test] + fn invisible_def_in_seq_len_2() { + let layout: Tree = Tree::def(Def::Visible).then(Tree::def(Def::Invisible)); + assert_eq!(layout.prune(&|d| matches!(d, Def::Visible)), Tree::uninhabited()); + } + + #[test] + fn invisible_def_in_seq_len_3() { + let layout: Tree = + Tree::def(Def::Visible).then(Tree::from_bits(0x00)).then(Tree::def(Def::Invisible)); + assert_eq!(layout.prune(&|d| matches!(d, Def::Visible)), Tree::uninhabited()); + } + } + + mod should_accept { + use super::*; + + #[test] + fn visible_def() { + let layout: Tree = Tree::def(Def::Visible); + assert_eq!(layout.prune(&|d| matches!(d, Def::Visible)), Tree::unit()); + } + + #[test] + fn visible_def_in_seq_len_2() { + let layout: Tree = Tree::def(Def::Visible).then(Tree::def(Def::Visible)); + assert_eq!(layout.prune(&|d| matches!(d, Def::Visible)), Tree::unit()); + } + + #[test] + fn visible_def_in_seq_len_3() { + let layout: Tree = + Tree::def(Def::Visible).then(Tree::from_bits(0x00)).then(Tree::def(Def::Visible)); + assert_eq!(layout.prune(&|d| matches!(d, Def::Visible)), Tree::from_bits(0x00)); + } + } +} diff --git a/compiler/rustc_transmute/src/lib.rs b/compiler/rustc_transmute/src/lib.rs new file mode 100644 index 0000000000000..9f7508fdd716a --- /dev/null +++ b/compiler/rustc_transmute/src/lib.rs @@ -0,0 +1,114 @@ +#![feature( + alloc_layout_extra, + control_flow_enum, + decl_macro, + iterator_try_reduce, + never_type, + result_into_ok_or_err +)] +#![allow(dead_code, unused_variables)] + +#[cfg(feature = "rustc")] +pub(crate) use rustc_data_structures::fx::{FxHashMap as Map, FxHashSet as Set}; + +#[cfg(not(feature = "rustc"))] +pub(crate) use std::collections::{HashMap as Map, HashSet as Set}; + +pub(crate) mod layout; +pub(crate) mod maybe_transmutable; + +#[derive(Default)] +pub struct Assume { + pub alignment: bool, + pub lifetimes: bool, + pub validity: bool, + pub visibility: bool, +} + +/// The type encodes answers to the question: "Are these types transmutable?" +#[derive(Debug, Hash, Eq, PartialEq, PartialOrd, Ord, Clone)] +pub enum Answer +where + R: layout::Ref, +{ + /// `Src` is transmutable into `Dst`. + Yes, + + /// `Src` is NOT transmutable into `Dst`. + No(Reason), + + /// `Src` is transmutable into `Dst`, if `src` is transmutable into `dst`. + IfTransmutable { src: R, dst: R }, + + /// `Src` is transmutable into `Dst`, if all of the enclosed requirements are met. + IfAll(Vec>), + + /// `Src` is transmutable into `Dst` if any of the enclosed requirements are met. + IfAny(Vec>), +} + +/// Answers: Why wasn't the source type transmutable into the destination type? +#[derive(Debug, Hash, Eq, PartialEq, PartialOrd, Ord, Clone)] +pub enum Reason { + /// The layout of the source type is unspecified. + SrcIsUnspecified, + /// The layout of the destination type is unspecified. + DstIsUnspecified, + /// The layout of the destination type is bit-incompatible with the source type. + DstIsBitIncompatible, + /// There aren't any public constructors for `Dst`. + DstIsPrivate, + /// `Dst` is larger than `Src`, and the excess bytes were not exclusively uninitialized. + DstIsTooBig, +} + +#[cfg(feature = "rustc")] +mod rustc { + use rustc_infer::infer::InferCtxt; + use rustc_macros::{TypeFoldable, TypeVisitable}; + use rustc_middle::traits::ObligationCause; + use rustc_middle::ty::Binder; + use rustc_middle::ty::Ty; + + /// The source and destination types of a transmutation. + #[derive(TypeFoldable, TypeVisitable, Debug, Clone, Copy)] + pub struct Types<'tcx> { + /// The source type. + pub src: Ty<'tcx>, + /// The destination type. + pub dst: Ty<'tcx>, + } + + pub struct TransmuteTypeEnv<'cx, 'tcx> { + infcx: &'cx InferCtxt<'cx, 'tcx>, + } + + impl<'cx, 'tcx> TransmuteTypeEnv<'cx, 'tcx> { + pub fn new(infcx: &'cx InferCtxt<'cx, 'tcx>) -> Self { + Self { infcx } + } + + #[allow(unused)] + pub fn is_transmutable( + &mut self, + cause: ObligationCause<'tcx>, + src_and_dst: Binder<'tcx, Types<'tcx>>, + scope: Ty<'tcx>, + assume: crate::Assume, + ) -> crate::Answer> { + let src = src_and_dst.map_bound(|types| types.src).skip_binder(); + let dst = src_and_dst.map_bound(|types| types.dst).skip_binder(); + crate::maybe_transmutable::MaybeTransmutableQuery::new( + src, + dst, + scope, + assume, + self.infcx.tcx, + ) + .answer() + } + } +} + +#[cfg(feature = "rustc")] +pub use rustc::*; diff --git a/compiler/rustc_transmute/src/maybe_transmutable/mod.rs b/compiler/rustc_transmute/src/maybe_transmutable/mod.rs new file mode 100644 index 0000000000000..ef3852001a806 --- /dev/null +++ b/compiler/rustc_transmute/src/maybe_transmutable/mod.rs @@ -0,0 +1,320 @@ +use crate::Map; +use crate::{Answer, Reason}; + +#[cfg(test)] +mod tests; + +mod query_context; +use query_context::QueryContext; + +use crate::layout::{self, dfa, Byte, Dfa, Nfa, Tree, Uninhabited}; +pub(crate) struct MaybeTransmutableQuery +where + C: QueryContext, +{ + src: L, + dst: L, + scope: ::Scope, + assume: crate::Assume, + context: C, +} + +impl MaybeTransmutableQuery +where + C: QueryContext, +{ + pub(crate) fn new( + src: L, + dst: L, + scope: ::Scope, + assume: crate::Assume, + context: C, + ) -> Self { + Self { src, dst, scope, assume, context } + } + + pub(crate) fn map_layouts( + self, + f: F, + ) -> Result, Answer<::Ref>> + where + F: FnOnce( + L, + L, + ::Scope, + &C, + ) -> Result<(M, M), Answer<::Ref>>, + { + let Self { src, dst, scope, assume, context } = self; + + let (src, dst) = f(src, dst, scope, &context)?; + + Ok(MaybeTransmutableQuery { src, dst, scope, assume, context }) + } +} + +#[cfg(feature = "rustc")] +mod rustc { + use super::*; + use crate::layout::tree::Err; + + use rustc_middle::ty::Ty; + use rustc_middle::ty::TyCtxt; + + impl<'tcx> MaybeTransmutableQuery, TyCtxt<'tcx>> { + /// This method begins by converting `src` and `dst` from `Ty`s to `Tree`s, + /// then computes an answer using those trees. + #[tracing::instrument(skip(self), fields(src = ?self.src, dst = ?self.dst))] + pub fn answer(self) -> Answer< as QueryContext>::Ref> { + let query_or_answer = self.map_layouts(|src, dst, scope, &context| { + // Convert `src` and `dst` from their rustc representations, to `Tree`-based + // representations. If these conversions fail, conclude that the transmutation is + // unacceptable; the layouts of both the source and destination types must be + // well-defined. + let src = Tree::from_ty(src, context).map_err(|err| match err { + // Answer `Yes` here, because "Unknown Type" will already be reported by + // rustc. No need to spam the user with more errors. + Err::Unknown => Answer::Yes, + Err::Unspecified => Answer::No(Reason::SrcIsUnspecified), + })?; + + let dst = Tree::from_ty(dst, context).map_err(|err| match err { + Err::Unknown => Answer::Yes, + Err::Unspecified => Answer::No(Reason::DstIsUnspecified), + })?; + + Ok((src, dst)) + }); + + match query_or_answer { + Ok(query) => query.answer(), + Err(answer) => answer, + } + } + } +} + +impl MaybeTransmutableQuery::Def, ::Ref>, C> +where + C: QueryContext, +{ + /// Answers whether a `Tree` is transmutable into another `Tree`. + /// + /// This method begins by de-def'ing `src` and `dst`, and prunes private paths from `dst`, + /// then converts `src` and `dst` to `Nfa`s, and computes an answer using those NFAs. + #[inline(always)] + #[tracing::instrument(skip(self), fields(src = ?self.src, dst = ?self.dst))] + pub(crate) fn answer(self) -> Answer<::Ref> { + let assume_visibility = self.assume.visibility; + let query_or_answer = self.map_layouts(|src, dst, scope, context| { + // Remove all `Def` nodes from `src`, without checking their visibility. + let src = src.prune(&|def| true); + + tracing::trace!(src = ?src, "pruned src"); + + // Remove all `Def` nodes from `dst`, additionally... + let dst = if assume_visibility { + // ...if visibility is assumed, don't check their visibility. + dst.prune(&|def| true) + } else { + // ...otherwise, prune away all unreachable paths through the `Dst` layout. + dst.prune(&|def| context.is_accessible_from(def, scope)) + }; + + tracing::trace!(dst = ?dst, "pruned dst"); + + // Convert `src` from a tree-based representation to an NFA-based representation. + // If the conversion fails because `src` is uninhabited, conclude that the transmutation + // is acceptable, because instances of the `src` type do not exist. + let src = Nfa::from_tree(src).map_err(|Uninhabited| Answer::Yes)?; + + // Convert `dst` from a tree-based representation to an NFA-based representation. + // If the conversion fails because `src` is uninhabited, conclude that the transmutation + // is unacceptable, because instances of the `dst` type do not exist. + let dst = + Nfa::from_tree(dst).map_err(|Uninhabited| Answer::No(Reason::DstIsPrivate))?; + + Ok((src, dst)) + }); + + match query_or_answer { + Ok(query) => query.answer(), + Err(answer) => answer, + } + } +} + +impl MaybeTransmutableQuery::Ref>, C> +where + C: QueryContext, +{ + /// Answers whether a `Nfa` is transmutable into another `Nfa`. + /// + /// This method converts `src` and `dst` to DFAs, then computes an answer using those DFAs. + #[inline(always)] + #[tracing::instrument(skip(self), fields(src = ?self.src, dst = ?self.dst))] + pub(crate) fn answer(self) -> Answer<::Ref> { + let query_or_answer = self + .map_layouts(|src, dst, scope, context| Ok((Dfa::from_nfa(src), Dfa::from_nfa(dst)))); + + match query_or_answer { + Ok(query) => query.answer(), + Err(answer) => answer, + } + } +} + +impl MaybeTransmutableQuery::Ref>, C> +where + C: QueryContext, +{ + /// Answers whether a `Nfa` is transmutable into another `Nfa`. + /// + /// This method converts `src` and `dst` to DFAs, then computes an answer using those DFAs. + pub(crate) fn answer(self) -> Answer<::Ref> { + MaybeTransmutableQuery { + src: &self.src, + dst: &self.dst, + scope: self.scope, + assume: self.assume, + context: self.context, + } + .answer() + } +} + +impl<'l, C> MaybeTransmutableQuery<&'l Dfa<::Ref>, C> +where + C: QueryContext, +{ + pub(crate) fn answer(&mut self) -> Answer<::Ref> { + self.answer_memo(&mut Map::default(), self.src.start, self.dst.start) + } + + #[inline(always)] + #[tracing::instrument(skip(self))] + fn answer_memo( + &self, + cache: &mut Map<(dfa::State, dfa::State), Answer<::Ref>>, + src_state: dfa::State, + dst_state: dfa::State, + ) -> Answer<::Ref> { + if let Some(answer) = cache.get(&(src_state, dst_state)) { + answer.clone() + } else { + let answer = if dst_state == self.dst.accepting { + // truncation: `size_of(Src) >= size_of(Dst)` + Answer::Yes + } else if src_state == self.src.accepting { + // extension: `size_of(Src) >= size_of(Dst)` + if let Some(dst_state_prime) = self.dst.byte_from(dst_state, Byte::Uninit) { + self.answer_memo(cache, src_state, dst_state_prime) + } else { + Answer::No(Reason::DstIsTooBig) + } + } else { + let src_quantification = if self.assume.validity { + // if the compiler may assume that the programmer is doing additional validity checks, + // (e.g.: that `src != 3u8` when the destination type is `bool`) + // then there must exist at least one transition out of `src_state` such that the transmute is viable... + there_exists + } else { + // if the compiler cannot assume that the programmer is doing additional validity checks, + // then for all transitions out of `src_state`, such that the transmute is viable... + // then there must exist at least one transition out of `src_state` such that the transmute is viable... + for_all + }; + + src_quantification( + self.src.bytes_from(src_state).unwrap_or(&Map::default()), + |(&src_validity, &src_state_prime)| { + if let Some(dst_state_prime) = self.dst.byte_from(dst_state, src_validity) { + self.answer_memo(cache, src_state_prime, dst_state_prime) + } else if let Some(dst_state_prime) = + self.dst.byte_from(dst_state, Byte::Uninit) + { + self.answer_memo(cache, src_state_prime, dst_state_prime) + } else { + Answer::No(Reason::DstIsBitIncompatible) + } + }, + ) + }; + cache.insert((src_state, dst_state), answer.clone()); + answer + } + } +} + +impl Answer +where + R: layout::Ref, +{ + pub(crate) fn and(self, rhs: Self) -> Self { + match (self, rhs) { + (Self::No(reason), _) | (_, Self::No(reason)) => Self::No(reason), + (Self::Yes, Self::Yes) => Self::Yes, + (Self::IfAll(mut lhs), Self::IfAll(ref mut rhs)) => { + lhs.append(rhs); + Self::IfAll(lhs) + } + (constraint, Self::IfAll(mut constraints)) + | (Self::IfAll(mut constraints), constraint) => { + constraints.push(constraint); + Self::IfAll(constraints) + } + (lhs, rhs) => Self::IfAll(vec![lhs, rhs]), + } + } + + pub(crate) fn or(self, rhs: Self) -> Self { + match (self, rhs) { + (Self::Yes, _) | (_, Self::Yes) => Self::Yes, + (Self::No(lhr), Self::No(rhr)) => Self::No(lhr), + (Self::IfAny(mut lhs), Self::IfAny(ref mut rhs)) => { + lhs.append(rhs); + Self::IfAny(lhs) + } + (constraint, Self::IfAny(mut constraints)) + | (Self::IfAny(mut constraints), constraint) => { + constraints.push(constraint); + Self::IfAny(constraints) + } + (lhs, rhs) => Self::IfAny(vec![lhs, rhs]), + } + } +} + +pub fn for_all(iter: I, f: F) -> Answer +where + R: layout::Ref, + I: IntoIterator, + F: FnMut(::Item) -> Answer, +{ + use std::ops::ControlFlow::{Break, Continue}; + let (Continue(result) | Break(result)) = + iter.into_iter().map(f).try_fold(Answer::Yes, |constraints, constraint| { + match constraint.and(constraints) { + Answer::No(reason) => Break(Answer::No(reason)), + maybe => Continue(maybe), + } + }); + result +} + +pub fn there_exists(iter: I, f: F) -> Answer +where + R: layout::Ref, + I: IntoIterator, + F: FnMut(::Item) -> Answer, +{ + use std::ops::ControlFlow::{Break, Continue}; + let (Continue(result) | Break(result)) = iter.into_iter().map(f).try_fold( + Answer::No(Reason::DstIsBitIncompatible), + |constraints, constraint| match constraint.or(constraints) { + Answer::Yes => Break(Answer::Yes), + maybe => Continue(maybe), + }, + ); + result +} diff --git a/compiler/rustc_transmute/src/maybe_transmutable/query_context.rs b/compiler/rustc_transmute/src/maybe_transmutable/query_context.rs new file mode 100644 index 0000000000000..ab9bcd232f0d0 --- /dev/null +++ b/compiler/rustc_transmute/src/maybe_transmutable/query_context.rs @@ -0,0 +1,93 @@ +use crate::layout; + +/// Context necessary to answer the question "Are these types transmutable?". +pub(crate) trait QueryContext { + type Def: layout::Def; + type Ref: layout::Ref; + type Scope: Copy; + + /// Is `def` accessible from the defining module of `scope`? + fn is_accessible_from(&self, def: Self::Def, scope: Self::Scope) -> bool; + + fn min_align(&self, reference: Self::Ref) -> usize; +} + +#[cfg(test)] +pub(crate) mod test { + use super::QueryContext; + + pub(crate) struct UltraMinimal; + + #[derive(Debug, Hash, Eq, PartialEq, Clone, Copy)] + pub(crate) enum Def { + Visible, + Invisible, + } + + impl crate::layout::Def for Def {} + + impl QueryContext for UltraMinimal { + type Def = Def; + type Ref = !; + type Scope = (); + + fn is_accessible_from(&self, def: Def, scope: ()) -> bool { + matches!(Def::Visible, def) + } + + fn min_align(&self, reference: !) -> usize { + unimplemented!() + } + } +} + +#[cfg(feature = "rustc")] +mod rustc { + use super::*; + use rustc_middle::ty::{Ty, TyCtxt}; + + impl<'tcx> super::QueryContext for TyCtxt<'tcx> { + type Def = layout::rustc::Def<'tcx>; + type Ref = layout::rustc::Ref<'tcx>; + + type Scope = Ty<'tcx>; + + #[tracing::instrument(skip(self))] + fn is_accessible_from(&self, def: Self::Def, scope: Self::Scope) -> bool { + use layout::rustc::Def; + use rustc_middle::ty; + + let parent = if let ty::Adt(adt_def, ..) = scope.kind() { + use rustc_middle::ty::DefIdTree; + let parent = self.parent(adt_def.did()); + parent + } else { + // Is this always how we want to handle a non-ADT scope? + return false; + }; + + let def_id = match def { + Def::Adt(adt_def) => adt_def.did(), + Def::Variant(variant_def) => variant_def.def_id, + Def::Field(field_def) => field_def.did, + Def::Primitive => { + // primitives do not have a def_id, but they're always accessible + return true; + } + }; + + let ret = if self.visibility(def_id).is_accessible_from(parent, *self) { + true + } else { + false + }; + + tracing::trace!(ret = ?ret, "ret"); + ret + } + + fn min_align(&self, reference: Self::Ref) -> usize { + unimplemented!() + } + } +} diff --git a/compiler/rustc_transmute/src/maybe_transmutable/tests.rs b/compiler/rustc_transmute/src/maybe_transmutable/tests.rs new file mode 100644 index 0000000000000..d9d125687f656 --- /dev/null +++ b/compiler/rustc_transmute/src/maybe_transmutable/tests.rs @@ -0,0 +1,115 @@ +use super::query_context::test::{Def, UltraMinimal}; +use crate::maybe_transmutable::MaybeTransmutableQuery; +use crate::{layout, Answer, Reason, Set}; +use itertools::Itertools; + +mod bool { + use super::*; + + #[test] + fn should_permit_identity_transmutation_tree() { + println!("{:?}", layout::Tree::::bool()); + let answer = crate::maybe_transmutable::MaybeTransmutableQuery::new( + layout::Tree::::bool(), + layout::Tree::::bool(), + (), + crate::Assume { alignment: false, lifetimes: false, validity: true, visibility: false }, + UltraMinimal, + ) + .answer(); + assert_eq!(answer, Answer::Yes); + } + + #[test] + fn should_permit_identity_transmutation_dfa() { + let answer = crate::maybe_transmutable::MaybeTransmutableQuery::new( + layout::Dfa::::bool(), + layout::Dfa::::bool(), + (), + crate::Assume { alignment: false, lifetimes: false, validity: true, visibility: false }, + UltraMinimal, + ) + .answer(); + assert_eq!(answer, Answer::Yes); + } + + #[test] + fn should_permit_validity_expansion_and_reject_contraction() { + let un = layout::Tree::::uninhabited(); + let b0 = layout::Tree::::from_bits(0); + let b1 = layout::Tree::::from_bits(1); + let b2 = layout::Tree::::from_bits(2); + + let alts = [b0, b1, b2]; + + let into_layout = |alts: Vec<_>| { + alts.into_iter().fold(layout::Tree::::uninhabited(), layout::Tree::::or) + }; + + let into_set = |alts: Vec<_>| { + #[cfg(feature = "rustc")] + let mut set = Set::default(); + #[cfg(not(feature = "rustc"))] + let mut set = Set::new(); + set.extend(alts); + set + }; + + for src_alts in alts.clone().into_iter().powerset() { + let src_layout = into_layout(src_alts.clone()); + let src_set = into_set(src_alts.clone()); + + for dst_alts in alts.clone().into_iter().powerset().filter(|alts| !alts.is_empty()) { + let dst_layout = into_layout(dst_alts.clone()); + let dst_set = into_set(dst_alts.clone()); + + if src_set.is_subset(&dst_set) { + assert_eq!( + Answer::Yes, + MaybeTransmutableQuery::new( + src_layout.clone(), + dst_layout.clone(), + (), + crate::Assume { validity: false, ..crate::Assume::default() }, + UltraMinimal, + ) + .answer(), + "{:?} SHOULD be transmutable into {:?}", + src_layout, + dst_layout + ); + } else if !src_set.is_disjoint(&dst_set) { + assert_eq!( + Answer::Yes, + MaybeTransmutableQuery::new( + src_layout.clone(), + dst_layout.clone(), + (), + crate::Assume { validity: true, ..crate::Assume::default() }, + UltraMinimal, + ) + .answer(), + "{:?} SHOULD be transmutable (assuming validity) into {:?}", + src_layout, + dst_layout + ); + } else { + assert_eq!( + Answer::No(Reason::DstIsBitIncompatible), + MaybeTransmutableQuery::new( + src_layout.clone(), + dst_layout.clone(), + (), + crate::Assume { validity: false, ..crate::Assume::default() }, + UltraMinimal, + ) + .answer(), + "{:?} should NOT be transmutable into {:?}", + src_layout, + dst_layout + ); + } + } + } + } +} diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index 234fa213da89f..add65a3be5042 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -27,6 +27,10 @@ mod valid_align; // alignment as a parameter, such as `Layout::padding_needed_for`. pub(crate) use valid_align::ValidAlign; +mod transmutability; +#[unstable(feature = "transmutability", issue = "none")] +pub use transmutability::{Assume, BikeshedIntrinsicFrom}; + #[stable(feature = "rust1", since = "1.0.0")] #[doc(inline)] pub use crate::intrinsics::transmute; diff --git a/library/core/src/mem/transmutability.rs b/library/core/src/mem/transmutability.rs new file mode 100644 index 0000000000000..52342f8a0ecd6 --- /dev/null +++ b/library/core/src/mem/transmutability.rs @@ -0,0 +1,39 @@ +/// Are values of a type transmutable into values of another type? +/// +/// This trait is implemented on-the-fly by the compiler for types `Src` and `Self` when the bits of +/// any value of type `Self` are safely transmutable into a value of type `Dst`, in a given `Context`, +/// notwithstanding whatever safety checks you have asked the compiler to [`Assume`] are satisfied. +#[unstable(feature = "transmutability", issue = "none")] +#[cfg_attr(not(bootstrap), lang = "transmute_trait")] +pub unsafe trait BikeshedIntrinsicFrom< + Src, + Context, + const ASSUME_ALIGNMENT: bool, + const ASSUME_LIFETIMES: bool, + const ASSUME_VALIDITY: bool, + const ASSUME_VISIBILITY: bool, +> where + Src: ?Sized, +{ +} + +/// What transmutation safety conditions shall the compiler assume that *you* are checking? +#[unstable(feature = "transmutability", issue = "none")] +#[derive(PartialEq, Eq, Clone, Copy, Debug)] +pub struct Assume { + /// When `true`, the compiler assumes that *you* are ensuring (either dynamically or statically) that + /// destination referents do not have stricter alignment requirements than source referents. + pub alignment: bool, + + /// When `true`, the compiler assume that *you* are ensuring that lifetimes are not extended in a manner + /// that violates Rust's memory model. + pub lifetimes: bool, + + /// When `true`, the compiler assumes that *you* are ensuring that the source type is actually a valid + /// instance of the destination type. + pub validity: bool, + + /// When `true`, the compiler assumes that *you* have ensured that it is safe for you to violate the + /// type and field privacy of the destination type (and sometimes of the source type, too). + pub visibility: bool, +} diff --git a/src/test/ui/transmutability/abstraction/const_generic_fn.rs b/src/test/ui/transmutability/abstraction/const_generic_fn.rs new file mode 100644 index 0000000000000..94c38bb28f7e2 --- /dev/null +++ b/src/test/ui/transmutability/abstraction/const_generic_fn.rs @@ -0,0 +1,41 @@ +// check-pass +//! An array must have the correct length. + +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code, incomplete_features, non_camel_case_types)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + pub struct Context; + + pub fn array_like() + where + T: BikeshedIntrinsicFrom<[E; N], Context, false, false, false, true>, + [E; N]: BikeshedIntrinsicFrom + {} +} + +fn len_0() { + type Array = [u8; 0]; + #[repr(C)] struct Struct(); + assert::array_like::(); +} + +fn len_1() { + type Array = [u8; 1]; + #[repr(C)] struct Struct(u8); + assert::array_like::(); +} + +fn len_2() { + type Array = [u8; 2]; + #[repr(C)] struct Struct(u8, u8); + assert::array_like::(); +} + +fn len_3() { + type Array = [u8; 3]; + #[repr(C)] struct Struct(u8, u8, u8); + assert::array_like::(); +} diff --git a/src/test/ui/transmutability/arrays/should_have_correct_length.rs b/src/test/ui/transmutability/arrays/should_have_correct_length.rs new file mode 100644 index 0000000000000..bfe6d830a1be7 --- /dev/null +++ b/src/test/ui/transmutability/arrays/should_have_correct_length.rs @@ -0,0 +1,44 @@ +// check-pass +//! An array must have the correct length. + +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code, incomplete_features, non_camel_case_types)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + pub struct Context; + + pub fn is_maybe_transmutable() + where + Dst: BikeshedIntrinsicFrom + {} +} + +fn should_have_len_0() { + type Array = [u8; 0]; + #[repr(C)] struct Struct(); + assert::is_maybe_transmutable::(); + assert::is_maybe_transmutable::(); +} + +fn should_have_len_1() { + type Array = [u8; 1]; + #[repr(C)] struct Struct(u8); + assert::is_maybe_transmutable::(); + assert::is_maybe_transmutable::(); +} + +fn should_have_len_2() { + type Array = [u8; 2]; + #[repr(C)] struct Struct(u8, u8); + assert::is_maybe_transmutable::(); + assert::is_maybe_transmutable::(); +} + +fn should_have_len_3() { + type Array = [u8; 3]; + #[repr(C)] struct Struct(u8, u8, u8); + assert::is_maybe_transmutable::(); + assert::is_maybe_transmutable::(); +} diff --git a/src/test/ui/transmutability/arrays/should_inherit_alignment.rs b/src/test/ui/transmutability/arrays/should_inherit_alignment.rs new file mode 100644 index 0000000000000..fcb1765ea6bb4 --- /dev/null +++ b/src/test/ui/transmutability/arrays/should_inherit_alignment.rs @@ -0,0 +1,55 @@ +// check-pass +//! An array must inherit the alignment of its inner type. + +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code, incomplete_features, non_camel_case_types)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + pub struct Context; + + pub fn is_maybe_transmutable() + where + Dst: BikeshedIntrinsicFrom + {} +} + +#[derive(Clone, Copy)] #[repr(u8)] enum Ox00 { V = 0x00 } +#[derive(Clone, Copy)] #[repr(u8)] enum Ox01 { V = 0x01 } +#[derive(Clone, Copy)] #[repr(u8)] enum OxFF { V = 0xFF } + +#[repr(C)] +union Uninit { + a: (), + b: OxFF, +} + +#[repr(C, align(2))] struct align_2(Ox00); + +fn len_0() { + #[repr(C)] struct ImplicitlyPadded([align_2; 0], Ox01); + #[repr(C)] struct ExplicitlyPadded(Ox01, Uninit); + + #[repr(C)] struct Struct(); + assert::is_maybe_transmutable::(); + assert::is_maybe_transmutable::(); +} + +fn len_1() { + #[repr(C)] struct ImplicitlyPadded([align_2; 1], Ox01); + #[repr(C)] struct ExplicitlyPadded(Ox00, Uninit, Ox01, Uninit); + + #[repr(C)] struct Struct(); + assert::is_maybe_transmutable::(); + assert::is_maybe_transmutable::(); +} + +fn len_2() { + #[repr(C)] struct ImplicitlyPadded([align_2; 2], Ox01); + #[repr(C)] struct ExplicitlyPadded(Ox00, Uninit, Ox00, Uninit, Ox01, Uninit); + + #[repr(C)] struct Struct(); + assert::is_maybe_transmutable::(); + assert::is_maybe_transmutable::(); +} diff --git a/src/test/ui/transmutability/arrays/should_require_well_defined_layout.rs b/src/test/ui/transmutability/arrays/should_require_well_defined_layout.rs new file mode 100644 index 0000000000000..36f9ceb0da7a6 --- /dev/null +++ b/src/test/ui/transmutability/arrays/should_require_well_defined_layout.rs @@ -0,0 +1,61 @@ +//! An array must have a well-defined layout to participate in a transmutation. + +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code, incomplete_features, non_camel_case_types)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + pub struct Context; + + pub fn is_maybe_transmutable() + where + Dst: BikeshedIntrinsicFrom + {} +} + +fn should_reject_repr_rust() +{ + fn unit() { + type repr_rust = [String; 0]; + assert::is_maybe_transmutable::(); //~ ERROR not satisfied + assert::is_maybe_transmutable::(); //~ ERROR not satisfied + } + + fn singleton() { + type repr_rust = [String; 1]; + assert::is_maybe_transmutable::(); //~ ERROR not satisfied + assert::is_maybe_transmutable::(); //~ ERROR not satisfied + } + + fn duplex() { + type repr_rust = [String; 2]; + assert::is_maybe_transmutable::(); //~ ERROR not satisfied + assert::is_maybe_transmutable::(); //~ ERROR not satisfied + } +} + +fn should_accept_repr_C() +{ + fn unit() { + #[repr(C)] struct repr_c(u8, u16, u8); + type array = [repr_c; 0]; + assert::is_maybe_transmutable::(); + assert::is_maybe_transmutable::(); + } + + fn singleton() { + #[repr(C)] struct repr_c(u8, u16, u8); + type array = [repr_c; 1]; + assert::is_maybe_transmutable::(); + assert::is_maybe_transmutable::(); + } + + fn duplex() { + #[repr(C)] struct repr_c(u8, u16, u8); + #[repr(C)] struct duplex(repr_c, repr_c); + type array = [repr_c; 2]; + assert::is_maybe_transmutable::(); + assert::is_maybe_transmutable::(); + } +} diff --git a/src/test/ui/transmutability/arrays/should_require_well_defined_layout.stderr b/src/test/ui/transmutability/arrays/should_require_well_defined_layout.stderr new file mode 100644 index 0000000000000..109e58c4093cb --- /dev/null +++ b/src/test/ui/transmutability/arrays/should_require_well_defined_layout.stderr @@ -0,0 +1,93 @@ +error[E0277]: the trait bound `(): BikeshedIntrinsicFrom<[String; 0], assert::Context, true, true, true, true>` is not satisfied + --> $DIR/should_require_well_defined_layout.rs:21:52 + | +LL | assert::is_maybe_transmutable::(); + | ^^ the trait `BikeshedIntrinsicFrom<[String; 0], assert::Context, true, true, true, true>` is not implemented for `()` + | +note: required by a bound in `is_maybe_transmutable` + --> $DIR/should_require_well_defined_layout.rs:13:14 + | +LL | pub fn is_maybe_transmutable() + | --------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` + +error[E0277]: the trait bound `[String; 0]: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/should_require_well_defined_layout.rs:22:47 + | +LL | assert::is_maybe_transmutable::(); + | ^^^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `[String; 0]` + | +note: required by a bound in `is_maybe_transmutable` + --> $DIR/should_require_well_defined_layout.rs:13:14 + | +LL | pub fn is_maybe_transmutable() + | --------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` + +error[E0277]: the trait bound `(): BikeshedIntrinsicFrom<[String; 1], assert::Context, true, true, true, true>` is not satisfied + --> $DIR/should_require_well_defined_layout.rs:27:52 + | +LL | assert::is_maybe_transmutable::(); + | ^^ the trait `BikeshedIntrinsicFrom<[String; 1], assert::Context, true, true, true, true>` is not implemented for `()` + | +note: required by a bound in `is_maybe_transmutable` + --> $DIR/should_require_well_defined_layout.rs:13:14 + | +LL | pub fn is_maybe_transmutable() + | --------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` + +error[E0277]: the trait bound `[String; 1]: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/should_require_well_defined_layout.rs:28:47 + | +LL | assert::is_maybe_transmutable::(); + | ^^^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `[String; 1]` + | +note: required by a bound in `is_maybe_transmutable` + --> $DIR/should_require_well_defined_layout.rs:13:14 + | +LL | pub fn is_maybe_transmutable() + | --------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` + +error[E0277]: the trait bound `(): BikeshedIntrinsicFrom<[String; 2], assert::Context, true, true, true, true>` is not satisfied + --> $DIR/should_require_well_defined_layout.rs:33:52 + | +LL | assert::is_maybe_transmutable::(); + | ^^ the trait `BikeshedIntrinsicFrom<[String; 2], assert::Context, true, true, true, true>` is not implemented for `()` + | +note: required by a bound in `is_maybe_transmutable` + --> $DIR/should_require_well_defined_layout.rs:13:14 + | +LL | pub fn is_maybe_transmutable() + | --------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` + +error[E0277]: the trait bound `[String; 2]: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/should_require_well_defined_layout.rs:34:47 + | +LL | assert::is_maybe_transmutable::(); + | ^^^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `[String; 2]` + | +note: required by a bound in `is_maybe_transmutable` + --> $DIR/should_require_well_defined_layout.rs:13:14 + | +LL | pub fn is_maybe_transmutable() + | --------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/transmutability/enums/repr/primitive_reprs_should_have_correct_length.rs b/src/test/ui/transmutability/enums/repr/primitive_reprs_should_have_correct_length.rs new file mode 100644 index 0000000000000..cd411a4b838e0 --- /dev/null +++ b/src/test/ui/transmutability/enums/repr/primitive_reprs_should_have_correct_length.rs @@ -0,0 +1,149 @@ +//! An enum with a primitive repr should have exactly the size of that primitive. + +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + + pub fn is_transmutable() + where + Dst: BikeshedIntrinsicFrom + {} +} + +#[repr(C)] +struct Zst; + +#[derive(Clone, Copy)] +#[repr(i8)] enum V0i8 { V } +#[repr(u8)] enum V0u8 { V } +#[repr(i16)] enum V0i16 { V } +#[repr(u16)] enum V0u16 { V } +#[repr(i32)] enum V0i32 { V } +#[repr(u32)] enum V0u32 { V } +#[repr(i64)] enum V0i64 { V } +#[repr(u64)] enum V0u64 { V } +#[repr(isize)] enum V0isize { V } +#[repr(usize)] enum V0usize { V } + +fn n8() { + struct Context; + + type Smaller = Zst; + type Analog = u8; + type Larger = u16; + + fn i_should_have_correct_length() { + type Current = V0i8; + + assert::is_transmutable::(); //~ ERROR not satisfied + assert::is_transmutable::(); + assert::is_transmutable::(); //~ ERROR not satisfied + } + + fn u_should_have_correct_length() { + type Current = V0u8; + + assert::is_transmutable::(); //~ ERROR not satisfied + assert::is_transmutable::(); + assert::is_transmutable::(); //~ ERROR not satisfied + } +} + +fn n16() { + struct Context; + + type Smaller = u8; + type Analog = u16; + type Larger = u32; + + fn i_should_have_correct_length() { + type Current = V0i16; + + assert::is_transmutable::(); //~ ERROR not satisfied + assert::is_transmutable::(); + assert::is_transmutable::(); //~ ERROR not satisfied + } + + fn u_should_have_correct_length() { + type Current = V0u16; + + assert::is_transmutable::(); //~ ERROR not satisfied + assert::is_transmutable::(); + assert::is_transmutable::(); //~ ERROR not satisfied + } +} + +fn n32() { + struct Context; + + type Smaller = u16; + type Analog = u32; + type Larger = u64; + + fn i_should_have_correct_length() { + type Current = V0i32; + + assert::is_transmutable::(); //~ ERROR not satisfied + assert::is_transmutable::(); + assert::is_transmutable::(); //~ ERROR not satisfied + } + + fn u_should_have_correct_length() { + type Current = V0u32; + + assert::is_transmutable::(); //~ ERROR not satisfied + assert::is_transmutable::(); + assert::is_transmutable::(); //~ ERROR not satisfied + } +} + +fn n64() { + struct Context; + + type Smaller = u32; + type Analog = u64; + type Larger = u128; + + fn i_should_have_correct_length() { + type Current = V0i64; + + assert::is_transmutable::(); //~ ERROR not satisfied + assert::is_transmutable::(); + assert::is_transmutable::(); //~ ERROR not satisfied + } + + fn u_should_have_correct_length() { + type Current = V0u64; + + assert::is_transmutable::(); //~ ERROR not satisfied + assert::is_transmutable::(); + assert::is_transmutable::(); //~ ERROR not satisfied + } +} + +fn nsize() { + struct Context; + + type Smaller = u8; + type Analog = usize; + type Larger = [usize; 2]; + + fn i_should_have_correct_length() { + type Current = V0isize; + + assert::is_transmutable::(); //~ ERROR not satisfied + assert::is_transmutable::(); + assert::is_transmutable::(); //~ ERROR not satisfied + } + + fn u_should_have_correct_length() { + type Current = V0usize; + + assert::is_transmutable::(); //~ ERROR not satisfied + assert::is_transmutable::(); + assert::is_transmutable::(); //~ ERROR not satisfied + } +} diff --git a/src/test/ui/transmutability/enums/repr/primitive_reprs_should_have_correct_length.stderr b/src/test/ui/transmutability/enums/repr/primitive_reprs_should_have_correct_length.stderr new file mode 100644 index 0000000000000..da24c6a021efe --- /dev/null +++ b/src/test/ui/transmutability/enums/repr/primitive_reprs_should_have_correct_length.stderr @@ -0,0 +1,303 @@ +error[E0277]: the trait bound `V0i8: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/primitive_reprs_should_have_correct_length.rs:41:44 + | +LL | assert::is_transmutable::(); + | ^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `V0i8` + | +note: required by a bound in `is_transmutable` + --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `u16: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/primitive_reprs_should_have_correct_length.rs:43:44 + | +LL | assert::is_transmutable::(); + | ^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u16` + | +note: required by a bound in `is_transmutable` + --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `V0u8: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/primitive_reprs_should_have_correct_length.rs:49:44 + | +LL | assert::is_transmutable::(); + | ^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `V0u8` + | +note: required by a bound in `is_transmutable` + --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `u16: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/primitive_reprs_should_have_correct_length.rs:51:44 + | +LL | assert::is_transmutable::(); + | ^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u16` + | +note: required by a bound in `is_transmutable` + --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `V0i16: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/primitive_reprs_should_have_correct_length.rs:65:44 + | +LL | assert::is_transmutable::(); + | ^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `V0i16` + | +note: required by a bound in `is_transmutable` + --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `u32: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/primitive_reprs_should_have_correct_length.rs:67:44 + | +LL | assert::is_transmutable::(); + | ^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u32` + | +note: required by a bound in `is_transmutable` + --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `V0u16: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/primitive_reprs_should_have_correct_length.rs:73:44 + | +LL | assert::is_transmutable::(); + | ^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `V0u16` + | +note: required by a bound in `is_transmutable` + --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `u32: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/primitive_reprs_should_have_correct_length.rs:75:44 + | +LL | assert::is_transmutable::(); + | ^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u32` + | +note: required by a bound in `is_transmutable` + --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `V0i32: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/primitive_reprs_should_have_correct_length.rs:89:44 + | +LL | assert::is_transmutable::(); + | ^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `V0i32` + | +note: required by a bound in `is_transmutable` + --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `u64: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/primitive_reprs_should_have_correct_length.rs:91:44 + | +LL | assert::is_transmutable::(); + | ^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u64` + | +note: required by a bound in `is_transmutable` + --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `V0u32: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/primitive_reprs_should_have_correct_length.rs:97:44 + | +LL | assert::is_transmutable::(); + | ^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `V0u32` + | +note: required by a bound in `is_transmutable` + --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `u64: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/primitive_reprs_should_have_correct_length.rs:99:44 + | +LL | assert::is_transmutable::(); + | ^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u64` + | +note: required by a bound in `is_transmutable` + --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `V0i64: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/primitive_reprs_should_have_correct_length.rs:113:44 + | +LL | assert::is_transmutable::(); + | ^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `V0i64` + | +note: required by a bound in `is_transmutable` + --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `u128: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/primitive_reprs_should_have_correct_length.rs:115:44 + | +LL | assert::is_transmutable::(); + | ^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u128` + | +note: required by a bound in `is_transmutable` + --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `V0u64: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/primitive_reprs_should_have_correct_length.rs:121:44 + | +LL | assert::is_transmutable::(); + | ^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `V0u64` + | +note: required by a bound in `is_transmutable` + --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `u128: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/primitive_reprs_should_have_correct_length.rs:123:44 + | +LL | assert::is_transmutable::(); + | ^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u128` + | +note: required by a bound in `is_transmutable` + --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `V0isize: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/primitive_reprs_should_have_correct_length.rs:137:44 + | +LL | assert::is_transmutable::(); + | ^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `V0isize` + | +note: required by a bound in `is_transmutable` + --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `[usize; 2]: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/primitive_reprs_should_have_correct_length.rs:139:44 + | +LL | assert::is_transmutable::(); + | ^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `[usize; 2]` + | +note: required by a bound in `is_transmutable` + --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `V0usize: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/primitive_reprs_should_have_correct_length.rs:145:44 + | +LL | assert::is_transmutable::(); + | ^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `V0usize` + | +note: required by a bound in `is_transmutable` + --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `[usize; 2]: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/primitive_reprs_should_have_correct_length.rs:147:44 + | +LL | assert::is_transmutable::(); + | ^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `[usize; 2]` + | +note: required by a bound in `is_transmutable` + --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error: aborting due to 20 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/transmutability/enums/repr/should_require_well_defined_layout.rs b/src/test/ui/transmutability/enums/repr/should_require_well_defined_layout.rs new file mode 100644 index 0000000000000..24a88d6ac95cc --- /dev/null +++ b/src/test/ui/transmutability/enums/repr/should_require_well_defined_layout.rs @@ -0,0 +1,117 @@ +//! An enum must have a well-defined layout to participate in a transmutation. + +#![crate_type = "lib"] +#![feature(repr128)] +#![feature(transmutability)] +#![allow(dead_code, incomplete_features, non_camel_case_types)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + pub struct Context; + + pub fn is_maybe_transmutable() + where + Dst: BikeshedIntrinsicFrom + {} +} + +fn should_reject_repr_rust() { + fn void() { + enum repr_rust {} + assert::is_maybe_transmutable::(); //~ ERROR not satisfied + assert::is_maybe_transmutable::(); //~ ERROR not satisfied + } + + fn singleton() { + enum repr_rust { V } + assert::is_maybe_transmutable::(); //~ ERROR not satisfied + assert::is_maybe_transmutable::(); //~ ERROR not satisfied + } + + fn duplex() { + enum repr_rust { A, B } + assert::is_maybe_transmutable::(); //~ ERROR not satisfied + assert::is_maybe_transmutable::(); //~ ERROR not satisfied + } +} + +fn should_accept_primitive_reprs() +{ + fn should_accept_repr_i8() { + #[repr(i8)] enum repr_i8 { V } + assert::is_maybe_transmutable::(); + assert::is_maybe_transmutable::(); + } + + fn should_accept_repr_u8() { + #[repr(u8)] enum repr_u8 { V } + assert::is_maybe_transmutable::(); + assert::is_maybe_transmutable::(); + } + + fn should_accept_repr_i16() { + #[repr(i16)] enum repr_i16 { V } + assert::is_maybe_transmutable::(); + assert::is_maybe_transmutable::(); + } + + fn should_accept_repr_u16() { + #[repr(u16)] enum repr_u16 { V } + assert::is_maybe_transmutable::(); + assert::is_maybe_transmutable::(); + } + + fn should_accept_repr_i32() { + #[repr(i32)] enum repr_i32 { V } + assert::is_maybe_transmutable::(); + assert::is_maybe_transmutable::(); + } + + fn should_accept_repr_u32() { + #[repr(u32)] enum repr_u32 { V } + assert::is_maybe_transmutable::(); + assert::is_maybe_transmutable::(); + } + + fn should_accept_repr_i64() { + #[repr(i64)] enum repr_i64 { V } + assert::is_maybe_transmutable::(); + assert::is_maybe_transmutable::(); + } + + fn should_accept_repr_u64() { + #[repr(u64)] enum repr_u64 { V } + assert::is_maybe_transmutable::(); + assert::is_maybe_transmutable::(); + } + + fn should_accept_repr_i128() { + #[repr(i128)] enum repr_i128 { V } + assert::is_maybe_transmutable::(); + assert::is_maybe_transmutable::(); + } + + fn should_accept_repr_u128() { + #[repr(u128)] enum repr_u128 { V } + assert::is_maybe_transmutable::(); + assert::is_maybe_transmutable::(); + } + + fn should_accept_repr_isize() { + #[repr(isize)] enum repr_isize { V } + assert::is_maybe_transmutable::(); + assert::is_maybe_transmutable::(); + } + + fn should_accept_repr_usize() { + #[repr(usize)] enum repr_usize { V } + assert::is_maybe_transmutable::(); + assert::is_maybe_transmutable::(); + } +} + +fn should_accept_repr_C() { + #[repr(C)] enum repr_c { V } + assert::is_maybe_transmutable::(); + assert::is_maybe_transmutable::(); +} diff --git a/src/test/ui/transmutability/enums/repr/should_require_well_defined_layout.stderr b/src/test/ui/transmutability/enums/repr/should_require_well_defined_layout.stderr new file mode 100644 index 0000000000000..1bfbff68f06cb --- /dev/null +++ b/src/test/ui/transmutability/enums/repr/should_require_well_defined_layout.stderr @@ -0,0 +1,93 @@ +error[E0277]: the trait bound `(): BikeshedIntrinsicFrom` is not satisfied + --> $DIR/should_require_well_defined_layout.rs:21:52 + | +LL | assert::is_maybe_transmutable::(); + | ^^ the trait `BikeshedIntrinsicFrom` is not implemented for `()` + | +note: required by a bound in `is_maybe_transmutable` + --> $DIR/should_require_well_defined_layout.rs:14:14 + | +LL | pub fn is_maybe_transmutable() + | --------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` + +error[E0277]: the trait bound `void::repr_rust: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/should_require_well_defined_layout.rs:22:47 + | +LL | assert::is_maybe_transmutable::(); + | ^^^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `void::repr_rust` + | +note: required by a bound in `is_maybe_transmutable` + --> $DIR/should_require_well_defined_layout.rs:14:14 + | +LL | pub fn is_maybe_transmutable() + | --------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` + +error[E0277]: the trait bound `(): BikeshedIntrinsicFrom` is not satisfied + --> $DIR/should_require_well_defined_layout.rs:27:52 + | +LL | assert::is_maybe_transmutable::(); + | ^^ the trait `BikeshedIntrinsicFrom` is not implemented for `()` + | +note: required by a bound in `is_maybe_transmutable` + --> $DIR/should_require_well_defined_layout.rs:14:14 + | +LL | pub fn is_maybe_transmutable() + | --------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` + +error[E0277]: the trait bound `singleton::repr_rust: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/should_require_well_defined_layout.rs:28:47 + | +LL | assert::is_maybe_transmutable::(); + | ^^^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `singleton::repr_rust` + | +note: required by a bound in `is_maybe_transmutable` + --> $DIR/should_require_well_defined_layout.rs:14:14 + | +LL | pub fn is_maybe_transmutable() + | --------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` + +error[E0277]: the trait bound `(): BikeshedIntrinsicFrom` is not satisfied + --> $DIR/should_require_well_defined_layout.rs:33:52 + | +LL | assert::is_maybe_transmutable::(); + | ^^ the trait `BikeshedIntrinsicFrom` is not implemented for `()` + | +note: required by a bound in `is_maybe_transmutable` + --> $DIR/should_require_well_defined_layout.rs:14:14 + | +LL | pub fn is_maybe_transmutable() + | --------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` + +error[E0277]: the trait bound `duplex::repr_rust: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/should_require_well_defined_layout.rs:34:47 + | +LL | assert::is_maybe_transmutable::(); + | ^^^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `duplex::repr_rust` + | +note: required by a bound in `is_maybe_transmutable` + --> $DIR/should_require_well_defined_layout.rs:14:14 + | +LL | pub fn is_maybe_transmutable() + | --------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/transmutability/enums/should_order_correctly.rs b/src/test/ui/transmutability/enums/should_order_correctly.rs new file mode 100644 index 0000000000000..6558d2658ee45 --- /dev/null +++ b/src/test/ui/transmutability/enums/should_order_correctly.rs @@ -0,0 +1,32 @@ +// check-pass +//! The payloads of an enum variant should be ordered after its tag. + +#![crate_type = "lib"] +#![feature(arbitrary_enum_discriminant)] +#![feature(transmutability)] +#![allow(dead_code)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + pub struct Context; + + pub fn is_transmutable() + where + Dst: BikeshedIntrinsicFrom + {} +} + +#[repr(u8)] enum V0 { V = 0 } +#[repr(u8)] enum V1 { V = 1 } +#[repr(u8)] enum V2 { V = 2 } + +#[repr(u8)] enum E01 { V0(V1) = 0u8 } +#[repr(u8)] enum E012 { V0(V1, V2) = 0u8 } + +fn should_order_tag_and_fields_correctly() { + // An implementation that (incorrectly) arranges E01 as [0x01, 0x00] will, + // in principle, reject this transmutation. + assert::is_transmutable::(); + // Again, but with one more field. + assert::is_transmutable::(); +} diff --git a/src/test/ui/transmutability/enums/should_pad_variants.rs b/src/test/ui/transmutability/enums/should_pad_variants.rs new file mode 100644 index 0000000000000..87951586523de --- /dev/null +++ b/src/test/ui/transmutability/enums/should_pad_variants.rs @@ -0,0 +1,40 @@ +//! The variants of an enum must be padded with uninit bytes such that they have +//! the same length (in bytes). + +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + + pub fn is_transmutable() + where + Dst: BikeshedIntrinsicFrom + {} +} + +#[derive(Clone, Copy)] +#[repr(C)] struct Zst; + +#[derive(Clone, Copy)] +#[repr(u8)] enum V0 { V = 0 } + +#[derive(Clone, Copy)] +#[repr(u8)] enum V2 { V = 2 } + +#[repr(C, u8)] +enum Lopsided { + Smol(Zst), + Lorg(V0), +} + +#[repr(C)] struct Src(V0, Zst, V2); +#[repr(C)] struct Dst(Lopsided, V2); + +fn should_pad_variants() { + struct Context; + // If the implementation (incorrectly) fails to pad `Lopsided::Smol` with + // an uninitialized byte, this transmutation might be (wrongly) accepted: + assert::is_transmutable::(); //~ ERROR not satisfied +} diff --git a/src/test/ui/transmutability/enums/should_pad_variants.stderr b/src/test/ui/transmutability/enums/should_pad_variants.stderr new file mode 100644 index 0000000000000..b940ca077d4ad --- /dev/null +++ b/src/test/ui/transmutability/enums/should_pad_variants.stderr @@ -0,0 +1,18 @@ +error[E0277]: the trait bound `Dst: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/should_pad_variants.rs:39:36 + | +LL | assert::is_transmutable::(); + | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `Dst` + | +note: required by a bound in `is_transmutable` + --> $DIR/should_pad_variants.rs:13:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/transmutability/enums/should_respect_endianness.rs b/src/test/ui/transmutability/enums/should_respect_endianness.rs new file mode 100644 index 0000000000000..9bab44e1d914f --- /dev/null +++ b/src/test/ui/transmutability/enums/should_respect_endianness.rs @@ -0,0 +1,33 @@ +//! The target endianness should be a consideration in computing the layout of +//! an enum with a multi-byte tag. + +#![crate_type = "lib"] +#![feature(arbitrary_enum_discriminant)] +#![feature(transmutability)] +#![allow(dead_code)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + pub struct Context; + + pub fn is_transmutable() + where + Dst: BikeshedIntrinsicFrom + {} +} + +#[repr(u16)] enum Src { V = 0xCAFE } + +#[repr(u8)] enum OxCA { V = 0xCA } +#[repr(u8)] enum OxFE { V = 0xFE } + +#[cfg(target_endian = "big")] #[repr(C)] struct Expected(OxCA, OxFE); +#[cfg(target_endian = "big")] #[repr(C)] struct Unexpected(OxFE, OxCA); + +#[cfg(target_endian = "little")] #[repr(C)] struct Expected(OxFE, OxCA); +#[cfg(target_endian = "little")] #[repr(C)] struct Unexpected(OxCA, OxFE); + +fn should_respect_endianness() { + assert::is_transmutable::(); + assert::is_transmutable::(); //~ ERROR not satisfied +} diff --git a/src/test/ui/transmutability/enums/should_respect_endianness.stderr b/src/test/ui/transmutability/enums/should_respect_endianness.stderr new file mode 100644 index 0000000000000..3f3335d4a1b8f --- /dev/null +++ b/src/test/ui/transmutability/enums/should_respect_endianness.stderr @@ -0,0 +1,18 @@ +error[E0277]: the trait bound `Unexpected: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/should_respect_endianness.rs:32:36 + | +LL | assert::is_transmutable::(); + | ^^^^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `Unexpected` + | +note: required by a bound in `is_transmutable` + --> $DIR/should_respect_endianness.rs:15:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/transmutability/malformed-program-gracefulness/unknown_dst.rs b/src/test/ui/transmutability/malformed-program-gracefulness/unknown_dst.rs new file mode 100644 index 0000000000000..e13462d390b03 --- /dev/null +++ b/src/test/ui/transmutability/malformed-program-gracefulness/unknown_dst.rs @@ -0,0 +1,21 @@ +// An unknown destination type should be gracefully handled. + +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code, incomplete_features, non_camel_case_types)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + pub struct Context; + + pub fn is_transmutable() + where + Dst: BikeshedIntrinsicFrom + {} +} + +fn should_gracefully_handle_unknown_dst() { + struct Context; + struct Src; + assert::is_transmutable::(); //~ cannot find type +} diff --git a/src/test/ui/transmutability/malformed-program-gracefulness/unknown_dst.stderr b/src/test/ui/transmutability/malformed-program-gracefulness/unknown_dst.stderr new file mode 100644 index 0000000000000..85087282d3a6e --- /dev/null +++ b/src/test/ui/transmutability/malformed-program-gracefulness/unknown_dst.stderr @@ -0,0 +1,12 @@ +error[E0412]: cannot find type `Dst` in this scope + --> $DIR/unknown_dst.rs:20:36 + | +LL | fn should_gracefully_handle_unknown_dst() { + | - help: you might be missing a type parameter: `` +... +LL | assert::is_transmutable::(); + | ^^^ not found in this scope + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0412`. diff --git a/src/test/ui/transmutability/malformed-program-gracefulness/unknown_src.rs b/src/test/ui/transmutability/malformed-program-gracefulness/unknown_src.rs new file mode 100644 index 0000000000000..dc51e2a8f4d2b --- /dev/null +++ b/src/test/ui/transmutability/malformed-program-gracefulness/unknown_src.rs @@ -0,0 +1,21 @@ +// An unknown source type should be gracefully handled. + +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code, incomplete_features, non_camel_case_types)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + pub struct Context; + + pub fn is_transmutable() + where + Dst: BikeshedIntrinsicFrom + {} +} + +fn should_gracefully_handle_unknown_src() { + struct Context; + #[repr(C)] struct Dst; + assert::is_transmutable::(); //~ cannot find type +} diff --git a/src/test/ui/transmutability/malformed-program-gracefulness/unknown_src.stderr b/src/test/ui/transmutability/malformed-program-gracefulness/unknown_src.stderr new file mode 100644 index 0000000000000..9bedbe87c3f7f --- /dev/null +++ b/src/test/ui/transmutability/malformed-program-gracefulness/unknown_src.stderr @@ -0,0 +1,12 @@ +error[E0412]: cannot find type `Src` in this scope + --> $DIR/unknown_src.rs:20:31 + | +LL | fn should_gracefully_handle_unknown_src() { + | - help: you might be missing a type parameter: `` +... +LL | assert::is_transmutable::(); + | ^^^ not found in this scope + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0412`. diff --git a/src/test/ui/transmutability/malformed-program-gracefulness/unknown_src_field.rs b/src/test/ui/transmutability/malformed-program-gracefulness/unknown_src_field.rs new file mode 100644 index 0000000000000..86fc8bd6b2856 --- /dev/null +++ b/src/test/ui/transmutability/malformed-program-gracefulness/unknown_src_field.rs @@ -0,0 +1,22 @@ +// An unknown destination type should be gracefully handled. + +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code, incomplete_features, non_camel_case_types)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + pub struct Context; + + pub fn is_transmutable() + where + Dst: BikeshedIntrinsicFrom + {} +} + +fn should_gracefully_handle_unknown_dst_field() { + struct Context; + #[repr(C)] struct Src; + #[repr(C)] struct Dst(Missing); //~ cannot find type + assert::is_transmutable::(); +} diff --git a/src/test/ui/transmutability/malformed-program-gracefulness/unknown_src_field.stderr b/src/test/ui/transmutability/malformed-program-gracefulness/unknown_src_field.stderr new file mode 100644 index 0000000000000..475e6f429f3c9 --- /dev/null +++ b/src/test/ui/transmutability/malformed-program-gracefulness/unknown_src_field.stderr @@ -0,0 +1,9 @@ +error[E0412]: cannot find type `Missing` in this scope + --> $DIR/unknown_src_field.rs:20:27 + | +LL | #[repr(C)] struct Dst(Missing); + | ^^^^^^^ not found in this scope + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0412`. diff --git a/src/test/ui/transmutability/primitives/bool.rs b/src/test/ui/transmutability/primitives/bool.rs new file mode 100644 index 0000000000000..13cecd1d8b7ea --- /dev/null +++ b/src/test/ui/transmutability/primitives/bool.rs @@ -0,0 +1,25 @@ +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code)] +#![allow(incomplete_features)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + pub struct Context; + + pub fn is_transmutable() + where + Dst: BikeshedIntrinsicFrom + {} + + pub fn is_maybe_transmutable() + where + Dst: BikeshedIntrinsicFrom + {} +} + +fn contrast_with_u8() { + assert::is_transmutable::(); //~ ERROR not satisfied + assert::is_maybe_transmutable::(); + assert::is_transmutable::(); +} diff --git a/src/test/ui/transmutability/primitives/bool.stderr b/src/test/ui/transmutability/primitives/bool.stderr new file mode 100644 index 0000000000000..f05bb433ec844 --- /dev/null +++ b/src/test/ui/transmutability/primitives/bool.stderr @@ -0,0 +1,18 @@ +error[E0277]: the trait bound `bool: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/bool.rs:22:35 + | +LL | assert::is_transmutable::(); + | ^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `bool` + | +note: required by a bound in `is_transmutable` + --> $DIR/bool.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/transmutability/primitives/numbers.rs b/src/test/ui/transmutability/primitives/numbers.rs new file mode 100644 index 0000000000000..3dbdfab9686a8 --- /dev/null +++ b/src/test/ui/transmutability/primitives/numbers.rs @@ -0,0 +1,128 @@ +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code)] +#![allow(incomplete_features)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + struct Context; + + pub fn is_transmutable() + where + Dst: BikeshedIntrinsicFrom + {} +} + +fn should_accept_identity() { + assert::is_transmutable::< i8, i8>(); + assert::is_transmutable::< u8, u8>(); + assert::is_transmutable::< i16, i16>(); + assert::is_transmutable::< u16, u16>(); + assert::is_transmutable::< i32, i32>(); + assert::is_transmutable::< f32, f32>(); + assert::is_transmutable::< u32, u32>(); + assert::is_transmutable::< i64, i64>(); + assert::is_transmutable::< f64, f64>(); + assert::is_transmutable::< u64, u64>(); + assert::is_transmutable::< i128, i128>(); + assert::is_transmutable::< u128, u128>(); + assert::is_transmutable::(); + assert::is_transmutable::(); +} + +fn should_be_bitransmutable() { + assert::is_transmutable::< i8, u8>(); + assert::is_transmutable::< u8, i8>(); + + assert::is_transmutable::< i16, u16>(); + assert::is_transmutable::< u16, i16>(); + + assert::is_transmutable::< i32, f32>(); + assert::is_transmutable::< i32, u32>(); + assert::is_transmutable::< f32, i32>(); + assert::is_transmutable::< f32, u32>(); + assert::is_transmutable::< u32, i32>(); + assert::is_transmutable::< u32, f32>(); + + assert::is_transmutable::< u64, i64>(); + assert::is_transmutable::< u64, f64>(); + assert::is_transmutable::< i64, u64>(); + assert::is_transmutable::< i64, f64>(); + assert::is_transmutable::< f64, u64>(); + assert::is_transmutable::< f64, i64>(); + + assert::is_transmutable::< u128, i128>(); + assert::is_transmutable::< i128, u128>(); + + assert::is_transmutable::(); + assert::is_transmutable::(); +} + +fn should_reject_extension() { + assert::is_transmutable::< i8, i16>(); //~ ERROR not satisfied + assert::is_transmutable::< i8, u16>(); //~ ERROR not satisfied + assert::is_transmutable::< i8, i32>(); //~ ERROR not satisfied + assert::is_transmutable::< i8, f32>(); //~ ERROR not satisfied + assert::is_transmutable::< i8, u32>(); //~ ERROR not satisfied + assert::is_transmutable::< i8, u64>(); //~ ERROR not satisfied + assert::is_transmutable::< i8, i64>(); //~ ERROR not satisfied + assert::is_transmutable::< i8, f64>(); //~ ERROR not satisfied + assert::is_transmutable::< i8, u128>(); //~ ERROR not satisfied + assert::is_transmutable::< i8, i128>(); //~ ERROR not satisfied + + assert::is_transmutable::< u8, i16>(); //~ ERROR not satisfied + assert::is_transmutable::< u8, u16>(); //~ ERROR not satisfied + assert::is_transmutable::< u8, i32>(); //~ ERROR not satisfied + assert::is_transmutable::< u8, f32>(); //~ ERROR not satisfied + assert::is_transmutable::< u8, u32>(); //~ ERROR not satisfied + assert::is_transmutable::< u8, u64>(); //~ ERROR not satisfied + assert::is_transmutable::< u8, i64>(); //~ ERROR not satisfied + assert::is_transmutable::< u8, f64>(); //~ ERROR not satisfied + assert::is_transmutable::< u8, u128>(); //~ ERROR not satisfied + assert::is_transmutable::< u8, i128>(); //~ ERROR not satisfied + + assert::is_transmutable::< i16, i32>(); //~ ERROR not satisfied + assert::is_transmutable::< i16, f32>(); //~ ERROR not satisfied + assert::is_transmutable::< i16, u32>(); //~ ERROR not satisfied + assert::is_transmutable::< i16, u64>(); //~ ERROR not satisfied + assert::is_transmutable::< i16, i64>(); //~ ERROR not satisfied + assert::is_transmutable::< i16, f64>(); //~ ERROR not satisfied + assert::is_transmutable::< i16, u128>(); //~ ERROR not satisfied + assert::is_transmutable::< i16, i128>(); //~ ERROR not satisfied + + assert::is_transmutable::< u16, i32>(); //~ ERROR not satisfied + assert::is_transmutable::< u16, f32>(); //~ ERROR not satisfied + assert::is_transmutable::< u16, u32>(); //~ ERROR not satisfied + assert::is_transmutable::< u16, u64>(); //~ ERROR not satisfied + assert::is_transmutable::< u16, i64>(); //~ ERROR not satisfied + assert::is_transmutable::< u16, f64>(); //~ ERROR not satisfied + assert::is_transmutable::< u16, u128>(); //~ ERROR not satisfied + assert::is_transmutable::< u16, i128>(); //~ ERROR not satisfied + + assert::is_transmutable::< i32, u64>(); //~ ERROR not satisfied + assert::is_transmutable::< i32, i64>(); //~ ERROR not satisfied + assert::is_transmutable::< i32, f64>(); //~ ERROR not satisfied + assert::is_transmutable::< i32, u128>(); //~ ERROR not satisfied + assert::is_transmutable::< i32, i128>(); //~ ERROR not satisfied + + assert::is_transmutable::< f32, u64>(); //~ ERROR not satisfied + assert::is_transmutable::< f32, i64>(); //~ ERROR not satisfied + assert::is_transmutable::< f32, f64>(); //~ ERROR not satisfied + assert::is_transmutable::< f32, u128>(); //~ ERROR not satisfied + assert::is_transmutable::< f32, i128>(); //~ ERROR not satisfied + + assert::is_transmutable::< u32, u64>(); //~ ERROR not satisfied + assert::is_transmutable::< u32, i64>(); //~ ERROR not satisfied + assert::is_transmutable::< u32, f64>(); //~ ERROR not satisfied + assert::is_transmutable::< u32, u128>(); //~ ERROR not satisfied + assert::is_transmutable::< u32, i128>(); //~ ERROR not satisfied + + assert::is_transmutable::< u64, u128>(); //~ ERROR not satisfied + assert::is_transmutable::< u64, i128>(); //~ ERROR not satisfied + + assert::is_transmutable::< i64, u128>(); //~ ERROR not satisfied + assert::is_transmutable::< i64, i128>(); //~ ERROR not satisfied + + assert::is_transmutable::< f64, u128>(); //~ ERROR not satisfied + assert::is_transmutable::< f64, i128>(); //~ ERROR not satisfied +} diff --git a/src/test/ui/transmutability/primitives/numbers.stderr b/src/test/ui/transmutability/primitives/numbers.stderr new file mode 100644 index 0000000000000..6bd3379dfd1a4 --- /dev/null +++ b/src/test/ui/transmutability/primitives/numbers.stderr @@ -0,0 +1,858 @@ +error[E0277]: the trait bound `i16: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:62:40 + | +LL | assert::is_transmutable::< i8, i16>(); + | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i16` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `u16: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:63:40 + | +LL | assert::is_transmutable::< i8, u16>(); + | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u16` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `i32: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:64:40 + | +LL | assert::is_transmutable::< i8, i32>(); + | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i32` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `f32: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:65:40 + | +LL | assert::is_transmutable::< i8, f32>(); + | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `f32` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `u32: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:66:40 + | +LL | assert::is_transmutable::< i8, u32>(); + | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u32` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `u64: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:67:40 + | +LL | assert::is_transmutable::< i8, u64>(); + | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u64` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `i64: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:68:40 + | +LL | assert::is_transmutable::< i8, i64>(); + | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i64` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `f64: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:69:40 + | +LL | assert::is_transmutable::< i8, f64>(); + | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `f64` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `u128: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:70:39 + | +LL | assert::is_transmutable::< i8, u128>(); + | ^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u128` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `i128: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:71:39 + | +LL | assert::is_transmutable::< i8, i128>(); + | ^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i128` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `i16: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:73:40 + | +LL | assert::is_transmutable::< u8, i16>(); + | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i16` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `u16: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:74:40 + | +LL | assert::is_transmutable::< u8, u16>(); + | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u16` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `i32: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:75:40 + | +LL | assert::is_transmutable::< u8, i32>(); + | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i32` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `f32: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:76:40 + | +LL | assert::is_transmutable::< u8, f32>(); + | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `f32` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `u32: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:77:40 + | +LL | assert::is_transmutable::< u8, u32>(); + | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u32` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `u64: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:78:40 + | +LL | assert::is_transmutable::< u8, u64>(); + | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u64` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `i64: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:79:40 + | +LL | assert::is_transmutable::< u8, i64>(); + | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i64` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `f64: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:80:40 + | +LL | assert::is_transmutable::< u8, f64>(); + | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `f64` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `u128: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:81:39 + | +LL | assert::is_transmutable::< u8, u128>(); + | ^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u128` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `i128: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:82:39 + | +LL | assert::is_transmutable::< u8, i128>(); + | ^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i128` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `i32: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:84:40 + | +LL | assert::is_transmutable::< i16, i32>(); + | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i32` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `f32: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:85:40 + | +LL | assert::is_transmutable::< i16, f32>(); + | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `f32` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `u32: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:86:40 + | +LL | assert::is_transmutable::< i16, u32>(); + | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u32` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `u64: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:87:40 + | +LL | assert::is_transmutable::< i16, u64>(); + | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u64` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `i64: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:88:40 + | +LL | assert::is_transmutable::< i16, i64>(); + | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i64` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `f64: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:89:40 + | +LL | assert::is_transmutable::< i16, f64>(); + | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `f64` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `u128: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:90:39 + | +LL | assert::is_transmutable::< i16, u128>(); + | ^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u128` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `i128: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:91:39 + | +LL | assert::is_transmutable::< i16, i128>(); + | ^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i128` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `i32: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:93:40 + | +LL | assert::is_transmutable::< u16, i32>(); + | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i32` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `f32: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:94:40 + | +LL | assert::is_transmutable::< u16, f32>(); + | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `f32` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `u32: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:95:40 + | +LL | assert::is_transmutable::< u16, u32>(); + | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u32` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `u64: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:96:40 + | +LL | assert::is_transmutable::< u16, u64>(); + | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u64` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `i64: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:97:40 + | +LL | assert::is_transmutable::< u16, i64>(); + | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i64` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `f64: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:98:40 + | +LL | assert::is_transmutable::< u16, f64>(); + | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `f64` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `u128: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:99:39 + | +LL | assert::is_transmutable::< u16, u128>(); + | ^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u128` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `i128: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:100:39 + | +LL | assert::is_transmutable::< u16, i128>(); + | ^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i128` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `u64: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:102:40 + | +LL | assert::is_transmutable::< i32, u64>(); + | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u64` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `i64: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:103:40 + | +LL | assert::is_transmutable::< i32, i64>(); + | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i64` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `f64: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:104:40 + | +LL | assert::is_transmutable::< i32, f64>(); + | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `f64` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `u128: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:105:39 + | +LL | assert::is_transmutable::< i32, u128>(); + | ^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u128` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `i128: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:106:39 + | +LL | assert::is_transmutable::< i32, i128>(); + | ^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i128` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `u64: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:108:40 + | +LL | assert::is_transmutable::< f32, u64>(); + | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u64` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `i64: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:109:40 + | +LL | assert::is_transmutable::< f32, i64>(); + | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i64` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `f64: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:110:40 + | +LL | assert::is_transmutable::< f32, f64>(); + | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `f64` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `u128: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:111:39 + | +LL | assert::is_transmutable::< f32, u128>(); + | ^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u128` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `i128: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:112:39 + | +LL | assert::is_transmutable::< f32, i128>(); + | ^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i128` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `u64: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:114:40 + | +LL | assert::is_transmutable::< u32, u64>(); + | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u64` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `i64: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:115:40 + | +LL | assert::is_transmutable::< u32, i64>(); + | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i64` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `f64: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:116:40 + | +LL | assert::is_transmutable::< u32, f64>(); + | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `f64` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `u128: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:117:39 + | +LL | assert::is_transmutable::< u32, u128>(); + | ^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u128` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `i128: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:118:39 + | +LL | assert::is_transmutable::< u32, i128>(); + | ^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i128` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `u128: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:120:39 + | +LL | assert::is_transmutable::< u64, u128>(); + | ^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u128` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `i128: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:121:39 + | +LL | assert::is_transmutable::< u64, i128>(); + | ^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i128` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `u128: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:123:39 + | +LL | assert::is_transmutable::< i64, u128>(); + | ^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u128` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `i128: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:124:39 + | +LL | assert::is_transmutable::< i64, i128>(); + | ^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i128` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `u128: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:126:39 + | +LL | assert::is_transmutable::< f64, u128>(); + | ^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u128` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `i128: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:127:39 + | +LL | assert::is_transmutable::< f64, i128>(); + | ^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i128` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error: aborting due to 57 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/transmutability/primitives/unit.rs b/src/test/ui/transmutability/primitives/unit.rs new file mode 100644 index 0000000000000..a9c618188bf41 --- /dev/null +++ b/src/test/ui/transmutability/primitives/unit.rs @@ -0,0 +1,24 @@ +//! The unit type, `()`, should be one byte. + +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + + pub fn is_transmutable() + where + Dst: BikeshedIntrinsicFrom + {} +} + +#[repr(C)] +struct Zst; + +fn should_have_correct_size() { + struct Context; + assert::is_transmutable::<(), Zst, Context>(); + assert::is_transmutable::(); + assert::is_transmutable::<(), u8, Context>(); //~ ERROR not satisfied +} diff --git a/src/test/ui/transmutability/primitives/unit.stderr b/src/test/ui/transmutability/primitives/unit.stderr new file mode 100644 index 0000000000000..f602612feea93 --- /dev/null +++ b/src/test/ui/transmutability/primitives/unit.stderr @@ -0,0 +1,18 @@ +error[E0277]: the trait bound `u8: BikeshedIntrinsicFrom<(), should_have_correct_size::Context, true, true, true, true>` is not satisfied + --> $DIR/unit.rs:23:35 + | +LL | assert::is_transmutable::<(), u8, Context>(); + | ^^ the trait `BikeshedIntrinsicFrom<(), should_have_correct_size::Context, true, true, true, true>` is not implemented for `u8` + | +note: required by a bound in `is_transmutable` + --> $DIR/unit.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/transmutability/references.rs b/src/test/ui/transmutability/references.rs new file mode 100644 index 0000000000000..c7d24aaf1caa8 --- /dev/null +++ b/src/test/ui/transmutability/references.rs @@ -0,0 +1,20 @@ +//! Transmutations involving references are not yet supported. + +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code, incomplete_features, non_camel_case_types)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + pub struct Context; + + pub fn is_maybe_transmutable() + where + Dst: BikeshedIntrinsicFrom + {} +} + +fn not_yet_implemented() { + #[repr(C)] struct Unit; + assert::is_maybe_transmutable::<&'static Unit, &'static Unit>(); //~ ERROR not satisfied +} diff --git a/src/test/ui/transmutability/references.stderr b/src/test/ui/transmutability/references.stderr new file mode 100644 index 0000000000000..7199e169e2977 --- /dev/null +++ b/src/test/ui/transmutability/references.stderr @@ -0,0 +1,18 @@ +error[E0277]: the trait bound `&'static Unit: BikeshedIntrinsicFrom<&'static Unit, assert::Context, true, true, true, true>` is not satisfied + --> $DIR/references.rs:19:52 + | +LL | assert::is_maybe_transmutable::<&'static Unit, &'static Unit>(); + | ^^^^^^^^^^^^^ the trait `BikeshedIntrinsicFrom<&'static Unit, assert::Context, true, true, true, true>` is not implemented for `&'static Unit` + | +note: required by a bound in `is_maybe_transmutable` + --> $DIR/references.rs:13:14 + | +LL | pub fn is_maybe_transmutable() + | --------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/transmutability/structs/repr/should_handle_align.rs b/src/test/ui/transmutability/structs/repr/should_handle_align.rs new file mode 100644 index 0000000000000..71720165ab063 --- /dev/null +++ b/src/test/ui/transmutability/structs/repr/should_handle_align.rs @@ -0,0 +1,36 @@ +// check-pass +//! The presence of an `align(X)` annotation must be accounted for. + +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code, incomplete_features, non_camel_case_types)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + pub struct Context; + + pub fn is_maybe_transmutable() + where + Dst: BikeshedIntrinsicFrom + {} +} + +fn should_pad_explicitly_aligned_field() { + #[derive(Clone, Copy)] #[repr(u8)] enum V0u8 { V = 0 } + + #[repr(C)] + pub union Uninit { + a: (), + b: V0u8, + } + + #[repr(C, align(2))] struct align_2(V0u8); + + #[repr(C)] struct ImplicitlyPadded(align_2, V0u8); + #[repr(C)] struct ExplicitlyPadded(V0u8, Uninit, V0u8); + + // An implementation that (incorrectly) does not place a padding byte after + // `align_2` will, incorrectly, reject the following transmutations. + assert::is_maybe_transmutable::(); + assert::is_maybe_transmutable::(); +} diff --git a/src/test/ui/transmutability/structs/repr/should_handle_packed.rs b/src/test/ui/transmutability/structs/repr/should_handle_packed.rs new file mode 100644 index 0000000000000..ae8acf5041897 --- /dev/null +++ b/src/test/ui/transmutability/structs/repr/should_handle_packed.rs @@ -0,0 +1,35 @@ +// check-pass +//! The presence of an `align(X)` annotation must be accounted for. + +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code, incomplete_features, non_camel_case_types)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + pub struct Context; + + pub fn is_maybe_transmutable() + where + Dst: BikeshedIntrinsicFrom + {} +} + +fn should_pad_explicitly_packed_field() { + #[derive(Clone, Copy)] #[repr(u8)] enum V0u8 { V = 0 } + #[derive(Clone, Copy)] #[repr(u32)] enum V0u32 { V = 0 } + + #[repr(C)] + pub union Uninit { + a: (), + b: V0u8, + } + + #[repr(C, packed(2))] struct ImplicitlyPadded(V0u8, V0u32); + #[repr(C)] struct ExplicitlyPadded(V0u8, Uninit, V0u8, V0u8, V0u8, V0u8); + + // An implementation that (incorrectly) does not place a padding byte after + // `align_2` will, incorrectly, reject the following transmutations. + assert::is_maybe_transmutable::(); + assert::is_maybe_transmutable::(); +} diff --git a/src/test/ui/transmutability/structs/repr/should_require_well_defined_layout.rs b/src/test/ui/transmutability/structs/repr/should_require_well_defined_layout.rs new file mode 100644 index 0000000000000..63419aceb6ce9 --- /dev/null +++ b/src/test/ui/transmutability/structs/repr/should_require_well_defined_layout.rs @@ -0,0 +1,76 @@ +//! A struct must have a well-defined layout to participate in a transmutation. + +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code, incomplete_features, non_camel_case_types)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + pub struct Context; + + pub fn is_maybe_transmutable() + where + Dst: BikeshedIntrinsicFrom + {} +} + +fn should_reject_repr_rust() +{ + fn unit() { + struct repr_rust; + assert::is_maybe_transmutable::(); //~ ERROR not satisfied + assert::is_maybe_transmutable::(); //~ ERROR not satisfied + } + + fn tuple() { + struct repr_rust(); + assert::is_maybe_transmutable::(); //~ ERROR not satisfied + assert::is_maybe_transmutable::(); //~ ERROR not satisfied + } + + fn braces() { + struct repr_rust{} + assert::is_maybe_transmutable::(); //~ ERROR not satisfied + assert::is_maybe_transmutable::(); //~ ERROR not satisfied + } + + fn aligned() { + #[repr(align(1))] struct repr_rust{} + assert::is_maybe_transmutable::(); //~ ERROR not satisfied + assert::is_maybe_transmutable::(); //~ ERROR not satisfied + } + + fn packed() { + #[repr(packed)] struct repr_rust{} + assert::is_maybe_transmutable::(); //~ ERROR not satisfied + assert::is_maybe_transmutable::(); //~ ERROR not satisfied + } + + fn nested() { + struct repr_rust; + #[repr(C)] struct repr_c(repr_rust); + assert::is_maybe_transmutable::(); //~ ERROR not satisfied + assert::is_maybe_transmutable::(); //~ ERROR not satisfied + } +} + +fn should_accept_repr_C() +{ + fn unit() { + #[repr(C)] struct repr_c; + assert::is_maybe_transmutable::(); + assert::is_maybe_transmutable::(); + } + + fn tuple() { + #[repr(C)] struct repr_c(); + assert::is_maybe_transmutable::(); + assert::is_maybe_transmutable::(); + } + + fn braces() { + #[repr(C)] struct repr_c{} + assert::is_maybe_transmutable::(); + assert::is_maybe_transmutable::(); + } +} diff --git a/src/test/ui/transmutability/structs/repr/should_require_well_defined_layout.stderr b/src/test/ui/transmutability/structs/repr/should_require_well_defined_layout.stderr new file mode 100644 index 0000000000000..ab582dd668807 --- /dev/null +++ b/src/test/ui/transmutability/structs/repr/should_require_well_defined_layout.stderr @@ -0,0 +1,183 @@ +error[E0277]: the trait bound `(): BikeshedIntrinsicFrom` is not satisfied + --> $DIR/should_require_well_defined_layout.rs:21:52 + | +LL | assert::is_maybe_transmutable::(); + | ^^ the trait `BikeshedIntrinsicFrom` is not implemented for `()` + | +note: required by a bound in `is_maybe_transmutable` + --> $DIR/should_require_well_defined_layout.rs:13:14 + | +LL | pub fn is_maybe_transmutable() + | --------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` + +error[E0277]: the trait bound `should_reject_repr_rust::unit::repr_rust: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/should_require_well_defined_layout.rs:22:47 + | +LL | assert::is_maybe_transmutable::(); + | ^^^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `should_reject_repr_rust::unit::repr_rust` + | +note: required by a bound in `is_maybe_transmutable` + --> $DIR/should_require_well_defined_layout.rs:13:14 + | +LL | pub fn is_maybe_transmutable() + | --------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` + +error[E0277]: the trait bound `(): BikeshedIntrinsicFrom` is not satisfied + --> $DIR/should_require_well_defined_layout.rs:27:52 + | +LL | assert::is_maybe_transmutable::(); + | ^^ the trait `BikeshedIntrinsicFrom` is not implemented for `()` + | +note: required by a bound in `is_maybe_transmutable` + --> $DIR/should_require_well_defined_layout.rs:13:14 + | +LL | pub fn is_maybe_transmutable() + | --------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` + +error[E0277]: the trait bound `should_reject_repr_rust::tuple::repr_rust: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/should_require_well_defined_layout.rs:28:47 + | +LL | assert::is_maybe_transmutable::(); + | ^^^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `should_reject_repr_rust::tuple::repr_rust` + | +note: required by a bound in `is_maybe_transmutable` + --> $DIR/should_require_well_defined_layout.rs:13:14 + | +LL | pub fn is_maybe_transmutable() + | --------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` + +error[E0277]: the trait bound `(): BikeshedIntrinsicFrom` is not satisfied + --> $DIR/should_require_well_defined_layout.rs:33:52 + | +LL | assert::is_maybe_transmutable::(); + | ^^ the trait `BikeshedIntrinsicFrom` is not implemented for `()` + | +note: required by a bound in `is_maybe_transmutable` + --> $DIR/should_require_well_defined_layout.rs:13:14 + | +LL | pub fn is_maybe_transmutable() + | --------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` + +error[E0277]: the trait bound `should_reject_repr_rust::braces::repr_rust: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/should_require_well_defined_layout.rs:34:47 + | +LL | assert::is_maybe_transmutable::(); + | ^^^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `should_reject_repr_rust::braces::repr_rust` + | +note: required by a bound in `is_maybe_transmutable` + --> $DIR/should_require_well_defined_layout.rs:13:14 + | +LL | pub fn is_maybe_transmutable() + | --------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` + +error[E0277]: the trait bound `(): BikeshedIntrinsicFrom` is not satisfied + --> $DIR/should_require_well_defined_layout.rs:39:52 + | +LL | assert::is_maybe_transmutable::(); + | ^^ the trait `BikeshedIntrinsicFrom` is not implemented for `()` + | +note: required by a bound in `is_maybe_transmutable` + --> $DIR/should_require_well_defined_layout.rs:13:14 + | +LL | pub fn is_maybe_transmutable() + | --------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` + +error[E0277]: the trait bound `aligned::repr_rust: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/should_require_well_defined_layout.rs:40:47 + | +LL | assert::is_maybe_transmutable::(); + | ^^^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `aligned::repr_rust` + | +note: required by a bound in `is_maybe_transmutable` + --> $DIR/should_require_well_defined_layout.rs:13:14 + | +LL | pub fn is_maybe_transmutable() + | --------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` + +error[E0277]: the trait bound `(): BikeshedIntrinsicFrom` is not satisfied + --> $DIR/should_require_well_defined_layout.rs:45:52 + | +LL | assert::is_maybe_transmutable::(); + | ^^ the trait `BikeshedIntrinsicFrom` is not implemented for `()` + | +note: required by a bound in `is_maybe_transmutable` + --> $DIR/should_require_well_defined_layout.rs:13:14 + | +LL | pub fn is_maybe_transmutable() + | --------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` + +error[E0277]: the trait bound `packed::repr_rust: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/should_require_well_defined_layout.rs:46:47 + | +LL | assert::is_maybe_transmutable::(); + | ^^^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `packed::repr_rust` + | +note: required by a bound in `is_maybe_transmutable` + --> $DIR/should_require_well_defined_layout.rs:13:14 + | +LL | pub fn is_maybe_transmutable() + | --------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` + +error[E0277]: the trait bound `(): BikeshedIntrinsicFrom` is not satisfied + --> $DIR/should_require_well_defined_layout.rs:52:49 + | +LL | assert::is_maybe_transmutable::(); + | ^^ the trait `BikeshedIntrinsicFrom` is not implemented for `()` + | +note: required by a bound in `is_maybe_transmutable` + --> $DIR/should_require_well_defined_layout.rs:13:14 + | +LL | pub fn is_maybe_transmutable() + | --------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` + +error[E0277]: the trait bound `nested::repr_c: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/should_require_well_defined_layout.rs:53:47 + | +LL | assert::is_maybe_transmutable::(); + | ^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `nested::repr_c` + | +note: required by a bound in `is_maybe_transmutable` + --> $DIR/should_require_well_defined_layout.rs:13:14 + | +LL | pub fn is_maybe_transmutable() + | --------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` + +error: aborting due to 12 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/transmutability/structs/should_order_fields_correctly.rs b/src/test/ui/transmutability/structs/should_order_fields_correctly.rs new file mode 100644 index 0000000000000..db49b914fe065 --- /dev/null +++ b/src/test/ui/transmutability/structs/should_order_fields_correctly.rs @@ -0,0 +1,31 @@ +// check-pass +//! The fields of a struct should be laid out in lexical order. + +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + pub struct Context; + + pub fn is_transmutable() + where + Dst: BikeshedIntrinsicFrom + {} +} + +#[repr(u8)] enum V0 { V = 0 } +#[repr(u8)] enum V1 { V = 1 } +#[repr(u8)] enum V2 { V = 2 } + +#[repr(C)] struct S01(V0, V1); +#[repr(C)] struct S012(V0, V1, V2); + +fn should_order_tag_and_fields_correctly() { + // An implementation that (incorrectly) arranges S01 as [0x01, 0x00] will, + // in principle, reject this transmutation. + assert::is_transmutable::(); + // Again, but with one more field. + assert::is_transmutable::(); +} diff --git a/src/test/ui/transmutability/unions/boolish.rs b/src/test/ui/transmutability/unions/boolish.rs new file mode 100644 index 0000000000000..975118b99b7ba --- /dev/null +++ b/src/test/ui/transmutability/unions/boolish.rs @@ -0,0 +1,31 @@ +// check-pass + +#![crate_type = "lib"] +#![feature(transmutability)] +#![feature(marker_trait_attr)] +#![allow(dead_code)] +#![allow(incomplete_features)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + pub struct Context; + + pub fn is_transmutable() + where + Dst: BikeshedIntrinsicFrom + {} +} + +fn should_match_bool() { + #[derive(Copy, Clone)] #[repr(u8)] pub enum False { V = 0 } + #[derive(Copy, Clone)] #[repr(u8)] pub enum True { V = 1 } + + #[repr(C)] + pub union Bool { + pub f: False, + pub t: True, + } + + assert::is_transmutable::(); + assert::is_transmutable::(); +} diff --git a/src/test/ui/transmutability/unions/repr/should_handle_align.rs b/src/test/ui/transmutability/unions/repr/should_handle_align.rs new file mode 100644 index 0000000000000..e215799a23240 --- /dev/null +++ b/src/test/ui/transmutability/unions/repr/should_handle_align.rs @@ -0,0 +1,40 @@ +// check-pass +//! The presence of an `align(X)` annotation must be accounted for. + +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code, incomplete_features, non_camel_case_types)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + pub struct Context; + + pub fn is_maybe_transmutable() + where + Dst: BikeshedIntrinsicFrom + {} +} + +fn should_pad_explicitly_aligned_field() { + #[derive(Clone, Copy)] #[repr(u8)] enum V0u8 { V = 0 } + #[derive(Clone, Copy)] #[repr(u8)] enum V1u8 { V = 1 } + + #[repr(C)] + pub union Uninit { + a: (), + b: V1u8, + } + + #[repr(C, align(2))] + pub union align_2 { + a: V0u8, + } + + #[repr(C)] struct ImplicitlyPadded(align_2, V0u8); + #[repr(C)] struct ExplicitlyPadded(V0u8, Uninit, V0u8); + + // An implementation that (incorrectly) does not place a padding byte after + // `align_2` will, incorrectly, reject the following transmutations. + assert::is_maybe_transmutable::(); + assert::is_maybe_transmutable::(); +} diff --git a/src/test/ui/transmutability/unions/repr/should_handle_packed.rs b/src/test/ui/transmutability/unions/repr/should_handle_packed.rs new file mode 100644 index 0000000000000..34a53c7a80c42 --- /dev/null +++ b/src/test/ui/transmutability/unions/repr/should_handle_packed.rs @@ -0,0 +1,41 @@ +// check-pass +//! The presence of an `align(X)` annotation must be accounted for. + +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code, incomplete_features, non_camel_case_types)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + pub struct Context; + + pub fn is_maybe_transmutable() + where + Dst: BikeshedIntrinsicFrom + {} +} + +fn should_pad_explicitly_packed_field() { + #[derive(Clone, Copy)] #[repr(u8)] enum V0u8 { V = 0 } + #[derive(Clone, Copy)] #[repr(u8)] enum V1u8 { V = 1 } + #[derive(Clone, Copy)] #[repr(u8)] enum V2u8 { V = 2 } + #[derive(Clone, Copy)] #[repr(u32)] enum V3u32 { V = 3 } + + #[repr(C)] + pub union Uninit { + a: (), + b: V1u8, + } + + #[repr(C, packed(2))] + pub union Packed { + a: [V3u32; 0], + b: V0u8, + } + + #[repr(C)] struct ImplicitlyPadded(Packed, V2u8); + #[repr(C)] struct ExplicitlyPadded(V0u8, Uninit, V2u8); + + assert::is_maybe_transmutable::(); + assert::is_maybe_transmutable::(); +} diff --git a/src/test/ui/transmutability/unions/repr/should_require_well_defined_layout.rs b/src/test/ui/transmutability/unions/repr/should_require_well_defined_layout.rs new file mode 100644 index 0000000000000..d6e28d7f0db3f --- /dev/null +++ b/src/test/ui/transmutability/unions/repr/should_require_well_defined_layout.rs @@ -0,0 +1,37 @@ +//! A struct must have a well-defined layout to participate in a transmutation. + +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code, incomplete_features, non_camel_case_types)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + pub struct Context; + + pub fn is_maybe_transmutable() + where + Dst: BikeshedIntrinsicFrom + {} +} + +fn should_reject_repr_rust() +{ + union repr_rust { + a: u8 + } + + assert::is_maybe_transmutable::(); //~ ERROR not satisfied + assert::is_maybe_transmutable::(); //~ ERROR not satisfied +} + +fn should_accept_repr_C() +{ + #[repr(C)] + union repr_c { + a: u8 + } + + struct repr_rust; + assert::is_maybe_transmutable::(); + assert::is_maybe_transmutable::(); +} diff --git a/src/test/ui/transmutability/unions/repr/should_require_well_defined_layout.stderr b/src/test/ui/transmutability/unions/repr/should_require_well_defined_layout.stderr new file mode 100644 index 0000000000000..c24193f9a6d77 --- /dev/null +++ b/src/test/ui/transmutability/unions/repr/should_require_well_defined_layout.stderr @@ -0,0 +1,33 @@ +error[E0277]: the trait bound `(): BikeshedIntrinsicFrom` is not satisfied + --> $DIR/should_require_well_defined_layout.rs:23:48 + | +LL | assert::is_maybe_transmutable::(); + | ^^ the trait `BikeshedIntrinsicFrom` is not implemented for `()` + | +note: required by a bound in `is_maybe_transmutable` + --> $DIR/should_require_well_defined_layout.rs:13:14 + | +LL | pub fn is_maybe_transmutable() + | --------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` + +error[E0277]: the trait bound `should_reject_repr_rust::repr_rust: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/should_require_well_defined_layout.rs:24:43 + | +LL | assert::is_maybe_transmutable::(); + | ^^^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `should_reject_repr_rust::repr_rust` + | +note: required by a bound in `is_maybe_transmutable` + --> $DIR/should_require_well_defined_layout.rs:13:14 + | +LL | pub fn is_maybe_transmutable() + | --------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/transmutability/unions/should_pad_variants.rs b/src/test/ui/transmutability/unions/should_pad_variants.rs new file mode 100644 index 0000000000000..d4126693f9284 --- /dev/null +++ b/src/test/ui/transmutability/unions/should_pad_variants.rs @@ -0,0 +1,40 @@ +//! The variants of a union must be padded with uninit bytes such that they have +//! the same length (in bytes). + +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + + pub fn is_transmutable() + where + Dst: BikeshedIntrinsicFrom + {} +} + +#[derive(Clone, Copy)] +#[repr(C)] struct Zst; + +#[derive(Clone, Copy)] +#[repr(u8)] enum V0 { V = 0 } + +#[derive(Clone, Copy)] +#[repr(u8)] enum V2 { V = 2 } + +#[repr(C)] +union Lopsided { + smol: Zst, + lorg: V0, +} + +#[repr(C)] struct Src(V0, Zst, V2); +#[repr(C)] struct Dst(V0, Lopsided, V2); + +fn should_pad_variants() { + struct Context; + // If the implementation (incorrectly) fails to pad `Lopsided::smol` with + // an uninitialized byte, this transmutation might be (wrongly) accepted: + assert::is_transmutable::(); //~ ERROR not satisfied +} diff --git a/src/test/ui/transmutability/unions/should_pad_variants.stderr b/src/test/ui/transmutability/unions/should_pad_variants.stderr new file mode 100644 index 0000000000000..b940ca077d4ad --- /dev/null +++ b/src/test/ui/transmutability/unions/should_pad_variants.stderr @@ -0,0 +1,18 @@ +error[E0277]: the trait bound `Dst: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/should_pad_variants.rs:39:36 + | +LL | assert::is_transmutable::(); + | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `Dst` + | +note: required by a bound in `is_transmutable` + --> $DIR/should_pad_variants.rs:13:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/transmutability/unions/should_permit_intersecting_if_validity_is_assumed.rs b/src/test/ui/transmutability/unions/should_permit_intersecting_if_validity_is_assumed.rs new file mode 100644 index 0000000000000..2493d71554ad3 --- /dev/null +++ b/src/test/ui/transmutability/unions/should_permit_intersecting_if_validity_is_assumed.rs @@ -0,0 +1,39 @@ +// check-pass +//! If validity is assumed, there need only be one matching bit-pattern between +//! the source and destination types. + +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code, incomplete_features, non_camel_case_types)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + pub struct Context; + + pub fn is_maybe_transmutable() + where + Dst: BikeshedIntrinsicFrom + // validity IS assumed --------------------------------^^^^ + {} +} + +#[derive(Clone, Copy)] #[repr(u8)] enum Ox00 { V = 0x00 } +#[derive(Clone, Copy)] #[repr(u8)] enum Ox7F { V = 0x7F } +#[derive(Clone, Copy)] #[repr(u8)] enum OxFF { V = 0xFF } + +fn test() { + #[repr(C)] + union A { + a: Ox00, + b: Ox7F, + } + + #[repr(C)] + union B { + a: Ox7F, + b: OxFF, + } + + assert::is_maybe_transmutable::(); + assert::is_maybe_transmutable::(); +} diff --git a/src/test/ui/transmutability/unions/should_reject_contraction.rs b/src/test/ui/transmutability/unions/should_reject_contraction.rs new file mode 100644 index 0000000000000..34b31595193dd --- /dev/null +++ b/src/test/ui/transmutability/unions/should_reject_contraction.rs @@ -0,0 +1,36 @@ +//! Validity may not be contracted, unless validity is assumed. + +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code, incomplete_features, non_camel_case_types)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + pub struct Context; + + pub fn is_transmutable() + where + Dst: BikeshedIntrinsicFrom + {} +} + +#[derive(Clone, Copy)] #[repr(u8)] enum Ox00 { V = 0x00 } +#[derive(Clone, Copy)] #[repr(u8)] enum Ox01 { V = 0x01 } +#[derive(Clone, Copy)] #[repr(u8)] enum OxFF { V = 0xFF } + +fn test() { + #[repr(C)] + union Subset { + a: Ox00, + b: OxFF, + } + + #[repr(C)] + union Superset { + a: Ox00, + b: OxFF, + c: Ox01, + } + + assert::is_transmutable::(); //~ ERROR not satisfied +} diff --git a/src/test/ui/transmutability/unions/should_reject_contraction.stderr b/src/test/ui/transmutability/unions/should_reject_contraction.stderr new file mode 100644 index 0000000000000..1465c3df22837 --- /dev/null +++ b/src/test/ui/transmutability/unions/should_reject_contraction.stderr @@ -0,0 +1,18 @@ +error[E0277]: the trait bound `Subset: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/should_reject_contraction.rs:35:41 + | +LL | assert::is_transmutable::(); + | ^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `Subset` + | +note: required by a bound in `is_transmutable` + --> $DIR/should_reject_contraction.rs:13:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/transmutability/unions/should_reject_disjoint.rs b/src/test/ui/transmutability/unions/should_reject_disjoint.rs new file mode 100644 index 0000000000000..b4b06c571315e --- /dev/null +++ b/src/test/ui/transmutability/unions/should_reject_disjoint.rs @@ -0,0 +1,36 @@ +//! Validity must be satisfiable, even if validity is assumed. + +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code, incomplete_features, non_camel_case_types)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + pub struct Context; + + pub fn is_maybe_transmutable() + where + Dst: BikeshedIntrinsicFrom + // validity IS assumed --------------------------------^^^^ + {} +} + +#[derive(Clone, Copy)] #[repr(u8)] enum Ox00 { V = 0x00 } +#[derive(Clone, Copy)] #[repr(u8)] enum Ox01 { V = 0x01 } +#[derive(Clone, Copy)] #[repr(u8)] enum OxFF { V = 0xFF } + +fn test() { + #[repr(C)] + union A { + a: Ox00, + b: OxFF, + } + + #[repr(C)] + union B { + c: Ox01, + } + + assert::is_maybe_transmutable::(); //~ ERROR not satisfied + assert::is_maybe_transmutable::(); //~ ERROR not satisfied +} diff --git a/src/test/ui/transmutability/unions/should_reject_disjoint.stderr b/src/test/ui/transmutability/unions/should_reject_disjoint.stderr new file mode 100644 index 0000000000000..a140f0c506b3b --- /dev/null +++ b/src/test/ui/transmutability/unions/should_reject_disjoint.stderr @@ -0,0 +1,33 @@ +error[E0277]: the trait bound `B: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/should_reject_disjoint.rs:34:40 + | +LL | assert::is_maybe_transmutable::(); + | ^ the trait `BikeshedIntrinsicFrom` is not implemented for `B` + | +note: required by a bound in `is_maybe_transmutable` + --> $DIR/should_reject_disjoint.rs:13:14 + | +LL | pub fn is_maybe_transmutable() + | --------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` + +error[E0277]: the trait bound `A: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/should_reject_disjoint.rs:35:40 + | +LL | assert::is_maybe_transmutable::(); + | ^ the trait `BikeshedIntrinsicFrom` is not implemented for `A` + | +note: required by a bound in `is_maybe_transmutable` + --> $DIR/should_reject_disjoint.rs:13:14 + | +LL | pub fn is_maybe_transmutable() + | --------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/transmutability/unions/should_reject_intersecting.rs b/src/test/ui/transmutability/unions/should_reject_intersecting.rs new file mode 100644 index 0000000000000..1ed7d2a0bd9a0 --- /dev/null +++ b/src/test/ui/transmutability/unions/should_reject_intersecting.rs @@ -0,0 +1,38 @@ +//! ALL valid bit patterns of the source must be valid bit patterns of the +//! destination type, unless validity is assumed. + +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code, incomplete_features, non_camel_case_types)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + pub struct Context; + + pub fn is_transmutable() + where + Dst: BikeshedIntrinsicFrom + // validity is NOT assumed ----------------------------^^^^^ + {} +} + +#[derive(Clone, Copy)] #[repr(u8)] enum Ox00 { V = 0x00 } +#[derive(Clone, Copy)] #[repr(u8)] enum Ox7F { V = 0x7F } +#[derive(Clone, Copy)] #[repr(u8)] enum OxFF { V = 0xFF } + +fn test() { + #[repr(C)] + union A { + a: Ox00, + b: Ox7F, + } + + #[repr(C)] + union B { + a: Ox7F, + b: OxFF, + } + + assert::is_transmutable::(); //~ ERROR not satisfied + assert::is_transmutable::(); //~ ERROR not satisfied +} diff --git a/src/test/ui/transmutability/unions/should_reject_intersecting.stderr b/src/test/ui/transmutability/unions/should_reject_intersecting.stderr new file mode 100644 index 0000000000000..43e642b569152 --- /dev/null +++ b/src/test/ui/transmutability/unions/should_reject_intersecting.stderr @@ -0,0 +1,33 @@ +error[E0277]: the trait bound `B: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/should_reject_intersecting.rs:36:34 + | +LL | assert::is_transmutable::(); + | ^ the trait `BikeshedIntrinsicFrom` is not implemented for `B` + | +note: required by a bound in `is_transmutable` + --> $DIR/should_reject_intersecting.rs:14:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `A: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/should_reject_intersecting.rs:37:34 + | +LL | assert::is_transmutable::(); + | ^ the trait `BikeshedIntrinsicFrom` is not implemented for `A` + | +note: required by a bound in `is_transmutable` + --> $DIR/should_reject_intersecting.rs:14:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_private_field.rs b/src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_private_field.rs new file mode 100644 index 0000000000000..5a8c810494c58 --- /dev/null +++ b/src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_private_field.rs @@ -0,0 +1,38 @@ +// check-pass +//! If visibility is assumed, a transmutation should be accepted even if the +//! destination type contains a private field. + +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + + pub fn is_transmutable() + where + Dst: BikeshedIntrinsicFrom + // visibility IS assumed -------------------------------------^^^^ + {} +} + +mod src { + #[repr(C)] pub(self) struct Zst; + + #[repr(C)] pub(in super) struct Src { + pub(self) field: Zst, + } +} + +mod dst { + #[repr(C)] pub(in super) struct Zst; + + #[repr(C)] pub(in super) struct Dst { + pub(self) field: Zst, // <- private field + } +} + +fn test() { + struct Context; + assert::is_transmutable::(); +} diff --git a/src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_private_variant.rs b/src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_private_variant.rs new file mode 100644 index 0000000000000..77ab4fa6bff4b --- /dev/null +++ b/src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_private_variant.rs @@ -0,0 +1,39 @@ +// check-pass +//! If visibility is assumed, a transmutation should be accepted even if the +//! destination type contains a private variant. + +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + + pub fn is_transmutable() + where + Dst: BikeshedIntrinsicFrom + // visibility IS assumed -------------------------------------^^^^ + {} +} + +mod src { + #[repr(C)] pub(self) struct Zst; + + #[repr(C)] pub(in super) struct Src { + pub(self) field: Zst, + } +} + +mod dst { + #[derive(Copy, Clone)] + #[repr(C)] pub(in super) struct Zst; + + #[repr(C)] pub(in super) union Dst { + pub(self) field: Zst, // <- private variant + } +} + +fn test() { + struct Context; + assert::is_transmutable::(); +} diff --git a/src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_tricky_unreachable_field.rs b/src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_tricky_unreachable_field.rs new file mode 100644 index 0000000000000..2421b24cbf07f --- /dev/null +++ b/src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_tricky_unreachable_field.rs @@ -0,0 +1,46 @@ +// check-pass +//! Unless visibility is assumed, a transmutation should be rejected if the +//! destination type contains an unreachable field (e.g., a public field with a +//! private type). (This rule is distinct from type privacy, which still may +//! forbid naming such types.) +//! +//! This test exercises a tricky-to-implement instance of this principle: the +//! "pub-in-priv trick". In the below example, the type `dst::private::Zst` is +//! unreachable from `Context`. + +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + + pub fn is_transmutable() + where + Dst: BikeshedIntrinsicFrom + // visibility IS assumed -------------------------------------^^^^ + {} +} + +mod src { + #[repr(C)] pub(in super) struct Zst; + + #[repr(C)] pub(in super) struct Src { + pub(in super) field: Zst, + } +} + +mod dst { + mod private { + #[repr(C)] pub struct Zst; // <- unreachable type + } + + #[repr(C)] pub(in super) struct Dst { + pub(in super) field: private::Zst, + } +} + +fn test() { + struct Context; + assert::is_transmutable::(); +} diff --git a/src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_unreachable_field.rs b/src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_unreachable_field.rs new file mode 100644 index 0000000000000..80b454fda560f --- /dev/null +++ b/src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_unreachable_field.rs @@ -0,0 +1,39 @@ +//! If visibility is assumed, a transmutation should be accepted even if the +//! destination type contains an unreachable field (e.g., a public field with a +//! private type). (This rule is distinct from type privacy, which still may +//! forbid naming such types.) + +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + + pub fn is_transmutable() + where + Dst: BikeshedIntrinsicFrom + // visibility IS assumed -------------------------------------^^^^ + {} +} + +mod src { + #[repr(C)] pub(self) struct Zst; + + #[repr(C)] pub(in super) struct Src { + pub(self) field: Zst, + } +} + +mod dst { + #[repr(C)] pub(self) struct Zst; // <- unreachable type + + #[repr(C)] pub(in super) struct Dst { + pub(in super) field: Zst, //~ ERROR private type + } +} + +fn test() { + struct Context; + assert::is_transmutable::(); +} diff --git a/src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_unreachable_field.stderr b/src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_unreachable_field.stderr new file mode 100644 index 0000000000000..be83b7ce33f24 --- /dev/null +++ b/src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_unreachable_field.stderr @@ -0,0 +1,12 @@ +error[E0446]: private type `dst::Zst` in public interface + --> $DIR/should_accept_if_dst_has_unreachable_field.rs:32:9 + | +LL | #[repr(C)] pub(self) struct Zst; // <- unreachable type + | -------------------- `dst::Zst` declared as private +... +LL | pub(in super) field: Zst, + | ^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0446`. diff --git a/src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_unreachable_ty.rs b/src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_unreachable_ty.rs new file mode 100644 index 0000000000000..7c53c91e4eda7 --- /dev/null +++ b/src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_unreachable_ty.rs @@ -0,0 +1,40 @@ +//! If visibility is assumed, a transmutation should be accepted even if the +//! destination type contains an unreachable field (e.g., a public field with a +//! private type). (This rule is distinct from type privacy, which still may +//! forbid naming such types.) + +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + + pub fn is_transmutable() + where + Dst: BikeshedIntrinsicFrom + // visibility IS assumed -------------------------------------^^^^ + {} +} + +mod src { + #[repr(C)] pub(self) struct Zst; + + #[repr(C)] pub(in super) struct Src { + pub(self) field: Zst, + } +} + +mod dst { + #[repr(C)] pub(in super) struct Zst; + + // unreachable type + #[repr(C)] pub(self) struct Dst { + pub(in super) field: Zst, + } +} + +fn test() { + struct Context; + assert::is_transmutable::(); //~ ERROR `Dst` is private +} diff --git a/src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_unreachable_ty.stderr b/src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_unreachable_ty.stderr new file mode 100644 index 0000000000000..827df05decb8f --- /dev/null +++ b/src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_unreachable_ty.stderr @@ -0,0 +1,15 @@ +error[E0603]: struct `Dst` is private + --> $DIR/should_accept_if_dst_has_unreachable_ty.rs:39:46 + | +LL | assert::is_transmutable::(); + | ^^^ private struct + | +note: the struct `Dst` is defined here + --> $DIR/should_accept_if_dst_has_unreachable_ty.rs:32:16 + | +LL | #[repr(C)] pub(self) struct Dst { + | ^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0603`. diff --git a/src/test/ui/transmutability/visibility/should_accept_if_src_has_private_field.rs b/src/test/ui/transmutability/visibility/should_accept_if_src_has_private_field.rs new file mode 100644 index 0000000000000..c3f298f016325 --- /dev/null +++ b/src/test/ui/transmutability/visibility/should_accept_if_src_has_private_field.rs @@ -0,0 +1,38 @@ +// check-pass +//! The presence of a private field in the source type does not affect +//! transmutability. + +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + + pub fn is_transmutable() + where + Dst: BikeshedIntrinsicFrom + // visibility is NOT assumed ---------------------------------^^^^^ + {} +} + +mod src { + #[repr(C)] pub(in super) struct Zst; + + #[repr(C)] pub(in super) struct Src { + pub(self) field: Zst, // <- private field + } +} + +mod dst { + #[repr(C)] pub(in super) struct Zst; + + #[repr(C)] pub(in super) struct Dst { + pub(in super) field: Zst, + } +} + +fn test() { + struct Context; + assert::is_transmutable::(); +} diff --git a/src/test/ui/transmutability/visibility/should_accept_if_src_has_private_variant.rs b/src/test/ui/transmutability/visibility/should_accept_if_src_has_private_variant.rs new file mode 100644 index 0000000000000..73f6aece51eb5 --- /dev/null +++ b/src/test/ui/transmutability/visibility/should_accept_if_src_has_private_variant.rs @@ -0,0 +1,39 @@ +// check-pass +//! The presence of a private variant in the source type does not affect +//! transmutability. + +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + + pub fn is_transmutable() + where + Dst: BikeshedIntrinsicFrom + // visibility is NOT assumed ---------------------------------^^^^^ + {} +} + +mod src { + #[derive(Copy, Clone)] + #[repr(C)] pub(in super) struct Zst; + + #[repr(C)] pub(in super) union Src { + pub(self) field: Zst, // <- private variant + } +} + +mod dst { + #[repr(C)] pub(in super) struct Zst; + + #[repr(C)] pub(in super) struct Dst { + pub(in super) field: Zst, + } +} + +fn test() { + struct Context; + assert::is_transmutable::(); +} diff --git a/src/test/ui/transmutability/visibility/should_accept_if_src_has_unreachable_field.rs b/src/test/ui/transmutability/visibility/should_accept_if_src_has_unreachable_field.rs new file mode 100644 index 0000000000000..6d602601e96ab --- /dev/null +++ b/src/test/ui/transmutability/visibility/should_accept_if_src_has_unreachable_field.rs @@ -0,0 +1,38 @@ +//! The presence of an unreachable field in the source type (e.g., a public +//! field with a private type does not affect transmutability. (This rule is +//! distinct from type privacy, which still may forbid naming such types.) + +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + + pub fn is_transmutable() + where + Dst: BikeshedIntrinsicFrom + // visibility is NOT assumed ---------------------------------^^^^^ + {} +} + +mod src { + #[repr(C)] pub(self) struct Zst; // <- unreachable type + + #[repr(C)] pub(in super) struct Src { + pub(in super) field: Zst, //~ ERROR private type + } +} + +mod dst { + #[repr(C)] pub(in super) struct Zst; + + #[repr(C)] pub(in super) struct Dst { + pub(in super) field: Zst, + } +} + +fn test() { + struct Context; + assert::is_transmutable::(); +} diff --git a/src/test/ui/transmutability/visibility/should_accept_if_src_has_unreachable_field.stderr b/src/test/ui/transmutability/visibility/should_accept_if_src_has_unreachable_field.stderr new file mode 100644 index 0000000000000..3f7d08d0ae248 --- /dev/null +++ b/src/test/ui/transmutability/visibility/should_accept_if_src_has_unreachable_field.stderr @@ -0,0 +1,12 @@ +error[E0446]: private type `src::Zst` in public interface + --> $DIR/should_accept_if_src_has_unreachable_field.rs:23:9 + | +LL | #[repr(C)] pub(self) struct Zst; // <- unreachable type + | -------------------- `src::Zst` declared as private +... +LL | pub(in super) field: Zst, + | ^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0446`. diff --git a/src/test/ui/transmutability/visibility/should_accept_if_src_has_unreachable_ty.rs b/src/test/ui/transmutability/visibility/should_accept_if_src_has_unreachable_ty.rs new file mode 100644 index 0000000000000..1943fb8716a11 --- /dev/null +++ b/src/test/ui/transmutability/visibility/should_accept_if_src_has_unreachable_ty.rs @@ -0,0 +1,39 @@ +//! The presence of an unreachable source type (i.e., the source type is +//! private) does not affect transmutability. (This rule is distinct from type +//! privacy, which still may forbid naming such types.) + +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + + pub fn is_transmutable() + where + Dst: BikeshedIntrinsicFrom + // visibility is NOT assumed ---------------------------------^^^^^ + {} +} + +mod src { + #[repr(C)] pub(in super) struct Zst; + + // unreachable type + #[repr(C)] pub(self) struct Src { + pub(in super) field: Zst, + } +} + +mod dst { + #[repr(C)] pub(in super) struct Zst; + + #[repr(C)] pub(in super) struct Dst { + pub(in super) field: Zst, + } +} + +fn test() { + struct Context; + assert::is_transmutable::(); //~ ERROR `Src` is private +} diff --git a/src/test/ui/transmutability/visibility/should_accept_if_src_has_unreachable_ty.stderr b/src/test/ui/transmutability/visibility/should_accept_if_src_has_unreachable_ty.stderr new file mode 100644 index 0000000000000..e961984e18932 --- /dev/null +++ b/src/test/ui/transmutability/visibility/should_accept_if_src_has_unreachable_ty.stderr @@ -0,0 +1,15 @@ +error[E0603]: struct `Src` is private + --> $DIR/should_accept_if_src_has_unreachable_ty.rs:38:36 + | +LL | assert::is_transmutable::(); + | ^^^ private struct + | +note: the struct `Src` is defined here + --> $DIR/should_accept_if_src_has_unreachable_ty.rs:23:16 + | +LL | #[repr(C)] pub(self) struct Src { + | ^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0603`. diff --git a/src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_field.rs b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_field.rs new file mode 100644 index 0000000000000..04cb6885887f4 --- /dev/null +++ b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_field.rs @@ -0,0 +1,37 @@ +//! Unless visibility is assumed, a transmutation should be rejected if the +//! destination type contains a private field. + +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + + pub fn is_transmutable() + where + Dst: BikeshedIntrinsicFrom + // visibility is NOT assumed ---------------------------------^^^^^ + {} +} + +mod src { + #[repr(C)] pub(in super) struct Zst; + + #[repr(C)] pub(in super) struct Src { + pub(in super) field: Zst, + } +} + +mod dst { + #[repr(C)] pub(in super) struct Zst; + + #[repr(C)] pub(in super) struct Dst { + pub(self) field: Zst, // <- private field + } +} + +fn test() { + struct Context; + assert::is_transmutable::(); //~ ERROR not satisfied +} diff --git a/src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_field.stderr b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_field.stderr new file mode 100644 index 0000000000000..4dfbfaeafb648 --- /dev/null +++ b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_field.stderr @@ -0,0 +1,18 @@ +error[E0277]: the trait bound `Dst: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/should_reject_if_dst_has_private_field.rs:36:41 + | +LL | assert::is_transmutable::(); + | ^^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `Dst` + | +note: required by a bound in `is_transmutable` + --> $DIR/should_reject_if_dst_has_private_field.rs:13:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_variant.rs b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_variant.rs new file mode 100644 index 0000000000000..768e7bc559efe --- /dev/null +++ b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_variant.rs @@ -0,0 +1,38 @@ +//! Unless visibility is assumed, a transmutation should be rejected if the +//! destination type contains a private variant. + +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + + pub fn is_transmutable() + where + Dst: BikeshedIntrinsicFrom + // visibility is NOT assumed ---------------------------------^^^^^ + {} +} + +mod src { + #[repr(C)] pub(in super) struct Zst; + + #[repr(C)] pub(in super) struct Src { + pub(in super) field: Zst, + } +} + +mod dst { + #[derive(Copy, Clone)] + #[repr(C)] pub(in super) struct Zst; + + #[repr(C)] pub(in super) union Dst { + pub(self) field: Zst, // <- private variant + } +} + +fn test() { + struct Context; + assert::is_transmutable::(); //~ ERROR not satisfied +} diff --git a/src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_variant.stderr b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_variant.stderr new file mode 100644 index 0000000000000..ed834a1bd2587 --- /dev/null +++ b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_variant.stderr @@ -0,0 +1,18 @@ +error[E0277]: the trait bound `Dst: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/should_reject_if_dst_has_private_variant.rs:37:41 + | +LL | assert::is_transmutable::(); + | ^^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `Dst` + | +note: required by a bound in `is_transmutable` + --> $DIR/should_reject_if_dst_has_private_variant.rs:13:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/transmutability/visibility/should_reject_if_dst_has_tricky_unreachable_field.rs b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_tricky_unreachable_field.rs new file mode 100644 index 0000000000000..c44fed4cce392 --- /dev/null +++ b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_tricky_unreachable_field.rs @@ -0,0 +1,52 @@ +// check-pass +//! NOTE: This test documents a known-bug in the implementation of the +//! transmutability trait. Once fixed, the above "check-pass" header should be +//! removed, and an "ERROR not satisfied" annotation should be added at the end +//! of the line starting with `assert::is_transmutable`. +//! +//! Unless visibility is assumed, a transmutation should be rejected if the +//! destination type contains an unreachable field (e.g., a public field with a +//! private type). (This rule is distinct from type privacy, which still may +//! forbid naming such types.) +//! +//! This test exercises a tricky-to-implement instance of this principle: the +//! "pub-in-priv trick". In the below example, the type `dst::private::Zst` is +//! unreachable from `Context`. Consequently, the transmute from `Src` to `Dst` +//! SHOULD be rejected. + +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + + pub fn is_transmutable() + where + Dst: BikeshedIntrinsicFrom + // visibility is NOT assumed ---------------------------------^^^^^ + {} +} + +mod src { + #[repr(C)] pub(in super) struct Zst; + + #[repr(C)] pub(in super) struct Src { + pub(in super) field: Zst, + } +} + +mod dst { + mod private { + #[repr(C)] pub struct Zst; // <- unreachable type + } + + #[repr(C)] pub(in super) struct Dst { + pub(in super) field: private::Zst, + } +} + +fn test() { + struct Context; + assert::is_transmutable::(); +} diff --git a/src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_field.rs b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_field.rs new file mode 100644 index 0000000000000..dbef149bacc99 --- /dev/null +++ b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_field.rs @@ -0,0 +1,39 @@ +//! Unless visibility is assumed, a transmutation should be rejected if the +//! destination type contains an unreachable field (e.g., a public field with a +//! private type). (This rule is distinct from type privacy, which still may +//! forbid naming such types.) + +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + + pub fn is_transmutable() + where + Dst: BikeshedIntrinsicFrom + // visibility is NOT assumed ---------------------------------^^^^^ + {} +} + +mod src { + #[repr(C)] pub(in super) struct Zst; + + #[repr(C)] pub(in super) struct Src { + pub(in super) field: Zst, + } +} + +mod dst { + #[repr(C)] pub(self) struct Zst; // <- unreachable type + + #[repr(C)] pub(in super) struct Dst { + pub(in super) field: Zst, + } +} + +fn test() { + struct Context; + assert::is_transmutable::(); //~ ERROR not satisfied +} diff --git a/src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_field.stderr b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_field.stderr new file mode 100644 index 0000000000000..3029d6ab8eeee --- /dev/null +++ b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_field.stderr @@ -0,0 +1,18 @@ +error[E0277]: the trait bound `Dst: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/should_reject_if_dst_has_unreachable_field.rs:38:41 + | +LL | assert::is_transmutable::(); + | ^^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `Dst` + | +note: required by a bound in `is_transmutable` + --> $DIR/should_reject_if_dst_has_unreachable_field.rs:15:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_ty.rs b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_ty.rs new file mode 100644 index 0000000000000..c5947eceb656e --- /dev/null +++ b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_ty.rs @@ -0,0 +1,42 @@ +//! Unless visibility is assumed, a transmutation should be rejected if the +//! destination type contains an unreachable field (e.g., a public field with a +//! private type). (This rule is distinct from type privacy, which still may +//! forbid naming such types.) + +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + + pub fn is_transmutable() + where + Dst: BikeshedIntrinsicFrom + // visibility is NOT assumed ---------------------------------^^^^^ + {} +} + +mod src { + #[repr(C)] pub(in super) struct Zst; + + #[repr(C)] pub(in super) struct Src { + pub(in super) field: Zst, + } +} + +mod dst { + #[repr(C)] pub(in super) struct Zst; + + // unreachable type + #[repr(C)] pub(self) struct Dst { + pub(in super) field: Zst, + } +} + +fn test() { + struct Context; + assert::is_transmutable::(); + //~^ ERROR `Dst` is private + //~| ERROR not satisfied +} diff --git a/src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_ty.stderr b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_ty.stderr new file mode 100644 index 0000000000000..2fd3889032149 --- /dev/null +++ b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_ty.stderr @@ -0,0 +1,31 @@ +error[E0603]: struct `Dst` is private + --> $DIR/should_reject_if_dst_has_unreachable_ty.rs:39:46 + | +LL | assert::is_transmutable::(); + | ^^^ private struct + | +note: the struct `Dst` is defined here + --> $DIR/should_reject_if_dst_has_unreachable_ty.rs:32:16 + | +LL | #[repr(C)] pub(self) struct Dst { + | ^^^^^^^^^^^^^^^^^^^^ + +error[E0277]: the trait bound `Dst: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/should_reject_if_dst_has_unreachable_ty.rs:39:41 + | +LL | assert::is_transmutable::(); + | ^^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `Dst` + | +note: required by a bound in `is_transmutable` + --> $DIR/should_reject_if_dst_has_unreachable_ty.rs:15:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0277, E0603. +For more information about an error, try `rustc --explain E0277`. From 18751a708a5831dffcd3b95755496efdaf7ae7a0 Mon Sep 17 00:00:00 2001 From: Jack Wrenn Date: Wed, 20 Jul 2022 19:57:55 +0000 Subject: [PATCH 07/19] safe transmute: gracefully handle const params of wrong types ref: https://github.com/rust-lang/rust/pull/92268/files#r925244819 --- .../src/traits/select/confirmation.rs | 2 +- .../wrong-type-assume.rs | 40 +++++++++++++++++++ .../wrong-type-assume.stderr | 27 +++++++++++++ 3 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/transmutability/malformed-program-gracefulness/wrong-type-assume.rs create mode 100644 src/test/ui/transmutability/malformed-program-gracefulness/wrong-type-assume.stderr diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index a609fb2b17266..672c9b7b088df 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -288,7 +288,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .substs .const_at(i) .try_eval_bool(self.tcx(), obligation.param_env) - .unwrap() + .unwrap_or(true) }; let src_and_dst = predicate.map_bound(|p| rustc_transmute::Types { diff --git a/src/test/ui/transmutability/malformed-program-gracefulness/wrong-type-assume.rs b/src/test/ui/transmutability/malformed-program-gracefulness/wrong-type-assume.rs new file mode 100644 index 0000000000000..bd36748e7901b --- /dev/null +++ b/src/test/ui/transmutability/malformed-program-gracefulness/wrong-type-assume.rs @@ -0,0 +1,40 @@ +//! The implementation must behave well if const values of wrong types are +//! provided. + +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code, incomplete_features, non_camel_case_types)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + + pub fn is_transmutable< + Src, + Dst, + Context, + const ASSUME_ALIGNMENT: bool, + const ASSUME_LIFETIMES: bool, + const ASSUME_VALIDITY: bool, + const ASSUME_VISIBILITY: bool, + >() + where + Dst: BikeshedIntrinsicFrom< + Src, + Context, + ASSUME_ALIGNMENT, + ASSUME_LIFETIMES, + ASSUME_VALIDITY, + ASSUME_VISIBILITY, + >, + {} +} + +fn test() { + struct Context; + #[repr(C)] struct Src; + #[repr(C)] struct Dst; + assert::is_transmutable::(); //~ ERROR mismatched types + assert::is_transmutable::(); //~ ERROR mismatched types + assert::is_transmutable::(); //~ ERROR mismatched types + assert::is_transmutable::(); //~ ERROR mismatched types +} diff --git a/src/test/ui/transmutability/malformed-program-gracefulness/wrong-type-assume.stderr b/src/test/ui/transmutability/malformed-program-gracefulness/wrong-type-assume.stderr new file mode 100644 index 0000000000000..e1464e02352c6 --- /dev/null +++ b/src/test/ui/transmutability/malformed-program-gracefulness/wrong-type-assume.stderr @@ -0,0 +1,27 @@ +error[E0308]: mismatched types + --> $DIR/wrong-type-assume.rs:36:51 + | +LL | assert::is_transmutable::(); + | ^^^ expected `bool`, found `u8` + +error[E0308]: mismatched types + --> $DIR/wrong-type-assume.rs:37:58 + | +LL | assert::is_transmutable::(); + | ^^^ expected `bool`, found `u8` + +error[E0308]: mismatched types + --> $DIR/wrong-type-assume.rs:38:65 + | +LL | assert::is_transmutable::(); + | ^^^ expected `bool`, found `u8` + +error[E0308]: mismatched types + --> $DIR/wrong-type-assume.rs:39:72 + | +LL | assert::is_transmutable::(); + | ^^^ expected `bool`, found `u8` + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0308`. From 8c5c291882d3cafd26757bb1326fc3b3135a87f5 Mon Sep 17 00:00:00 2001 From: Jack Wrenn Date: Wed, 20 Jul 2022 20:03:06 +0000 Subject: [PATCH 08/19] safe transmute: test when `ASSUME` params are passed indirectly ref: https://github.com/rust-lang/rust/pull/92268/files#r925258420 --- .../abstraction/abstracted_assume.rs | 73 +++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 src/test/ui/transmutability/abstraction/abstracted_assume.rs diff --git a/src/test/ui/transmutability/abstraction/abstracted_assume.rs b/src/test/ui/transmutability/abstraction/abstracted_assume.rs new file mode 100644 index 0000000000000..2abbbf3c158d6 --- /dev/null +++ b/src/test/ui/transmutability/abstraction/abstracted_assume.rs @@ -0,0 +1,73 @@ +// check-pass +//! The implementation should behave correctly when the `ASSUME` parameters are +//! provided indirectly through an abstraction. + +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code, incomplete_features, non_camel_case_types)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + + pub fn is_transmutable< + Src, + Dst, + Context, + const ASSUME_ALIGNMENT: bool, + const ASSUME_LIFETIMES: bool, + const ASSUME_VALIDITY: bool, + const ASSUME_VISIBILITY: bool, + >() + where + Dst: BikeshedIntrinsicFrom< + Src, + Context, + ASSUME_ALIGNMENT, + ASSUME_LIFETIMES, + ASSUME_VALIDITY, + ASSUME_VISIBILITY, + >, + {} +} + +fn direct() { + struct Context; + #[repr(C)] struct Src; + #[repr(C)] struct Dst; + + assert::is_transmutable::(); +} + +fn via_const() { + struct Context; + #[repr(C)] struct Src; + #[repr(C)] struct Dst; + + const FALSE: bool = false; + + assert::is_transmutable::(); +} + +fn via_associated_const() { + struct Context; + #[repr(C)] struct Src; + #[repr(C)] struct Dst; + + trait Trait { + const FALSE: bool = true; + } + + struct Ty; + + impl Trait for Ty {} + + assert::is_transmutable::< + Src, + Dst, + Context, + {Ty::FALSE}, + {Ty::FALSE}, + {Ty::FALSE}, + {Ty::FALSE} + >(); +} From 0fa70c3b1272c986eed27f838b645892ad435772 Mon Sep 17 00:00:00 2001 From: Jack Wrenn Date: Wed, 20 Jul 2022 20:21:57 +0000 Subject: [PATCH 09/19] safe transmute: revise `Hash`, `PartialEq` impls on `VariantDef`, `FieldDef` Exhaustively destructure parameter(s) so that changes to type definitions will lead to compile errors, thus reminding contributors to re-assess the assumptions underpinning these impls. ref: https://github.com/rust-lang/rust/pull/92268/#discussion_r925241377 ref: https://github.com/rust-lang/rust/pull/92268/#discussion_r925241718 --- compiler/rustc_middle/src/ty/mod.rs | 73 ++++++++++++++++++++++++----- 1 file changed, 61 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 5fda1e6538e91..ce931d0fcd3be 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1724,23 +1724,56 @@ impl VariantDef { } } -/// There should be only one VariantDef for each `def_id`, therefore -/// it is fine to implement `PartialEq` only based on `def_id`. impl PartialEq for VariantDef { #[inline] fn eq(&self, other: &Self) -> bool { - self.def_id == other.def_id + // There should be only one `VariantDef` for each `def_id`, therefore + // it is fine to implement `PartialEq` only based on `def_id`. + // + // Below, we exhaustively destructure `self` and `other` so that if the + // definition of `VariantDef` changes, a compile-error will be produced, + // reminding us to revisit this assumption. + + let Self { + def_id: lhs_def_id, + ctor_def_id: _, + name: _, + discr: _, + fields: _, + ctor_kind: _, + flags: _, + } = &self; + + let Self { + def_id: rhs_def_id, + ctor_def_id: _, + name: _, + discr: _, + fields: _, + ctor_kind: _, + flags: _, + } = other; + + lhs_def_id == rhs_def_id } } impl Eq for VariantDef {} -/// There should be only one VariantDef for each `def_id`, therefore -/// it is fine to implement `Hash` only based on `def_id`. impl Hash for VariantDef { #[inline] fn hash(&self, s: &mut H) { - self.def_id.hash(s) + // There should be only one `VariantDef` for each `def_id`, therefore + // it is fine to implement `Hash` only based on `def_id`. + // + // Below, we exhaustively destructure `self` so that if the definition + // of `VariantDef` changes, a compile-error will be produced, reminding + // us to revisit this assumption. + + let Self { def_id, ctor_def_id: _, name: _, discr: _, fields: _, ctor_kind: _, flags: _ } = + &self; + + def_id.hash(s) } } @@ -1764,23 +1797,39 @@ pub struct FieldDef { pub vis: Visibility, } -/// There should be only one FieldDef for each `did`, therefore -/// it is fine to implement `PartialEq` only based on `did`. impl PartialEq for FieldDef { #[inline] fn eq(&self, other: &Self) -> bool { - self.did == other.did + // There should be only one `FieldDef` for each `did`, therefore it is + // fine to implement `PartialEq` only based on `did`. + // + // Below, we exhaustively destructure `self` so that if the definition + // of `FieldDef` changes, a compile-error will be produced, reminding + // us to revisit this assumption. + + let Self { did: lhs_did, name: _, vis: _ } = &self; + + let Self { did: rhs_did, name: _, vis: _ } = other; + + lhs_did == rhs_did } } impl Eq for FieldDef {} -/// There should be only one FieldDef for each `did`, therefore -/// it is fine to implement `Hash` only based on `did`. impl Hash for FieldDef { #[inline] fn hash(&self, s: &mut H) { - self.did.hash(s) + // There should be only one `FieldDef` for each `did`, therefore it is + // fine to implement `Hash` only based on `did`. + // + // Below, we exhaustively destructure `self` so that if the definition + // of `FieldDef` changes, a compile-error will be produced, reminding + // us to revisit this assumption. + + let Self { did, name: _, vis: _ } = &self; + + did.hash(s) } } From c0d0ce95ebdab2817b2b6240f802b5814a1dfcfe Mon Sep 17 00:00:00 2001 From: Jack Wrenn Date: Thu, 21 Jul 2022 17:28:24 +0000 Subject: [PATCH 10/19] safe transmute: tweak tracing ref: https://github.com/rust-lang/rust/pull/92268#discussion_r925246903 ref: https://github.com/rust-lang/rust/pull/92268#discussion_r925250811 ref: https://github.com/rust-lang/rust/pull/92268#discussion_r925255782 --- compiler/rustc_transmute/src/layout/dfa.rs | 2 +- compiler/rustc_transmute/src/layout/tree.rs | 16 ++++------------ compiler/rustc_transmute/src/lib.rs | 3 +++ .../src/maybe_transmutable/mod.rs | 12 ++++++------ .../src/maybe_transmutable/query_context.rs | 4 ++-- 5 files changed, 16 insertions(+), 21 deletions(-) diff --git a/compiler/rustc_transmute/src/layout/dfa.rs b/compiler/rustc_transmute/src/layout/dfa.rs index cdd3195712d26..f2742dc8ee5ad 100644 --- a/compiler/rustc_transmute/src/layout/dfa.rs +++ b/compiler/rustc_transmute/src/layout/dfa.rs @@ -103,7 +103,7 @@ where Self { transitions, start, accepting } } - #[tracing::instrument] + #[instrument(level = "DEBUG")] #[cfg_attr(feature = "rustc", allow(rustc::potential_query_instability))] pub(crate) fn from_nfa(nfa: Nfa) -> Self { let Nfa { transitions: nfa_transitions, start: nfa_start, accepting: nfa_accepting } = nfa; diff --git a/compiler/rustc_transmute/src/layout/tree.rs b/compiler/rustc_transmute/src/layout/tree.rs index 67b401855d4be..70b3ba02b05b5 100644 --- a/compiler/rustc_transmute/src/layout/tree.rs +++ b/compiler/rustc_transmute/src/layout/tree.rs @@ -76,7 +76,6 @@ where } /// A `Tree` whose layout is entirely padding of the given width. - #[tracing::instrument] pub(crate) fn padding(width_in_bytes: usize) -> Self { Self::Seq(vec![Self::uninit(); width_in_bytes]) } @@ -316,10 +315,7 @@ pub(crate) mod rustc { tcx, )?, AdtKind::Enum => { - tracing::trace!( - adt_def = ?adt_def, - "treeifying enum" - ); + tracing::trace!(?adt_def, "treeifying enum"); let mut tree = Tree::uninhabited(); for (idx, discr) in adt_def.discriminants(tcx) { @@ -398,13 +394,13 @@ pub(crate) mod rustc { // The layout of the variant is prefixed by the discriminant, if any. if let Some(discr) = discr { - tracing::trace!(discr = ?discr, "treeifying discriminant"); + tracing::trace!(?discr, "treeifying discriminant"); let discr_layout = alloc::Layout::from_size_align( layout_summary.discriminant_size, clamp(layout_summary.discriminant_align), ) .unwrap(); - tracing::trace!(discr_layout = ?discr_layout, "computed discriminant layout"); + tracing::trace!(?discr_layout, "computed discriminant layout"); variant_layout = variant_layout.extend(discr_layout).unwrap().0; tree = tree.then(Self::from_disr(discr, tcx, layout_summary.discriminant_size)); } @@ -469,11 +465,7 @@ pub(crate) mod rustc { layout.align().abi.bytes().try_into().unwrap(), ) .unwrap(); - tracing::trace!( - ty = ?ty, - layout = ?layout, - "computed layout for type" - ); + tracing::trace!(?ty, ?layout, "computed layout for type"); Ok(layout) } } diff --git a/compiler/rustc_transmute/src/lib.rs b/compiler/rustc_transmute/src/lib.rs index 9f7508fdd716a..cfc7c752a6bd6 100644 --- a/compiler/rustc_transmute/src/lib.rs +++ b/compiler/rustc_transmute/src/lib.rs @@ -8,6 +8,9 @@ )] #![allow(dead_code, unused_variables)] +#[macro_use] +extern crate tracing; + #[cfg(feature = "rustc")] pub(crate) use rustc_data_structures::fx::{FxHashMap as Map, FxHashSet as Set}; diff --git a/compiler/rustc_transmute/src/maybe_transmutable/mod.rs b/compiler/rustc_transmute/src/maybe_transmutable/mod.rs index ef3852001a806..8fb85527a0f0a 100644 --- a/compiler/rustc_transmute/src/maybe_transmutable/mod.rs +++ b/compiler/rustc_transmute/src/maybe_transmutable/mod.rs @@ -64,7 +64,7 @@ mod rustc { impl<'tcx> MaybeTransmutableQuery, TyCtxt<'tcx>> { /// This method begins by converting `src` and `dst` from `Ty`s to `Tree`s, /// then computes an answer using those trees. - #[tracing::instrument(skip(self), fields(src = ?self.src, dst = ?self.dst))] + #[instrument(level = "DEBUG", skip(self), fields(src = ?self.src, dst = ?self.dst))] pub fn answer(self) -> Answer< as QueryContext>::Ref> { let query_or_answer = self.map_layouts(|src, dst, scope, &context| { // Convert `src` and `dst` from their rustc representations, to `Tree`-based @@ -103,14 +103,14 @@ where /// This method begins by de-def'ing `src` and `dst`, and prunes private paths from `dst`, /// then converts `src` and `dst` to `Nfa`s, and computes an answer using those NFAs. #[inline(always)] - #[tracing::instrument(skip(self), fields(src = ?self.src, dst = ?self.dst))] + #[instrument(level = "DEBUG", skip(self), fields(src = ?self.src, dst = ?self.dst))] pub(crate) fn answer(self) -> Answer<::Ref> { let assume_visibility = self.assume.visibility; let query_or_answer = self.map_layouts(|src, dst, scope, context| { // Remove all `Def` nodes from `src`, without checking their visibility. let src = src.prune(&|def| true); - tracing::trace!(src = ?src, "pruned src"); + tracing::trace!(?src, "pruned src"); // Remove all `Def` nodes from `dst`, additionally... let dst = if assume_visibility { @@ -121,7 +121,7 @@ where dst.prune(&|def| context.is_accessible_from(def, scope)) }; - tracing::trace!(dst = ?dst, "pruned dst"); + tracing::trace!(?dst, "pruned dst"); // Convert `src` from a tree-based representation to an NFA-based representation. // If the conversion fails because `src` is uninhabited, conclude that the transmutation @@ -152,7 +152,7 @@ where /// /// This method converts `src` and `dst` to DFAs, then computes an answer using those DFAs. #[inline(always)] - #[tracing::instrument(skip(self), fields(src = ?self.src, dst = ?self.dst))] + #[instrument(level = "DEBUG", skip(self), fields(src = ?self.src, dst = ?self.dst))] pub(crate) fn answer(self) -> Answer<::Ref> { let query_or_answer = self .map_layouts(|src, dst, scope, context| Ok((Dfa::from_nfa(src), Dfa::from_nfa(dst)))); @@ -192,7 +192,7 @@ where } #[inline(always)] - #[tracing::instrument(skip(self))] + #[instrument(level = "DEBUG", skip(self))] fn answer_memo( &self, cache: &mut Map<(dfa::State, dfa::State), Answer<::Ref>>, diff --git a/compiler/rustc_transmute/src/maybe_transmutable/query_context.rs b/compiler/rustc_transmute/src/maybe_transmutable/query_context.rs index ab9bcd232f0d0..1a66b6cfe00ef 100644 --- a/compiler/rustc_transmute/src/maybe_transmutable/query_context.rs +++ b/compiler/rustc_transmute/src/maybe_transmutable/query_context.rs @@ -52,7 +52,7 @@ mod rustc { type Scope = Ty<'tcx>; - #[tracing::instrument(skip(self))] + #[instrument(level = "DEBUG", skip(self))] fn is_accessible_from(&self, def: Self::Def, scope: Self::Scope) -> bool { use layout::rustc::Def; use rustc_middle::ty; @@ -82,7 +82,7 @@ mod rustc { false }; - tracing::trace!(ret = ?ret, "ret"); + tracing::trace!(?ret, "ret"); ret } From 4a15157baddb266af94a58a0b9c88cf6f5c6540c Mon Sep 17 00:00:00 2001 From: Jack Wrenn Date: Thu, 21 Jul 2022 17:38:25 +0000 Subject: [PATCH 11/19] safe transmute: don't mark user impls as unambiguous ref: https://github.com/rust-lang/rust/pull/92268#discussion_r925243794 --- .../src/traits/select/candidate_assembly.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index a18b835e70ce1..a60ce0f3437e0 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -884,7 +884,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { candidates: &mut SelectionCandidateSet<'tcx>, ) { if obligation.has_param_types_or_consts() { - candidates.ambiguous = false; return; } From 402644f72f61a28b3690a565be82d2178cd44800 Mon Sep 17 00:00:00 2001 From: Jack Wrenn Date: Thu, 21 Jul 2022 17:43:25 +0000 Subject: [PATCH 12/19] safe transmute: test to ensure that trait is correctly feature-gated ref: https://github.com/rust-lang/rust/pull/92268#discussion_r925265476 --- .../malformed-program-gracefulness/feature-missing.rs | 6 ++++++ .../feature-missing.stderr | 11 +++++++++++ 2 files changed, 17 insertions(+) create mode 100644 src/test/ui/transmutability/malformed-program-gracefulness/feature-missing.rs create mode 100644 src/test/ui/transmutability/malformed-program-gracefulness/feature-missing.stderr diff --git a/src/test/ui/transmutability/malformed-program-gracefulness/feature-missing.rs b/src/test/ui/transmutability/malformed-program-gracefulness/feature-missing.rs new file mode 100644 index 0000000000000..12018f3161a75 --- /dev/null +++ b/src/test/ui/transmutability/malformed-program-gracefulness/feature-missing.rs @@ -0,0 +1,6 @@ +// The trait must not be available if its feature flag is absent. + +#![crate_type = "lib"] + +use std::mem::BikeshedIntrinsicFrom; +//~^ ERROR use of unstable library feature 'transmutability' [E0658] diff --git a/src/test/ui/transmutability/malformed-program-gracefulness/feature-missing.stderr b/src/test/ui/transmutability/malformed-program-gracefulness/feature-missing.stderr new file mode 100644 index 0000000000000..4b51850634af1 --- /dev/null +++ b/src/test/ui/transmutability/malformed-program-gracefulness/feature-missing.stderr @@ -0,0 +1,11 @@ +error[E0658]: use of unstable library feature 'transmutability' + --> $DIR/feature-missing.rs:5:5 + | +LL | use std::mem::BikeshedIntrinsicFrom; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: add `#![feature(transmutability)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. From 21d1ab4877c96a2b2fa802444f3a3d311a96beef Mon Sep 17 00:00:00 2001 From: Jack Wrenn Date: Thu, 21 Jul 2022 17:53:01 +0000 Subject: [PATCH 13/19] safe transmute: add `rustc_on_unimplemented` to `BikeshedIntrinsicFrom` ref: https://github.com/rust-lang/rust/pull/92268#discussion_r925266583 --- library/core/src/mem/transmutability.rs | 4 + .../should_require_well_defined_layout.rs | 12 +- .../should_require_well_defined_layout.stderr | 30 +- ...mitive_reprs_should_have_correct_length.rs | 40 +-- ...ve_reprs_should_have_correct_length.stderr | 100 +++--- .../should_require_well_defined_layout.rs | 12 +- .../should_require_well_defined_layout.stderr | 30 +- .../enums/should_pad_variants.rs | 2 +- .../enums/should_pad_variants.stderr | 5 +- .../enums/should_respect_endianness.rs | 2 +- .../enums/should_respect_endianness.stderr | 5 +- .../ui/transmutability/primitives/bool.rs | 2 +- .../ui/transmutability/primitives/bool.stderr | 5 +- .../ui/transmutability/primitives/numbers.rs | 132 ++++---- .../transmutability/primitives/numbers.stderr | 285 +++++++++++------- .../ui/transmutability/primitives/unit.rs | 2 +- .../ui/transmutability/primitives/unit.stderr | 5 +- src/test/ui/transmutability/references.rs | 2 +- src/test/ui/transmutability/references.stderr | 5 +- .../should_require_well_defined_layout.rs | 24 +- .../should_require_well_defined_layout.stderr | 60 ++-- .../should_require_well_defined_layout.rs | 4 +- .../should_require_well_defined_layout.stderr | 10 +- .../unions/should_pad_variants.rs | 2 +- .../unions/should_pad_variants.stderr | 5 +- .../unions/should_reject_contraction.rs | 2 +- .../unions/should_reject_contraction.stderr | 5 +- .../unions/should_reject_disjoint.rs | 4 +- .../unions/should_reject_disjoint.stderr | 10 +- .../unions/should_reject_intersecting.rs | 4 +- .../unions/should_reject_intersecting.stderr | 10 +- .../should_reject_if_dst_has_private_field.rs | 2 +- ...uld_reject_if_dst_has_private_field.stderr | 5 +- ...hould_reject_if_dst_has_private_variant.rs | 2 +- ...d_reject_if_dst_has_private_variant.stderr | 5 +- ...ect_if_dst_has_tricky_unreachable_field.rs | 2 +- ...uld_reject_if_dst_has_unreachable_field.rs | 2 +- ...reject_if_dst_has_unreachable_field.stderr | 5 +- ...should_reject_if_dst_has_unreachable_ty.rs | 2 +- ...ld_reject_if_dst_has_unreachable_ty.stderr | 5 +- 40 files changed, 486 insertions(+), 364 deletions(-) diff --git a/library/core/src/mem/transmutability.rs b/library/core/src/mem/transmutability.rs index 52342f8a0ecd6..820a7582b113b 100644 --- a/library/core/src/mem/transmutability.rs +++ b/library/core/src/mem/transmutability.rs @@ -5,6 +5,10 @@ /// notwithstanding whatever safety checks you have asked the compiler to [`Assume`] are satisfied. #[unstable(feature = "transmutability", issue = "none")] #[cfg_attr(not(bootstrap), lang = "transmute_trait")] +#[rustc_on_unimplemented( + message = "`{Src}` cannot be safely transmuted into `{Self}` in the defining scope of `{Context}`.", + label = "`{Src}` cannot be safely transmuted into `{Self}` in the defining scope of `{Context}`." +)] pub unsafe trait BikeshedIntrinsicFrom< Src, Context, diff --git a/src/test/ui/transmutability/arrays/should_require_well_defined_layout.rs b/src/test/ui/transmutability/arrays/should_require_well_defined_layout.rs index 36f9ceb0da7a6..8e69527c1862c 100644 --- a/src/test/ui/transmutability/arrays/should_require_well_defined_layout.rs +++ b/src/test/ui/transmutability/arrays/should_require_well_defined_layout.rs @@ -18,20 +18,20 @@ fn should_reject_repr_rust() { fn unit() { type repr_rust = [String; 0]; - assert::is_maybe_transmutable::(); //~ ERROR not satisfied - assert::is_maybe_transmutable::(); //~ ERROR not satisfied + assert::is_maybe_transmutable::(); //~ ERROR cannot be safely transmuted + assert::is_maybe_transmutable::(); //~ ERROR cannot be safely transmuted } fn singleton() { type repr_rust = [String; 1]; - assert::is_maybe_transmutable::(); //~ ERROR not satisfied - assert::is_maybe_transmutable::(); //~ ERROR not satisfied + assert::is_maybe_transmutable::(); //~ ERROR cannot be safely transmuted + assert::is_maybe_transmutable::(); //~ ERROR cannot be safely transmuted } fn duplex() { type repr_rust = [String; 2]; - assert::is_maybe_transmutable::(); //~ ERROR not satisfied - assert::is_maybe_transmutable::(); //~ ERROR not satisfied + assert::is_maybe_transmutable::(); //~ ERROR cannot be safely transmuted + assert::is_maybe_transmutable::(); //~ ERROR cannot be safely transmuted } } diff --git a/src/test/ui/transmutability/arrays/should_require_well_defined_layout.stderr b/src/test/ui/transmutability/arrays/should_require_well_defined_layout.stderr index 109e58c4093cb..eae0c947d4253 100644 --- a/src/test/ui/transmutability/arrays/should_require_well_defined_layout.stderr +++ b/src/test/ui/transmutability/arrays/should_require_well_defined_layout.stderr @@ -1,9 +1,10 @@ -error[E0277]: the trait bound `(): BikeshedIntrinsicFrom<[String; 0], assert::Context, true, true, true, true>` is not satisfied +error[E0277]: `[String; 0]` cannot be safely transmuted into `()` in the defining scope of `assert::Context`. --> $DIR/should_require_well_defined_layout.rs:21:52 | LL | assert::is_maybe_transmutable::(); - | ^^ the trait `BikeshedIntrinsicFrom<[String; 0], assert::Context, true, true, true, true>` is not implemented for `()` + | ^^ `[String; 0]` cannot be safely transmuted into `()` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom<[String; 0], assert::Context, true, true, true, true>` is not implemented for `()` note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:13:14 | @@ -13,12 +14,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` -error[E0277]: the trait bound `[String; 0]: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u128` cannot be safely transmuted into `[String; 0]` in the defining scope of `assert::Context`. --> $DIR/should_require_well_defined_layout.rs:22:47 | LL | assert::is_maybe_transmutable::(); - | ^^^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `[String; 0]` + | ^^^^^^^^^ `u128` cannot be safely transmuted into `[String; 0]` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `[String; 0]` note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:13:14 | @@ -28,12 +30,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` -error[E0277]: the trait bound `(): BikeshedIntrinsicFrom<[String; 1], assert::Context, true, true, true, true>` is not satisfied +error[E0277]: `[String; 1]` cannot be safely transmuted into `()` in the defining scope of `assert::Context`. --> $DIR/should_require_well_defined_layout.rs:27:52 | LL | assert::is_maybe_transmutable::(); - | ^^ the trait `BikeshedIntrinsicFrom<[String; 1], assert::Context, true, true, true, true>` is not implemented for `()` + | ^^ `[String; 1]` cannot be safely transmuted into `()` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom<[String; 1], assert::Context, true, true, true, true>` is not implemented for `()` note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:13:14 | @@ -43,12 +46,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` -error[E0277]: the trait bound `[String; 1]: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u128` cannot be safely transmuted into `[String; 1]` in the defining scope of `assert::Context`. --> $DIR/should_require_well_defined_layout.rs:28:47 | LL | assert::is_maybe_transmutable::(); - | ^^^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `[String; 1]` + | ^^^^^^^^^ `u128` cannot be safely transmuted into `[String; 1]` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `[String; 1]` note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:13:14 | @@ -58,12 +62,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` -error[E0277]: the trait bound `(): BikeshedIntrinsicFrom<[String; 2], assert::Context, true, true, true, true>` is not satisfied +error[E0277]: `[String; 2]` cannot be safely transmuted into `()` in the defining scope of `assert::Context`. --> $DIR/should_require_well_defined_layout.rs:33:52 | LL | assert::is_maybe_transmutable::(); - | ^^ the trait `BikeshedIntrinsicFrom<[String; 2], assert::Context, true, true, true, true>` is not implemented for `()` + | ^^ `[String; 2]` cannot be safely transmuted into `()` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom<[String; 2], assert::Context, true, true, true, true>` is not implemented for `()` note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:13:14 | @@ -73,12 +78,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` -error[E0277]: the trait bound `[String; 2]: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u128` cannot be safely transmuted into `[String; 2]` in the defining scope of `assert::Context`. --> $DIR/should_require_well_defined_layout.rs:34:47 | LL | assert::is_maybe_transmutable::(); - | ^^^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `[String; 2]` + | ^^^^^^^^^ `u128` cannot be safely transmuted into `[String; 2]` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `[String; 2]` note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:13:14 | diff --git a/src/test/ui/transmutability/enums/repr/primitive_reprs_should_have_correct_length.rs b/src/test/ui/transmutability/enums/repr/primitive_reprs_should_have_correct_length.rs index cd411a4b838e0..18e02b0d2b908 100644 --- a/src/test/ui/transmutability/enums/repr/primitive_reprs_should_have_correct_length.rs +++ b/src/test/ui/transmutability/enums/repr/primitive_reprs_should_have_correct_length.rs @@ -38,17 +38,17 @@ fn n8() { fn i_should_have_correct_length() { type Current = V0i8; - assert::is_transmutable::(); //~ ERROR not satisfied + assert::is_transmutable::(); //~ ERROR cannot be safely transmuted assert::is_transmutable::(); - assert::is_transmutable::(); //~ ERROR not satisfied + assert::is_transmutable::(); //~ ERROR cannot be safely transmuted } fn u_should_have_correct_length() { type Current = V0u8; - assert::is_transmutable::(); //~ ERROR not satisfied + assert::is_transmutable::(); //~ ERROR cannot be safely transmuted assert::is_transmutable::(); - assert::is_transmutable::(); //~ ERROR not satisfied + assert::is_transmutable::(); //~ ERROR cannot be safely transmuted } } @@ -62,17 +62,17 @@ fn n16() { fn i_should_have_correct_length() { type Current = V0i16; - assert::is_transmutable::(); //~ ERROR not satisfied + assert::is_transmutable::(); //~ ERROR cannot be safely transmuted assert::is_transmutable::(); - assert::is_transmutable::(); //~ ERROR not satisfied + assert::is_transmutable::(); //~ ERROR cannot be safely transmuted } fn u_should_have_correct_length() { type Current = V0u16; - assert::is_transmutable::(); //~ ERROR not satisfied + assert::is_transmutable::(); //~ ERROR cannot be safely transmuted assert::is_transmutable::(); - assert::is_transmutable::(); //~ ERROR not satisfied + assert::is_transmutable::(); //~ ERROR cannot be safely transmuted } } @@ -86,17 +86,17 @@ fn n32() { fn i_should_have_correct_length() { type Current = V0i32; - assert::is_transmutable::(); //~ ERROR not satisfied + assert::is_transmutable::(); //~ ERROR cannot be safely transmuted assert::is_transmutable::(); - assert::is_transmutable::(); //~ ERROR not satisfied + assert::is_transmutable::(); //~ ERROR cannot be safely transmuted } fn u_should_have_correct_length() { type Current = V0u32; - assert::is_transmutable::(); //~ ERROR not satisfied + assert::is_transmutable::(); //~ ERROR cannot be safely transmuted assert::is_transmutable::(); - assert::is_transmutable::(); //~ ERROR not satisfied + assert::is_transmutable::(); //~ ERROR cannot be safely transmuted } } @@ -110,17 +110,17 @@ fn n64() { fn i_should_have_correct_length() { type Current = V0i64; - assert::is_transmutable::(); //~ ERROR not satisfied + assert::is_transmutable::(); //~ ERROR cannot be safely transmuted assert::is_transmutable::(); - assert::is_transmutable::(); //~ ERROR not satisfied + assert::is_transmutable::(); //~ ERROR cannot be safely transmuted } fn u_should_have_correct_length() { type Current = V0u64; - assert::is_transmutable::(); //~ ERROR not satisfied + assert::is_transmutable::(); //~ ERROR cannot be safely transmuted assert::is_transmutable::(); - assert::is_transmutable::(); //~ ERROR not satisfied + assert::is_transmutable::(); //~ ERROR cannot be safely transmuted } } @@ -134,16 +134,16 @@ fn nsize() { fn i_should_have_correct_length() { type Current = V0isize; - assert::is_transmutable::(); //~ ERROR not satisfied + assert::is_transmutable::(); //~ ERROR cannot be safely transmuted assert::is_transmutable::(); - assert::is_transmutable::(); //~ ERROR not satisfied + assert::is_transmutable::(); //~ ERROR cannot be safely transmuted } fn u_should_have_correct_length() { type Current = V0usize; - assert::is_transmutable::(); //~ ERROR not satisfied + assert::is_transmutable::(); //~ ERROR cannot be safely transmuted assert::is_transmutable::(); - assert::is_transmutable::(); //~ ERROR not satisfied + assert::is_transmutable::(); //~ ERROR cannot be safely transmuted } } diff --git a/src/test/ui/transmutability/enums/repr/primitive_reprs_should_have_correct_length.stderr b/src/test/ui/transmutability/enums/repr/primitive_reprs_should_have_correct_length.stderr index da24c6a021efe..fa2e3b89b079a 100644 --- a/src/test/ui/transmutability/enums/repr/primitive_reprs_should_have_correct_length.stderr +++ b/src/test/ui/transmutability/enums/repr/primitive_reprs_should_have_correct_length.stderr @@ -1,9 +1,10 @@ -error[E0277]: the trait bound `V0i8: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `Zst` cannot be safely transmuted into `V0i8` in the defining scope of `n8::Context`. --> $DIR/primitive_reprs_should_have_correct_length.rs:41:44 | LL | assert::is_transmutable::(); - | ^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `V0i8` + | ^^^^^^^ `Zst` cannot be safely transmuted into `V0i8` in the defining scope of `n8::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `V0i8` note: required by a bound in `is_transmutable` --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 | @@ -13,12 +14,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `u16: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `V0i8` cannot be safely transmuted into `u16` in the defining scope of `n8::Context`. --> $DIR/primitive_reprs_should_have_correct_length.rs:43:44 | LL | assert::is_transmutable::(); - | ^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u16` + | ^^^^^^ `V0i8` cannot be safely transmuted into `u16` in the defining scope of `n8::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u16` note: required by a bound in `is_transmutable` --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 | @@ -28,12 +30,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `V0u8: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `Zst` cannot be safely transmuted into `V0u8` in the defining scope of `n8::Context`. --> $DIR/primitive_reprs_should_have_correct_length.rs:49:44 | LL | assert::is_transmutable::(); - | ^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `V0u8` + | ^^^^^^^ `Zst` cannot be safely transmuted into `V0u8` in the defining scope of `n8::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `V0u8` note: required by a bound in `is_transmutable` --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 | @@ -43,12 +46,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `u16: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `V0u8` cannot be safely transmuted into `u16` in the defining scope of `n8::Context`. --> $DIR/primitive_reprs_should_have_correct_length.rs:51:44 | LL | assert::is_transmutable::(); - | ^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u16` + | ^^^^^^ `V0u8` cannot be safely transmuted into `u16` in the defining scope of `n8::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u16` note: required by a bound in `is_transmutable` --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 | @@ -58,12 +62,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `V0i16: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u8` cannot be safely transmuted into `V0i16` in the defining scope of `n16::Context`. --> $DIR/primitive_reprs_should_have_correct_length.rs:65:44 | LL | assert::is_transmutable::(); - | ^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `V0i16` + | ^^^^^^^ `u8` cannot be safely transmuted into `V0i16` in the defining scope of `n16::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `V0i16` note: required by a bound in `is_transmutable` --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 | @@ -73,12 +78,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `u32: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `V0i16` cannot be safely transmuted into `u32` in the defining scope of `n16::Context`. --> $DIR/primitive_reprs_should_have_correct_length.rs:67:44 | LL | assert::is_transmutable::(); - | ^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u32` + | ^^^^^^ `V0i16` cannot be safely transmuted into `u32` in the defining scope of `n16::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u32` note: required by a bound in `is_transmutable` --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 | @@ -88,12 +94,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `V0u16: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u8` cannot be safely transmuted into `V0u16` in the defining scope of `n16::Context`. --> $DIR/primitive_reprs_should_have_correct_length.rs:73:44 | LL | assert::is_transmutable::(); - | ^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `V0u16` + | ^^^^^^^ `u8` cannot be safely transmuted into `V0u16` in the defining scope of `n16::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `V0u16` note: required by a bound in `is_transmutable` --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 | @@ -103,12 +110,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `u32: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `V0u16` cannot be safely transmuted into `u32` in the defining scope of `n16::Context`. --> $DIR/primitive_reprs_should_have_correct_length.rs:75:44 | LL | assert::is_transmutable::(); - | ^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u32` + | ^^^^^^ `V0u16` cannot be safely transmuted into `u32` in the defining scope of `n16::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u32` note: required by a bound in `is_transmutable` --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 | @@ -118,12 +126,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `V0i32: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u16` cannot be safely transmuted into `V0i32` in the defining scope of `n32::Context`. --> $DIR/primitive_reprs_should_have_correct_length.rs:89:44 | LL | assert::is_transmutable::(); - | ^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `V0i32` + | ^^^^^^^ `u16` cannot be safely transmuted into `V0i32` in the defining scope of `n32::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `V0i32` note: required by a bound in `is_transmutable` --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 | @@ -133,12 +142,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `u64: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `V0i32` cannot be safely transmuted into `u64` in the defining scope of `n32::Context`. --> $DIR/primitive_reprs_should_have_correct_length.rs:91:44 | LL | assert::is_transmutable::(); - | ^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u64` + | ^^^^^^ `V0i32` cannot be safely transmuted into `u64` in the defining scope of `n32::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u64` note: required by a bound in `is_transmutable` --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 | @@ -148,12 +158,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `V0u32: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u16` cannot be safely transmuted into `V0u32` in the defining scope of `n32::Context`. --> $DIR/primitive_reprs_should_have_correct_length.rs:97:44 | LL | assert::is_transmutable::(); - | ^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `V0u32` + | ^^^^^^^ `u16` cannot be safely transmuted into `V0u32` in the defining scope of `n32::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `V0u32` note: required by a bound in `is_transmutable` --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 | @@ -163,12 +174,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `u64: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `V0u32` cannot be safely transmuted into `u64` in the defining scope of `n32::Context`. --> $DIR/primitive_reprs_should_have_correct_length.rs:99:44 | LL | assert::is_transmutable::(); - | ^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u64` + | ^^^^^^ `V0u32` cannot be safely transmuted into `u64` in the defining scope of `n32::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u64` note: required by a bound in `is_transmutable` --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 | @@ -178,12 +190,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `V0i64: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u32` cannot be safely transmuted into `V0i64` in the defining scope of `n64::Context`. --> $DIR/primitive_reprs_should_have_correct_length.rs:113:44 | LL | assert::is_transmutable::(); - | ^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `V0i64` + | ^^^^^^^ `u32` cannot be safely transmuted into `V0i64` in the defining scope of `n64::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `V0i64` note: required by a bound in `is_transmutable` --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 | @@ -193,12 +206,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `u128: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `V0i64` cannot be safely transmuted into `u128` in the defining scope of `n64::Context`. --> $DIR/primitive_reprs_should_have_correct_length.rs:115:44 | LL | assert::is_transmutable::(); - | ^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u128` + | ^^^^^^ `V0i64` cannot be safely transmuted into `u128` in the defining scope of `n64::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u128` note: required by a bound in `is_transmutable` --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 | @@ -208,12 +222,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `V0u64: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u32` cannot be safely transmuted into `V0u64` in the defining scope of `n64::Context`. --> $DIR/primitive_reprs_should_have_correct_length.rs:121:44 | LL | assert::is_transmutable::(); - | ^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `V0u64` + | ^^^^^^^ `u32` cannot be safely transmuted into `V0u64` in the defining scope of `n64::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `V0u64` note: required by a bound in `is_transmutable` --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 | @@ -223,12 +238,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `u128: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `V0u64` cannot be safely transmuted into `u128` in the defining scope of `n64::Context`. --> $DIR/primitive_reprs_should_have_correct_length.rs:123:44 | LL | assert::is_transmutable::(); - | ^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u128` + | ^^^^^^ `V0u64` cannot be safely transmuted into `u128` in the defining scope of `n64::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u128` note: required by a bound in `is_transmutable` --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 | @@ -238,12 +254,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `V0isize: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u8` cannot be safely transmuted into `V0isize` in the defining scope of `nsize::Context`. --> $DIR/primitive_reprs_should_have_correct_length.rs:137:44 | LL | assert::is_transmutable::(); - | ^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `V0isize` + | ^^^^^^^ `u8` cannot be safely transmuted into `V0isize` in the defining scope of `nsize::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `V0isize` note: required by a bound in `is_transmutable` --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 | @@ -253,12 +270,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `[usize; 2]: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `V0isize` cannot be safely transmuted into `[usize; 2]` in the defining scope of `nsize::Context`. --> $DIR/primitive_reprs_should_have_correct_length.rs:139:44 | LL | assert::is_transmutable::(); - | ^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `[usize; 2]` + | ^^^^^^ `V0isize` cannot be safely transmuted into `[usize; 2]` in the defining scope of `nsize::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `[usize; 2]` note: required by a bound in `is_transmutable` --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 | @@ -268,12 +286,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `V0usize: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u8` cannot be safely transmuted into `V0usize` in the defining scope of `nsize::Context`. --> $DIR/primitive_reprs_should_have_correct_length.rs:145:44 | LL | assert::is_transmutable::(); - | ^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `V0usize` + | ^^^^^^^ `u8` cannot be safely transmuted into `V0usize` in the defining scope of `nsize::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `V0usize` note: required by a bound in `is_transmutable` --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 | @@ -283,12 +302,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `[usize; 2]: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `V0usize` cannot be safely transmuted into `[usize; 2]` in the defining scope of `nsize::Context`. --> $DIR/primitive_reprs_should_have_correct_length.rs:147:44 | LL | assert::is_transmutable::(); - | ^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `[usize; 2]` + | ^^^^^^ `V0usize` cannot be safely transmuted into `[usize; 2]` in the defining scope of `nsize::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `[usize; 2]` note: required by a bound in `is_transmutable` --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 | diff --git a/src/test/ui/transmutability/enums/repr/should_require_well_defined_layout.rs b/src/test/ui/transmutability/enums/repr/should_require_well_defined_layout.rs index 24a88d6ac95cc..978a12648f03a 100644 --- a/src/test/ui/transmutability/enums/repr/should_require_well_defined_layout.rs +++ b/src/test/ui/transmutability/enums/repr/should_require_well_defined_layout.rs @@ -18,20 +18,20 @@ mod assert { fn should_reject_repr_rust() { fn void() { enum repr_rust {} - assert::is_maybe_transmutable::(); //~ ERROR not satisfied - assert::is_maybe_transmutable::(); //~ ERROR not satisfied + assert::is_maybe_transmutable::(); //~ ERROR cannot be safely transmuted + assert::is_maybe_transmutable::(); //~ ERROR cannot be safely transmuted } fn singleton() { enum repr_rust { V } - assert::is_maybe_transmutable::(); //~ ERROR not satisfied - assert::is_maybe_transmutable::(); //~ ERROR not satisfied + assert::is_maybe_transmutable::(); //~ ERROR cannot be safely transmuted + assert::is_maybe_transmutable::(); //~ ERROR cannot be safely transmuted } fn duplex() { enum repr_rust { A, B } - assert::is_maybe_transmutable::(); //~ ERROR not satisfied - assert::is_maybe_transmutable::(); //~ ERROR not satisfied + assert::is_maybe_transmutable::(); //~ ERROR cannot be safely transmuted + assert::is_maybe_transmutable::(); //~ ERROR cannot be safely transmuted } } diff --git a/src/test/ui/transmutability/enums/repr/should_require_well_defined_layout.stderr b/src/test/ui/transmutability/enums/repr/should_require_well_defined_layout.stderr index 1bfbff68f06cb..3273e87c89ff4 100644 --- a/src/test/ui/transmutability/enums/repr/should_require_well_defined_layout.stderr +++ b/src/test/ui/transmutability/enums/repr/should_require_well_defined_layout.stderr @@ -1,9 +1,10 @@ -error[E0277]: the trait bound `(): BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `void::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`. --> $DIR/should_require_well_defined_layout.rs:21:52 | LL | assert::is_maybe_transmutable::(); - | ^^ the trait `BikeshedIntrinsicFrom` is not implemented for `()` + | ^^ `void::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `()` note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:14:14 | @@ -13,12 +14,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` -error[E0277]: the trait bound `void::repr_rust: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u128` cannot be safely transmuted into `void::repr_rust` in the defining scope of `assert::Context`. --> $DIR/should_require_well_defined_layout.rs:22:47 | LL | assert::is_maybe_transmutable::(); - | ^^^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `void::repr_rust` + | ^^^^^^^^^ `u128` cannot be safely transmuted into `void::repr_rust` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `void::repr_rust` note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:14:14 | @@ -28,12 +30,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` -error[E0277]: the trait bound `(): BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `singleton::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`. --> $DIR/should_require_well_defined_layout.rs:27:52 | LL | assert::is_maybe_transmutable::(); - | ^^ the trait `BikeshedIntrinsicFrom` is not implemented for `()` + | ^^ `singleton::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `()` note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:14:14 | @@ -43,12 +46,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` -error[E0277]: the trait bound `singleton::repr_rust: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u128` cannot be safely transmuted into `singleton::repr_rust` in the defining scope of `assert::Context`. --> $DIR/should_require_well_defined_layout.rs:28:47 | LL | assert::is_maybe_transmutable::(); - | ^^^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `singleton::repr_rust` + | ^^^^^^^^^ `u128` cannot be safely transmuted into `singleton::repr_rust` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `singleton::repr_rust` note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:14:14 | @@ -58,12 +62,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` -error[E0277]: the trait bound `(): BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `duplex::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`. --> $DIR/should_require_well_defined_layout.rs:33:52 | LL | assert::is_maybe_transmutable::(); - | ^^ the trait `BikeshedIntrinsicFrom` is not implemented for `()` + | ^^ `duplex::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `()` note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:14:14 | @@ -73,12 +78,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` -error[E0277]: the trait bound `duplex::repr_rust: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u128` cannot be safely transmuted into `duplex::repr_rust` in the defining scope of `assert::Context`. --> $DIR/should_require_well_defined_layout.rs:34:47 | LL | assert::is_maybe_transmutable::(); - | ^^^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `duplex::repr_rust` + | ^^^^^^^^^ `u128` cannot be safely transmuted into `duplex::repr_rust` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `duplex::repr_rust` note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:14:14 | diff --git a/src/test/ui/transmutability/enums/should_pad_variants.rs b/src/test/ui/transmutability/enums/should_pad_variants.rs index 87951586523de..466b6c8a15b52 100644 --- a/src/test/ui/transmutability/enums/should_pad_variants.rs +++ b/src/test/ui/transmutability/enums/should_pad_variants.rs @@ -36,5 +36,5 @@ fn should_pad_variants() { struct Context; // If the implementation (incorrectly) fails to pad `Lopsided::Smol` with // an uninitialized byte, this transmutation might be (wrongly) accepted: - assert::is_transmutable::(); //~ ERROR not satisfied + assert::is_transmutable::(); //~ ERROR cannot be safely transmuted } diff --git a/src/test/ui/transmutability/enums/should_pad_variants.stderr b/src/test/ui/transmutability/enums/should_pad_variants.stderr index b940ca077d4ad..429f7211d17a8 100644 --- a/src/test/ui/transmutability/enums/should_pad_variants.stderr +++ b/src/test/ui/transmutability/enums/should_pad_variants.stderr @@ -1,9 +1,10 @@ -error[E0277]: the trait bound `Dst: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `Src` cannot be safely transmuted into `Dst` in the defining scope of `should_pad_variants::Context`. --> $DIR/should_pad_variants.rs:39:36 | LL | assert::is_transmutable::(); - | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `Dst` + | ^^^ `Src` cannot be safely transmuted into `Dst` in the defining scope of `should_pad_variants::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `Dst` note: required by a bound in `is_transmutable` --> $DIR/should_pad_variants.rs:13:14 | diff --git a/src/test/ui/transmutability/enums/should_respect_endianness.rs b/src/test/ui/transmutability/enums/should_respect_endianness.rs index 9bab44e1d914f..67a3c4e94ba8f 100644 --- a/src/test/ui/transmutability/enums/should_respect_endianness.rs +++ b/src/test/ui/transmutability/enums/should_respect_endianness.rs @@ -29,5 +29,5 @@ mod assert { fn should_respect_endianness() { assert::is_transmutable::(); - assert::is_transmutable::(); //~ ERROR not satisfied + assert::is_transmutable::(); //~ ERROR cannot be safely transmuted } diff --git a/src/test/ui/transmutability/enums/should_respect_endianness.stderr b/src/test/ui/transmutability/enums/should_respect_endianness.stderr index 3f3335d4a1b8f..78023cb378aca 100644 --- a/src/test/ui/transmutability/enums/should_respect_endianness.stderr +++ b/src/test/ui/transmutability/enums/should_respect_endianness.stderr @@ -1,9 +1,10 @@ -error[E0277]: the trait bound `Unexpected: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `Src` cannot be safely transmuted into `Unexpected` in the defining scope of `assert::Context`. --> $DIR/should_respect_endianness.rs:32:36 | LL | assert::is_transmutable::(); - | ^^^^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `Unexpected` + | ^^^^^^^^^^ `Src` cannot be safely transmuted into `Unexpected` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `Unexpected` note: required by a bound in `is_transmutable` --> $DIR/should_respect_endianness.rs:15:14 | diff --git a/src/test/ui/transmutability/primitives/bool.rs b/src/test/ui/transmutability/primitives/bool.rs index 13cecd1d8b7ea..4f79bc2533708 100644 --- a/src/test/ui/transmutability/primitives/bool.rs +++ b/src/test/ui/transmutability/primitives/bool.rs @@ -19,7 +19,7 @@ mod assert { } fn contrast_with_u8() { - assert::is_transmutable::(); //~ ERROR not satisfied + assert::is_transmutable::(); //~ ERROR cannot be safely transmuted assert::is_maybe_transmutable::(); assert::is_transmutable::(); } diff --git a/src/test/ui/transmutability/primitives/bool.stderr b/src/test/ui/transmutability/primitives/bool.stderr index f05bb433ec844..dc740251c871e 100644 --- a/src/test/ui/transmutability/primitives/bool.stderr +++ b/src/test/ui/transmutability/primitives/bool.stderr @@ -1,9 +1,10 @@ -error[E0277]: the trait bound `bool: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u8` cannot be safely transmuted into `bool` in the defining scope of `assert::Context`. --> $DIR/bool.rs:22:35 | LL | assert::is_transmutable::(); - | ^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `bool` + | ^^^^ `u8` cannot be safely transmuted into `bool` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `bool` note: required by a bound in `is_transmutable` --> $DIR/bool.rs:12:14 | diff --git a/src/test/ui/transmutability/primitives/numbers.rs b/src/test/ui/transmutability/primitives/numbers.rs index 3dbdfab9686a8..a5f79065d8aad 100644 --- a/src/test/ui/transmutability/primitives/numbers.rs +++ b/src/test/ui/transmutability/primitives/numbers.rs @@ -59,70 +59,70 @@ fn should_be_bitransmutable() { } fn should_reject_extension() { - assert::is_transmutable::< i8, i16>(); //~ ERROR not satisfied - assert::is_transmutable::< i8, u16>(); //~ ERROR not satisfied - assert::is_transmutable::< i8, i32>(); //~ ERROR not satisfied - assert::is_transmutable::< i8, f32>(); //~ ERROR not satisfied - assert::is_transmutable::< i8, u32>(); //~ ERROR not satisfied - assert::is_transmutable::< i8, u64>(); //~ ERROR not satisfied - assert::is_transmutable::< i8, i64>(); //~ ERROR not satisfied - assert::is_transmutable::< i8, f64>(); //~ ERROR not satisfied - assert::is_transmutable::< i8, u128>(); //~ ERROR not satisfied - assert::is_transmutable::< i8, i128>(); //~ ERROR not satisfied - - assert::is_transmutable::< u8, i16>(); //~ ERROR not satisfied - assert::is_transmutable::< u8, u16>(); //~ ERROR not satisfied - assert::is_transmutable::< u8, i32>(); //~ ERROR not satisfied - assert::is_transmutable::< u8, f32>(); //~ ERROR not satisfied - assert::is_transmutable::< u8, u32>(); //~ ERROR not satisfied - assert::is_transmutable::< u8, u64>(); //~ ERROR not satisfied - assert::is_transmutable::< u8, i64>(); //~ ERROR not satisfied - assert::is_transmutable::< u8, f64>(); //~ ERROR not satisfied - assert::is_transmutable::< u8, u128>(); //~ ERROR not satisfied - assert::is_transmutable::< u8, i128>(); //~ ERROR not satisfied - - assert::is_transmutable::< i16, i32>(); //~ ERROR not satisfied - assert::is_transmutable::< i16, f32>(); //~ ERROR not satisfied - assert::is_transmutable::< i16, u32>(); //~ ERROR not satisfied - assert::is_transmutable::< i16, u64>(); //~ ERROR not satisfied - assert::is_transmutable::< i16, i64>(); //~ ERROR not satisfied - assert::is_transmutable::< i16, f64>(); //~ ERROR not satisfied - assert::is_transmutable::< i16, u128>(); //~ ERROR not satisfied - assert::is_transmutable::< i16, i128>(); //~ ERROR not satisfied - - assert::is_transmutable::< u16, i32>(); //~ ERROR not satisfied - assert::is_transmutable::< u16, f32>(); //~ ERROR not satisfied - assert::is_transmutable::< u16, u32>(); //~ ERROR not satisfied - assert::is_transmutable::< u16, u64>(); //~ ERROR not satisfied - assert::is_transmutable::< u16, i64>(); //~ ERROR not satisfied - assert::is_transmutable::< u16, f64>(); //~ ERROR not satisfied - assert::is_transmutable::< u16, u128>(); //~ ERROR not satisfied - assert::is_transmutable::< u16, i128>(); //~ ERROR not satisfied - - assert::is_transmutable::< i32, u64>(); //~ ERROR not satisfied - assert::is_transmutable::< i32, i64>(); //~ ERROR not satisfied - assert::is_transmutable::< i32, f64>(); //~ ERROR not satisfied - assert::is_transmutable::< i32, u128>(); //~ ERROR not satisfied - assert::is_transmutable::< i32, i128>(); //~ ERROR not satisfied - - assert::is_transmutable::< f32, u64>(); //~ ERROR not satisfied - assert::is_transmutable::< f32, i64>(); //~ ERROR not satisfied - assert::is_transmutable::< f32, f64>(); //~ ERROR not satisfied - assert::is_transmutable::< f32, u128>(); //~ ERROR not satisfied - assert::is_transmutable::< f32, i128>(); //~ ERROR not satisfied - - assert::is_transmutable::< u32, u64>(); //~ ERROR not satisfied - assert::is_transmutable::< u32, i64>(); //~ ERROR not satisfied - assert::is_transmutable::< u32, f64>(); //~ ERROR not satisfied - assert::is_transmutable::< u32, u128>(); //~ ERROR not satisfied - assert::is_transmutable::< u32, i128>(); //~ ERROR not satisfied - - assert::is_transmutable::< u64, u128>(); //~ ERROR not satisfied - assert::is_transmutable::< u64, i128>(); //~ ERROR not satisfied - - assert::is_transmutable::< i64, u128>(); //~ ERROR not satisfied - assert::is_transmutable::< i64, i128>(); //~ ERROR not satisfied - - assert::is_transmutable::< f64, u128>(); //~ ERROR not satisfied - assert::is_transmutable::< f64, i128>(); //~ ERROR not satisfied + assert::is_transmutable::< i8, i16>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< i8, u16>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< i8, i32>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< i8, f32>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< i8, u32>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< i8, u64>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< i8, i64>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< i8, f64>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< i8, u128>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< i8, i128>(); //~ ERROR cannot be safely transmuted + + assert::is_transmutable::< u8, i16>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< u8, u16>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< u8, i32>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< u8, f32>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< u8, u32>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< u8, u64>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< u8, i64>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< u8, f64>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< u8, u128>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< u8, i128>(); //~ ERROR cannot be safely transmuted + + assert::is_transmutable::< i16, i32>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< i16, f32>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< i16, u32>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< i16, u64>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< i16, i64>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< i16, f64>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< i16, u128>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< i16, i128>(); //~ ERROR cannot be safely transmuted + + assert::is_transmutable::< u16, i32>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< u16, f32>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< u16, u32>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< u16, u64>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< u16, i64>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< u16, f64>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< u16, u128>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< u16, i128>(); //~ ERROR cannot be safely transmuted + + assert::is_transmutable::< i32, u64>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< i32, i64>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< i32, f64>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< i32, u128>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< i32, i128>(); //~ ERROR cannot be safely transmuted + + assert::is_transmutable::< f32, u64>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< f32, i64>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< f32, f64>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< f32, u128>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< f32, i128>(); //~ ERROR cannot be safely transmuted + + assert::is_transmutable::< u32, u64>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< u32, i64>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< u32, f64>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< u32, u128>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< u32, i128>(); //~ ERROR cannot be safely transmuted + + assert::is_transmutable::< u64, u128>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< u64, i128>(); //~ ERROR cannot be safely transmuted + + assert::is_transmutable::< i64, u128>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< i64, i128>(); //~ ERROR cannot be safely transmuted + + assert::is_transmutable::< f64, u128>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< f64, i128>(); //~ ERROR cannot be safely transmuted } diff --git a/src/test/ui/transmutability/primitives/numbers.stderr b/src/test/ui/transmutability/primitives/numbers.stderr index 6bd3379dfd1a4..9b802a444e86a 100644 --- a/src/test/ui/transmutability/primitives/numbers.stderr +++ b/src/test/ui/transmutability/primitives/numbers.stderr @@ -1,9 +1,10 @@ -error[E0277]: the trait bound `i16: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `i8` cannot be safely transmuted into `i16` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:62:40 | LL | assert::is_transmutable::< i8, i16>(); - | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i16` + | ^^^ `i8` cannot be safely transmuted into `i16` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i16` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -13,12 +14,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `u16: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `i8` cannot be safely transmuted into `u16` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:63:40 | LL | assert::is_transmutable::< i8, u16>(); - | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u16` + | ^^^ `i8` cannot be safely transmuted into `u16` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u16` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -28,12 +30,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `i32: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `i8` cannot be safely transmuted into `i32` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:64:40 | LL | assert::is_transmutable::< i8, i32>(); - | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i32` + | ^^^ `i8` cannot be safely transmuted into `i32` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i32` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -43,12 +46,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `f32: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `i8` cannot be safely transmuted into `f32` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:65:40 | LL | assert::is_transmutable::< i8, f32>(); - | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `f32` + | ^^^ `i8` cannot be safely transmuted into `f32` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `f32` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -58,12 +62,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `u32: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `i8` cannot be safely transmuted into `u32` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:66:40 | LL | assert::is_transmutable::< i8, u32>(); - | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u32` + | ^^^ `i8` cannot be safely transmuted into `u32` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u32` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -73,12 +78,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `u64: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `i8` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:67:40 | LL | assert::is_transmutable::< i8, u64>(); - | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u64` + | ^^^ `i8` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u64` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -88,12 +94,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `i64: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `i8` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:68:40 | LL | assert::is_transmutable::< i8, i64>(); - | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i64` + | ^^^ `i8` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i64` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -103,12 +110,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `f64: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `i8` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:69:40 | LL | assert::is_transmutable::< i8, f64>(); - | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `f64` + | ^^^ `i8` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `f64` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -118,12 +126,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `u128: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `i8` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:70:39 | LL | assert::is_transmutable::< i8, u128>(); - | ^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u128` + | ^^^^ `i8` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u128` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -133,12 +142,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `i128: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `i8` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:71:39 | LL | assert::is_transmutable::< i8, i128>(); - | ^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i128` + | ^^^^ `i8` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i128` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -148,12 +158,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `i16: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u8` cannot be safely transmuted into `i16` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:73:40 | LL | assert::is_transmutable::< u8, i16>(); - | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i16` + | ^^^ `u8` cannot be safely transmuted into `i16` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i16` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -163,12 +174,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `u16: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u8` cannot be safely transmuted into `u16` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:74:40 | LL | assert::is_transmutable::< u8, u16>(); - | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u16` + | ^^^ `u8` cannot be safely transmuted into `u16` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u16` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -178,12 +190,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `i32: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u8` cannot be safely transmuted into `i32` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:75:40 | LL | assert::is_transmutable::< u8, i32>(); - | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i32` + | ^^^ `u8` cannot be safely transmuted into `i32` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i32` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -193,12 +206,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `f32: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u8` cannot be safely transmuted into `f32` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:76:40 | LL | assert::is_transmutable::< u8, f32>(); - | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `f32` + | ^^^ `u8` cannot be safely transmuted into `f32` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `f32` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -208,12 +222,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `u32: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u8` cannot be safely transmuted into `u32` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:77:40 | LL | assert::is_transmutable::< u8, u32>(); - | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u32` + | ^^^ `u8` cannot be safely transmuted into `u32` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u32` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -223,12 +238,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `u64: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u8` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:78:40 | LL | assert::is_transmutable::< u8, u64>(); - | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u64` + | ^^^ `u8` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u64` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -238,12 +254,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `i64: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u8` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:79:40 | LL | assert::is_transmutable::< u8, i64>(); - | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i64` + | ^^^ `u8` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i64` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -253,12 +270,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `f64: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u8` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:80:40 | LL | assert::is_transmutable::< u8, f64>(); - | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `f64` + | ^^^ `u8` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `f64` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -268,12 +286,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `u128: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u8` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:81:39 | LL | assert::is_transmutable::< u8, u128>(); - | ^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u128` + | ^^^^ `u8` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u128` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -283,12 +302,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `i128: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u8` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:82:39 | LL | assert::is_transmutable::< u8, i128>(); - | ^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i128` + | ^^^^ `u8` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i128` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -298,12 +318,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `i32: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `i16` cannot be safely transmuted into `i32` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:84:40 | LL | assert::is_transmutable::< i16, i32>(); - | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i32` + | ^^^ `i16` cannot be safely transmuted into `i32` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i32` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -313,12 +334,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `f32: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `i16` cannot be safely transmuted into `f32` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:85:40 | LL | assert::is_transmutable::< i16, f32>(); - | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `f32` + | ^^^ `i16` cannot be safely transmuted into `f32` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `f32` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -328,12 +350,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `u32: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `i16` cannot be safely transmuted into `u32` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:86:40 | LL | assert::is_transmutable::< i16, u32>(); - | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u32` + | ^^^ `i16` cannot be safely transmuted into `u32` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u32` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -343,12 +366,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `u64: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `i16` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:87:40 | LL | assert::is_transmutable::< i16, u64>(); - | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u64` + | ^^^ `i16` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u64` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -358,12 +382,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `i64: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `i16` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:88:40 | LL | assert::is_transmutable::< i16, i64>(); - | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i64` + | ^^^ `i16` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i64` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -373,12 +398,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `f64: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `i16` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:89:40 | LL | assert::is_transmutable::< i16, f64>(); - | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `f64` + | ^^^ `i16` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `f64` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -388,12 +414,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `u128: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `i16` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:90:39 | LL | assert::is_transmutable::< i16, u128>(); - | ^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u128` + | ^^^^ `i16` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u128` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -403,12 +430,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `i128: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `i16` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:91:39 | LL | assert::is_transmutable::< i16, i128>(); - | ^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i128` + | ^^^^ `i16` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i128` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -418,12 +446,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `i32: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u16` cannot be safely transmuted into `i32` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:93:40 | LL | assert::is_transmutable::< u16, i32>(); - | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i32` + | ^^^ `u16` cannot be safely transmuted into `i32` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i32` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -433,12 +462,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `f32: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u16` cannot be safely transmuted into `f32` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:94:40 | LL | assert::is_transmutable::< u16, f32>(); - | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `f32` + | ^^^ `u16` cannot be safely transmuted into `f32` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `f32` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -448,12 +478,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `u32: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u16` cannot be safely transmuted into `u32` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:95:40 | LL | assert::is_transmutable::< u16, u32>(); - | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u32` + | ^^^ `u16` cannot be safely transmuted into `u32` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u32` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -463,12 +494,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `u64: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u16` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:96:40 | LL | assert::is_transmutable::< u16, u64>(); - | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u64` + | ^^^ `u16` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u64` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -478,12 +510,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `i64: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u16` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:97:40 | LL | assert::is_transmutable::< u16, i64>(); - | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i64` + | ^^^ `u16` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i64` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -493,12 +526,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `f64: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u16` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:98:40 | LL | assert::is_transmutable::< u16, f64>(); - | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `f64` + | ^^^ `u16` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `f64` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -508,12 +542,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `u128: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u16` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:99:39 | LL | assert::is_transmutable::< u16, u128>(); - | ^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u128` + | ^^^^ `u16` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u128` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -523,12 +558,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `i128: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u16` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:100:39 | LL | assert::is_transmutable::< u16, i128>(); - | ^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i128` + | ^^^^ `u16` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i128` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -538,12 +574,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `u64: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `i32` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:102:40 | LL | assert::is_transmutable::< i32, u64>(); - | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u64` + | ^^^ `i32` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u64` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -553,12 +590,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `i64: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `i32` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:103:40 | LL | assert::is_transmutable::< i32, i64>(); - | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i64` + | ^^^ `i32` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i64` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -568,12 +606,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `f64: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `i32` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:104:40 | LL | assert::is_transmutable::< i32, f64>(); - | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `f64` + | ^^^ `i32` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `f64` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -583,12 +622,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `u128: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `i32` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:105:39 | LL | assert::is_transmutable::< i32, u128>(); - | ^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u128` + | ^^^^ `i32` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u128` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -598,12 +638,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `i128: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `i32` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:106:39 | LL | assert::is_transmutable::< i32, i128>(); - | ^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i128` + | ^^^^ `i32` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i128` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -613,12 +654,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `u64: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `f32` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:108:40 | LL | assert::is_transmutable::< f32, u64>(); - | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u64` + | ^^^ `f32` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u64` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -628,12 +670,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `i64: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `f32` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:109:40 | LL | assert::is_transmutable::< f32, i64>(); - | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i64` + | ^^^ `f32` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i64` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -643,12 +686,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `f64: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `f32` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:110:40 | LL | assert::is_transmutable::< f32, f64>(); - | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `f64` + | ^^^ `f32` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `f64` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -658,12 +702,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `u128: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `f32` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:111:39 | LL | assert::is_transmutable::< f32, u128>(); - | ^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u128` + | ^^^^ `f32` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u128` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -673,12 +718,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `i128: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `f32` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:112:39 | LL | assert::is_transmutable::< f32, i128>(); - | ^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i128` + | ^^^^ `f32` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i128` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -688,12 +734,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `u64: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u32` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:114:40 | LL | assert::is_transmutable::< u32, u64>(); - | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u64` + | ^^^ `u32` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u64` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -703,12 +750,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `i64: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u32` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:115:40 | LL | assert::is_transmutable::< u32, i64>(); - | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i64` + | ^^^ `u32` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i64` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -718,12 +766,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `f64: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u32` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:116:40 | LL | assert::is_transmutable::< u32, f64>(); - | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `f64` + | ^^^ `u32` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `f64` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -733,12 +782,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `u128: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u32` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:117:39 | LL | assert::is_transmutable::< u32, u128>(); - | ^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u128` + | ^^^^ `u32` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u128` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -748,12 +798,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `i128: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u32` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:118:39 | LL | assert::is_transmutable::< u32, i128>(); - | ^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i128` + | ^^^^ `u32` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i128` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -763,12 +814,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `u128: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u64` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:120:39 | LL | assert::is_transmutable::< u64, u128>(); - | ^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u128` + | ^^^^ `u64` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u128` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -778,12 +830,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `i128: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u64` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:121:39 | LL | assert::is_transmutable::< u64, i128>(); - | ^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i128` + | ^^^^ `u64` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i128` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -793,12 +846,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `u128: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `i64` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:123:39 | LL | assert::is_transmutable::< i64, u128>(); - | ^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u128` + | ^^^^ `i64` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u128` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -808,12 +862,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `i128: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `i64` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:124:39 | LL | assert::is_transmutable::< i64, i128>(); - | ^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i128` + | ^^^^ `i64` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i128` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -823,12 +878,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `u128: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `f64` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:126:39 | LL | assert::is_transmutable::< f64, u128>(); - | ^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u128` + | ^^^^ `f64` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u128` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -838,12 +894,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `i128: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `f64` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:127:39 | LL | assert::is_transmutable::< f64, i128>(); - | ^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i128` + | ^^^^ `f64` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i128` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | diff --git a/src/test/ui/transmutability/primitives/unit.rs b/src/test/ui/transmutability/primitives/unit.rs index a9c618188bf41..86d4740300dff 100644 --- a/src/test/ui/transmutability/primitives/unit.rs +++ b/src/test/ui/transmutability/primitives/unit.rs @@ -20,5 +20,5 @@ fn should_have_correct_size() { struct Context; assert::is_transmutable::<(), Zst, Context>(); assert::is_transmutable::(); - assert::is_transmutable::<(), u8, Context>(); //~ ERROR not satisfied + assert::is_transmutable::<(), u8, Context>(); //~ ERROR cannot be safely transmuted } diff --git a/src/test/ui/transmutability/primitives/unit.stderr b/src/test/ui/transmutability/primitives/unit.stderr index f602612feea93..cf27c0d17b337 100644 --- a/src/test/ui/transmutability/primitives/unit.stderr +++ b/src/test/ui/transmutability/primitives/unit.stderr @@ -1,9 +1,10 @@ -error[E0277]: the trait bound `u8: BikeshedIntrinsicFrom<(), should_have_correct_size::Context, true, true, true, true>` is not satisfied +error[E0277]: `()` cannot be safely transmuted into `u8` in the defining scope of `should_have_correct_size::Context`. --> $DIR/unit.rs:23:35 | LL | assert::is_transmutable::<(), u8, Context>(); - | ^^ the trait `BikeshedIntrinsicFrom<(), should_have_correct_size::Context, true, true, true, true>` is not implemented for `u8` + | ^^ `()` cannot be safely transmuted into `u8` in the defining scope of `should_have_correct_size::Context`. | + = help: the trait `BikeshedIntrinsicFrom<(), should_have_correct_size::Context, true, true, true, true>` is not implemented for `u8` note: required by a bound in `is_transmutable` --> $DIR/unit.rs:12:14 | diff --git a/src/test/ui/transmutability/references.rs b/src/test/ui/transmutability/references.rs index c7d24aaf1caa8..c6fd4c43e95c0 100644 --- a/src/test/ui/transmutability/references.rs +++ b/src/test/ui/transmutability/references.rs @@ -16,5 +16,5 @@ mod assert { fn not_yet_implemented() { #[repr(C)] struct Unit; - assert::is_maybe_transmutable::<&'static Unit, &'static Unit>(); //~ ERROR not satisfied + assert::is_maybe_transmutable::<&'static Unit, &'static Unit>(); //~ ERROR cannot be safely transmuted } diff --git a/src/test/ui/transmutability/references.stderr b/src/test/ui/transmutability/references.stderr index 7199e169e2977..17ffcf64177e3 100644 --- a/src/test/ui/transmutability/references.stderr +++ b/src/test/ui/transmutability/references.stderr @@ -1,9 +1,10 @@ -error[E0277]: the trait bound `&'static Unit: BikeshedIntrinsicFrom<&'static Unit, assert::Context, true, true, true, true>` is not satisfied +error[E0277]: `&'static Unit` cannot be safely transmuted into `&'static Unit` in the defining scope of `assert::Context`. --> $DIR/references.rs:19:52 | LL | assert::is_maybe_transmutable::<&'static Unit, &'static Unit>(); - | ^^^^^^^^^^^^^ the trait `BikeshedIntrinsicFrom<&'static Unit, assert::Context, true, true, true, true>` is not implemented for `&'static Unit` + | ^^^^^^^^^^^^^ `&'static Unit` cannot be safely transmuted into `&'static Unit` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom<&'static Unit, assert::Context, true, true, true, true>` is not implemented for `&'static Unit` note: required by a bound in `is_maybe_transmutable` --> $DIR/references.rs:13:14 | diff --git a/src/test/ui/transmutability/structs/repr/should_require_well_defined_layout.rs b/src/test/ui/transmutability/structs/repr/should_require_well_defined_layout.rs index 63419aceb6ce9..556be989dbc25 100644 --- a/src/test/ui/transmutability/structs/repr/should_require_well_defined_layout.rs +++ b/src/test/ui/transmutability/structs/repr/should_require_well_defined_layout.rs @@ -18,39 +18,39 @@ fn should_reject_repr_rust() { fn unit() { struct repr_rust; - assert::is_maybe_transmutable::(); //~ ERROR not satisfied - assert::is_maybe_transmutable::(); //~ ERROR not satisfied + assert::is_maybe_transmutable::(); //~ ERROR cannot be safely transmuted + assert::is_maybe_transmutable::(); //~ ERROR cannot be safely transmuted } fn tuple() { struct repr_rust(); - assert::is_maybe_transmutable::(); //~ ERROR not satisfied - assert::is_maybe_transmutable::(); //~ ERROR not satisfied + assert::is_maybe_transmutable::(); //~ ERROR cannot be safely transmuted + assert::is_maybe_transmutable::(); //~ ERROR cannot be safely transmuted } fn braces() { struct repr_rust{} - assert::is_maybe_transmutable::(); //~ ERROR not satisfied - assert::is_maybe_transmutable::(); //~ ERROR not satisfied + assert::is_maybe_transmutable::(); //~ ERROR cannot be safely transmuted + assert::is_maybe_transmutable::(); //~ ERROR cannot be safely transmuted } fn aligned() { #[repr(align(1))] struct repr_rust{} - assert::is_maybe_transmutable::(); //~ ERROR not satisfied - assert::is_maybe_transmutable::(); //~ ERROR not satisfied + assert::is_maybe_transmutable::(); //~ ERROR cannot be safely transmuted + assert::is_maybe_transmutable::(); //~ ERROR cannot be safely transmuted } fn packed() { #[repr(packed)] struct repr_rust{} - assert::is_maybe_transmutable::(); //~ ERROR not satisfied - assert::is_maybe_transmutable::(); //~ ERROR not satisfied + assert::is_maybe_transmutable::(); //~ ERROR cannot be safely transmuted + assert::is_maybe_transmutable::(); //~ ERROR cannot be safely transmuted } fn nested() { struct repr_rust; #[repr(C)] struct repr_c(repr_rust); - assert::is_maybe_transmutable::(); //~ ERROR not satisfied - assert::is_maybe_transmutable::(); //~ ERROR not satisfied + assert::is_maybe_transmutable::(); //~ ERROR cannot be safely transmuted + assert::is_maybe_transmutable::(); //~ ERROR cannot be safely transmuted } } diff --git a/src/test/ui/transmutability/structs/repr/should_require_well_defined_layout.stderr b/src/test/ui/transmutability/structs/repr/should_require_well_defined_layout.stderr index ab582dd668807..07355f7c2ad26 100644 --- a/src/test/ui/transmutability/structs/repr/should_require_well_defined_layout.stderr +++ b/src/test/ui/transmutability/structs/repr/should_require_well_defined_layout.stderr @@ -1,9 +1,10 @@ -error[E0277]: the trait bound `(): BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `should_reject_repr_rust::unit::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`. --> $DIR/should_require_well_defined_layout.rs:21:52 | LL | assert::is_maybe_transmutable::(); - | ^^ the trait `BikeshedIntrinsicFrom` is not implemented for `()` + | ^^ `should_reject_repr_rust::unit::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `()` note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:13:14 | @@ -13,12 +14,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` -error[E0277]: the trait bound `should_reject_repr_rust::unit::repr_rust: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u128` cannot be safely transmuted into `should_reject_repr_rust::unit::repr_rust` in the defining scope of `assert::Context`. --> $DIR/should_require_well_defined_layout.rs:22:47 | LL | assert::is_maybe_transmutable::(); - | ^^^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `should_reject_repr_rust::unit::repr_rust` + | ^^^^^^^^^ `u128` cannot be safely transmuted into `should_reject_repr_rust::unit::repr_rust` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `should_reject_repr_rust::unit::repr_rust` note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:13:14 | @@ -28,12 +30,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` -error[E0277]: the trait bound `(): BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `should_reject_repr_rust::tuple::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`. --> $DIR/should_require_well_defined_layout.rs:27:52 | LL | assert::is_maybe_transmutable::(); - | ^^ the trait `BikeshedIntrinsicFrom` is not implemented for `()` + | ^^ `should_reject_repr_rust::tuple::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `()` note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:13:14 | @@ -43,12 +46,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` -error[E0277]: the trait bound `should_reject_repr_rust::tuple::repr_rust: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u128` cannot be safely transmuted into `should_reject_repr_rust::tuple::repr_rust` in the defining scope of `assert::Context`. --> $DIR/should_require_well_defined_layout.rs:28:47 | LL | assert::is_maybe_transmutable::(); - | ^^^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `should_reject_repr_rust::tuple::repr_rust` + | ^^^^^^^^^ `u128` cannot be safely transmuted into `should_reject_repr_rust::tuple::repr_rust` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `should_reject_repr_rust::tuple::repr_rust` note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:13:14 | @@ -58,12 +62,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` -error[E0277]: the trait bound `(): BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `should_reject_repr_rust::braces::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`. --> $DIR/should_require_well_defined_layout.rs:33:52 | LL | assert::is_maybe_transmutable::(); - | ^^ the trait `BikeshedIntrinsicFrom` is not implemented for `()` + | ^^ `should_reject_repr_rust::braces::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `()` note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:13:14 | @@ -73,12 +78,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` -error[E0277]: the trait bound `should_reject_repr_rust::braces::repr_rust: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u128` cannot be safely transmuted into `should_reject_repr_rust::braces::repr_rust` in the defining scope of `assert::Context`. --> $DIR/should_require_well_defined_layout.rs:34:47 | LL | assert::is_maybe_transmutable::(); - | ^^^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `should_reject_repr_rust::braces::repr_rust` + | ^^^^^^^^^ `u128` cannot be safely transmuted into `should_reject_repr_rust::braces::repr_rust` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `should_reject_repr_rust::braces::repr_rust` note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:13:14 | @@ -88,12 +94,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` -error[E0277]: the trait bound `(): BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `aligned::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`. --> $DIR/should_require_well_defined_layout.rs:39:52 | LL | assert::is_maybe_transmutable::(); - | ^^ the trait `BikeshedIntrinsicFrom` is not implemented for `()` + | ^^ `aligned::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `()` note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:13:14 | @@ -103,12 +110,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` -error[E0277]: the trait bound `aligned::repr_rust: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u128` cannot be safely transmuted into `aligned::repr_rust` in the defining scope of `assert::Context`. --> $DIR/should_require_well_defined_layout.rs:40:47 | LL | assert::is_maybe_transmutable::(); - | ^^^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `aligned::repr_rust` + | ^^^^^^^^^ `u128` cannot be safely transmuted into `aligned::repr_rust` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `aligned::repr_rust` note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:13:14 | @@ -118,12 +126,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` -error[E0277]: the trait bound `(): BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `packed::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`. --> $DIR/should_require_well_defined_layout.rs:45:52 | LL | assert::is_maybe_transmutable::(); - | ^^ the trait `BikeshedIntrinsicFrom` is not implemented for `()` + | ^^ `packed::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `()` note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:13:14 | @@ -133,12 +142,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` -error[E0277]: the trait bound `packed::repr_rust: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u128` cannot be safely transmuted into `packed::repr_rust` in the defining scope of `assert::Context`. --> $DIR/should_require_well_defined_layout.rs:46:47 | LL | assert::is_maybe_transmutable::(); - | ^^^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `packed::repr_rust` + | ^^^^^^^^^ `u128` cannot be safely transmuted into `packed::repr_rust` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `packed::repr_rust` note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:13:14 | @@ -148,12 +158,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` -error[E0277]: the trait bound `(): BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `nested::repr_c` cannot be safely transmuted into `()` in the defining scope of `assert::Context`. --> $DIR/should_require_well_defined_layout.rs:52:49 | LL | assert::is_maybe_transmutable::(); - | ^^ the trait `BikeshedIntrinsicFrom` is not implemented for `()` + | ^^ `nested::repr_c` cannot be safely transmuted into `()` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `()` note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:13:14 | @@ -163,12 +174,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` -error[E0277]: the trait bound `nested::repr_c: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u128` cannot be safely transmuted into `nested::repr_c` in the defining scope of `assert::Context`. --> $DIR/should_require_well_defined_layout.rs:53:47 | LL | assert::is_maybe_transmutable::(); - | ^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `nested::repr_c` + | ^^^^^^ `u128` cannot be safely transmuted into `nested::repr_c` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `nested::repr_c` note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:13:14 | diff --git a/src/test/ui/transmutability/unions/repr/should_require_well_defined_layout.rs b/src/test/ui/transmutability/unions/repr/should_require_well_defined_layout.rs index d6e28d7f0db3f..cec8e389f444e 100644 --- a/src/test/ui/transmutability/unions/repr/should_require_well_defined_layout.rs +++ b/src/test/ui/transmutability/unions/repr/should_require_well_defined_layout.rs @@ -20,8 +20,8 @@ fn should_reject_repr_rust() a: u8 } - assert::is_maybe_transmutable::(); //~ ERROR not satisfied - assert::is_maybe_transmutable::(); //~ ERROR not satisfied + assert::is_maybe_transmutable::(); //~ ERROR cannot be safely transmuted + assert::is_maybe_transmutable::(); //~ ERROR cannot be safely transmuted } fn should_accept_repr_C() diff --git a/src/test/ui/transmutability/unions/repr/should_require_well_defined_layout.stderr b/src/test/ui/transmutability/unions/repr/should_require_well_defined_layout.stderr index c24193f9a6d77..2ed01b159ab0b 100644 --- a/src/test/ui/transmutability/unions/repr/should_require_well_defined_layout.stderr +++ b/src/test/ui/transmutability/unions/repr/should_require_well_defined_layout.stderr @@ -1,9 +1,10 @@ -error[E0277]: the trait bound `(): BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `should_reject_repr_rust::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`. --> $DIR/should_require_well_defined_layout.rs:23:48 | LL | assert::is_maybe_transmutable::(); - | ^^ the trait `BikeshedIntrinsicFrom` is not implemented for `()` + | ^^ `should_reject_repr_rust::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `()` note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:13:14 | @@ -13,12 +14,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` -error[E0277]: the trait bound `should_reject_repr_rust::repr_rust: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u128` cannot be safely transmuted into `should_reject_repr_rust::repr_rust` in the defining scope of `assert::Context`. --> $DIR/should_require_well_defined_layout.rs:24:43 | LL | assert::is_maybe_transmutable::(); - | ^^^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `should_reject_repr_rust::repr_rust` + | ^^^^^^^^^ `u128` cannot be safely transmuted into `should_reject_repr_rust::repr_rust` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `should_reject_repr_rust::repr_rust` note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:13:14 | diff --git a/src/test/ui/transmutability/unions/should_pad_variants.rs b/src/test/ui/transmutability/unions/should_pad_variants.rs index d4126693f9284..c4757900f9c3e 100644 --- a/src/test/ui/transmutability/unions/should_pad_variants.rs +++ b/src/test/ui/transmutability/unions/should_pad_variants.rs @@ -36,5 +36,5 @@ fn should_pad_variants() { struct Context; // If the implementation (incorrectly) fails to pad `Lopsided::smol` with // an uninitialized byte, this transmutation might be (wrongly) accepted: - assert::is_transmutable::(); //~ ERROR not satisfied + assert::is_transmutable::(); //~ ERROR cannot be safely transmuted } diff --git a/src/test/ui/transmutability/unions/should_pad_variants.stderr b/src/test/ui/transmutability/unions/should_pad_variants.stderr index b940ca077d4ad..429f7211d17a8 100644 --- a/src/test/ui/transmutability/unions/should_pad_variants.stderr +++ b/src/test/ui/transmutability/unions/should_pad_variants.stderr @@ -1,9 +1,10 @@ -error[E0277]: the trait bound `Dst: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `Src` cannot be safely transmuted into `Dst` in the defining scope of `should_pad_variants::Context`. --> $DIR/should_pad_variants.rs:39:36 | LL | assert::is_transmutable::(); - | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `Dst` + | ^^^ `Src` cannot be safely transmuted into `Dst` in the defining scope of `should_pad_variants::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `Dst` note: required by a bound in `is_transmutable` --> $DIR/should_pad_variants.rs:13:14 | diff --git a/src/test/ui/transmutability/unions/should_reject_contraction.rs b/src/test/ui/transmutability/unions/should_reject_contraction.rs index 34b31595193dd..e8138d0e046c5 100644 --- a/src/test/ui/transmutability/unions/should_reject_contraction.rs +++ b/src/test/ui/transmutability/unions/should_reject_contraction.rs @@ -32,5 +32,5 @@ fn test() { c: Ox01, } - assert::is_transmutable::(); //~ ERROR not satisfied + assert::is_transmutable::(); //~ ERROR cannot be safely transmuted } diff --git a/src/test/ui/transmutability/unions/should_reject_contraction.stderr b/src/test/ui/transmutability/unions/should_reject_contraction.stderr index 1465c3df22837..99f5890081728 100644 --- a/src/test/ui/transmutability/unions/should_reject_contraction.stderr +++ b/src/test/ui/transmutability/unions/should_reject_contraction.stderr @@ -1,9 +1,10 @@ -error[E0277]: the trait bound `Subset: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `Superset` cannot be safely transmuted into `Subset` in the defining scope of `assert::Context`. --> $DIR/should_reject_contraction.rs:35:41 | LL | assert::is_transmutable::(); - | ^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `Subset` + | ^^^^^^ `Superset` cannot be safely transmuted into `Subset` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `Subset` note: required by a bound in `is_transmutable` --> $DIR/should_reject_contraction.rs:13:14 | diff --git a/src/test/ui/transmutability/unions/should_reject_disjoint.rs b/src/test/ui/transmutability/unions/should_reject_disjoint.rs index b4b06c571315e..16160e29a5469 100644 --- a/src/test/ui/transmutability/unions/should_reject_disjoint.rs +++ b/src/test/ui/transmutability/unions/should_reject_disjoint.rs @@ -31,6 +31,6 @@ fn test() { c: Ox01, } - assert::is_maybe_transmutable::(); //~ ERROR not satisfied - assert::is_maybe_transmutable::(); //~ ERROR not satisfied + assert::is_maybe_transmutable::(); //~ ERROR cannot be safely transmuted + assert::is_maybe_transmutable::(); //~ ERROR cannot be safely transmuted } diff --git a/src/test/ui/transmutability/unions/should_reject_disjoint.stderr b/src/test/ui/transmutability/unions/should_reject_disjoint.stderr index a140f0c506b3b..5714e2bf320c5 100644 --- a/src/test/ui/transmutability/unions/should_reject_disjoint.stderr +++ b/src/test/ui/transmutability/unions/should_reject_disjoint.stderr @@ -1,9 +1,10 @@ -error[E0277]: the trait bound `B: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `A` cannot be safely transmuted into `B` in the defining scope of `assert::Context`. --> $DIR/should_reject_disjoint.rs:34:40 | LL | assert::is_maybe_transmutable::(); - | ^ the trait `BikeshedIntrinsicFrom` is not implemented for `B` + | ^ `A` cannot be safely transmuted into `B` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `B` note: required by a bound in `is_maybe_transmutable` --> $DIR/should_reject_disjoint.rs:13:14 | @@ -13,12 +14,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` -error[E0277]: the trait bound `A: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `B` cannot be safely transmuted into `A` in the defining scope of `assert::Context`. --> $DIR/should_reject_disjoint.rs:35:40 | LL | assert::is_maybe_transmutable::(); - | ^ the trait `BikeshedIntrinsicFrom` is not implemented for `A` + | ^ `B` cannot be safely transmuted into `A` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `A` note: required by a bound in `is_maybe_transmutable` --> $DIR/should_reject_disjoint.rs:13:14 | diff --git a/src/test/ui/transmutability/unions/should_reject_intersecting.rs b/src/test/ui/transmutability/unions/should_reject_intersecting.rs index 1ed7d2a0bd9a0..58e399fb96225 100644 --- a/src/test/ui/transmutability/unions/should_reject_intersecting.rs +++ b/src/test/ui/transmutability/unions/should_reject_intersecting.rs @@ -33,6 +33,6 @@ fn test() { b: OxFF, } - assert::is_transmutable::(); //~ ERROR not satisfied - assert::is_transmutable::(); //~ ERROR not satisfied + assert::is_transmutable::(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::(); //~ ERROR cannot be safely transmuted } diff --git a/src/test/ui/transmutability/unions/should_reject_intersecting.stderr b/src/test/ui/transmutability/unions/should_reject_intersecting.stderr index 43e642b569152..92689a5f828b4 100644 --- a/src/test/ui/transmutability/unions/should_reject_intersecting.stderr +++ b/src/test/ui/transmutability/unions/should_reject_intersecting.stderr @@ -1,9 +1,10 @@ -error[E0277]: the trait bound `B: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `A` cannot be safely transmuted into `B` in the defining scope of `assert::Context`. --> $DIR/should_reject_intersecting.rs:36:34 | LL | assert::is_transmutable::(); - | ^ the trait `BikeshedIntrinsicFrom` is not implemented for `B` + | ^ `A` cannot be safely transmuted into `B` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `B` note: required by a bound in `is_transmutable` --> $DIR/should_reject_intersecting.rs:14:14 | @@ -13,12 +14,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `A: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `B` cannot be safely transmuted into `A` in the defining scope of `assert::Context`. --> $DIR/should_reject_intersecting.rs:37:34 | LL | assert::is_transmutable::(); - | ^ the trait `BikeshedIntrinsicFrom` is not implemented for `A` + | ^ `B` cannot be safely transmuted into `A` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `A` note: required by a bound in `is_transmutable` --> $DIR/should_reject_intersecting.rs:14:14 | diff --git a/src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_field.rs b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_field.rs index 04cb6885887f4..fcf3f3a527805 100644 --- a/src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_field.rs +++ b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_field.rs @@ -33,5 +33,5 @@ mod dst { fn test() { struct Context; - assert::is_transmutable::(); //~ ERROR not satisfied + assert::is_transmutable::(); //~ ERROR cannot be safely transmuted } diff --git a/src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_field.stderr b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_field.stderr index 4dfbfaeafb648..85124019e7f03 100644 --- a/src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_field.stderr +++ b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_field.stderr @@ -1,9 +1,10 @@ -error[E0277]: the trait bound `Dst: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `Src` cannot be safely transmuted into `Dst` in the defining scope of `test::Context`. --> $DIR/should_reject_if_dst_has_private_field.rs:36:41 | LL | assert::is_transmutable::(); - | ^^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `Dst` + | ^^^^^^^^ `Src` cannot be safely transmuted into `Dst` in the defining scope of `test::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `Dst` note: required by a bound in `is_transmutable` --> $DIR/should_reject_if_dst_has_private_field.rs:13:14 | diff --git a/src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_variant.rs b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_variant.rs index 768e7bc559efe..566b56467124f 100644 --- a/src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_variant.rs +++ b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_variant.rs @@ -34,5 +34,5 @@ mod dst { fn test() { struct Context; - assert::is_transmutable::(); //~ ERROR not satisfied + assert::is_transmutable::(); //~ ERROR cannot be safely transmuted } diff --git a/src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_variant.stderr b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_variant.stderr index ed834a1bd2587..0be564d93e2d8 100644 --- a/src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_variant.stderr +++ b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_variant.stderr @@ -1,9 +1,10 @@ -error[E0277]: the trait bound `Dst: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `Src` cannot be safely transmuted into `Dst` in the defining scope of `test::Context`. --> $DIR/should_reject_if_dst_has_private_variant.rs:37:41 | LL | assert::is_transmutable::(); - | ^^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `Dst` + | ^^^^^^^^ `Src` cannot be safely transmuted into `Dst` in the defining scope of `test::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `Dst` note: required by a bound in `is_transmutable` --> $DIR/should_reject_if_dst_has_private_variant.rs:13:14 | diff --git a/src/test/ui/transmutability/visibility/should_reject_if_dst_has_tricky_unreachable_field.rs b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_tricky_unreachable_field.rs index c44fed4cce392..35fff5966c85b 100644 --- a/src/test/ui/transmutability/visibility/should_reject_if_dst_has_tricky_unreachable_field.rs +++ b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_tricky_unreachable_field.rs @@ -1,7 +1,7 @@ // check-pass //! NOTE: This test documents a known-bug in the implementation of the //! transmutability trait. Once fixed, the above "check-pass" header should be -//! removed, and an "ERROR not satisfied" annotation should be added at the end +//! removed, and an "ERROR cannot be safely transmuted" annotation should be added at the end //! of the line starting with `assert::is_transmutable`. //! //! Unless visibility is assumed, a transmutation should be rejected if the diff --git a/src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_field.rs b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_field.rs index dbef149bacc99..42799d803b028 100644 --- a/src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_field.rs +++ b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_field.rs @@ -35,5 +35,5 @@ mod dst { fn test() { struct Context; - assert::is_transmutable::(); //~ ERROR not satisfied + assert::is_transmutable::(); //~ ERROR cannot be safely transmuted } diff --git a/src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_field.stderr b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_field.stderr index 3029d6ab8eeee..95c68d452010b 100644 --- a/src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_field.stderr +++ b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_field.stderr @@ -1,9 +1,10 @@ -error[E0277]: the trait bound `Dst: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `Src` cannot be safely transmuted into `Dst` in the defining scope of `test::Context`. --> $DIR/should_reject_if_dst_has_unreachable_field.rs:38:41 | LL | assert::is_transmutable::(); - | ^^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `Dst` + | ^^^^^^^^ `Src` cannot be safely transmuted into `Dst` in the defining scope of `test::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `Dst` note: required by a bound in `is_transmutable` --> $DIR/should_reject_if_dst_has_unreachable_field.rs:15:14 | diff --git a/src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_ty.rs b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_ty.rs index c5947eceb656e..e13b32b30d964 100644 --- a/src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_ty.rs +++ b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_ty.rs @@ -38,5 +38,5 @@ fn test() { struct Context; assert::is_transmutable::(); //~^ ERROR `Dst` is private - //~| ERROR not satisfied + //~| ERROR cannot be safely transmuted } diff --git a/src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_ty.stderr b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_ty.stderr index 2fd3889032149..3391839e39e02 100644 --- a/src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_ty.stderr +++ b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_ty.stderr @@ -10,12 +10,13 @@ note: the struct `Dst` is defined here LL | #[repr(C)] pub(self) struct Dst { | ^^^^^^^^^^^^^^^^^^^^ -error[E0277]: the trait bound `Dst: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `Src` cannot be safely transmuted into `Dst` in the defining scope of `test::Context`. --> $DIR/should_reject_if_dst_has_unreachable_ty.rs:39:41 | LL | assert::is_transmutable::(); - | ^^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `Dst` + | ^^^^^^^^ `Src` cannot be safely transmuted into `Dst` in the defining scope of `test::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `Dst` note: required by a bound in `is_transmutable` --> $DIR/should_reject_if_dst_has_unreachable_ty.rs:15:14 | From b78c3daad0f0b7490988f4957bab7bc53049b3bb Mon Sep 17 00:00:00 2001 From: Jack Wrenn Date: Thu, 21 Jul 2022 18:18:36 +0000 Subject: [PATCH 14/19] safe transmute: reference tracking issue ref: https://github.com/rust-lang/rust/pull/92268#discussion_r925266769 --- library/core/src/mem/mod.rs | 2 +- library/core/src/mem/transmutability.rs | 4 ++-- .../feature-missing.rs | 3 +++ .../feature-missing.stderr | 12 +++++++++++- 4 files changed, 17 insertions(+), 4 deletions(-) diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index add65a3be5042..b1cf5bd92d252 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -28,7 +28,7 @@ mod valid_align; pub(crate) use valid_align::ValidAlign; mod transmutability; -#[unstable(feature = "transmutability", issue = "none")] +#[unstable(feature = "transmutability", issue = "99571")] pub use transmutability::{Assume, BikeshedIntrinsicFrom}; #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/core/src/mem/transmutability.rs b/library/core/src/mem/transmutability.rs index 820a7582b113b..b59a5b89d839f 100644 --- a/library/core/src/mem/transmutability.rs +++ b/library/core/src/mem/transmutability.rs @@ -3,7 +3,7 @@ /// This trait is implemented on-the-fly by the compiler for types `Src` and `Self` when the bits of /// any value of type `Self` are safely transmutable into a value of type `Dst`, in a given `Context`, /// notwithstanding whatever safety checks you have asked the compiler to [`Assume`] are satisfied. -#[unstable(feature = "transmutability", issue = "none")] +#[unstable(feature = "transmutability", issue = "99571")] #[cfg_attr(not(bootstrap), lang = "transmute_trait")] #[rustc_on_unimplemented( message = "`{Src}` cannot be safely transmuted into `{Self}` in the defining scope of `{Context}`.", @@ -22,7 +22,7 @@ pub unsafe trait BikeshedIntrinsicFrom< } /// What transmutation safety conditions shall the compiler assume that *you* are checking? -#[unstable(feature = "transmutability", issue = "none")] +#[unstable(feature = "transmutability", issue = "99571")] #[derive(PartialEq, Eq, Clone, Copy, Debug)] pub struct Assume { /// When `true`, the compiler assumes that *you* are ensuring (either dynamically or statically) that diff --git a/src/test/ui/transmutability/malformed-program-gracefulness/feature-missing.rs b/src/test/ui/transmutability/malformed-program-gracefulness/feature-missing.rs index 12018f3161a75..30c381745d0f9 100644 --- a/src/test/ui/transmutability/malformed-program-gracefulness/feature-missing.rs +++ b/src/test/ui/transmutability/malformed-program-gracefulness/feature-missing.rs @@ -4,3 +4,6 @@ use std::mem::BikeshedIntrinsicFrom; //~^ ERROR use of unstable library feature 'transmutability' [E0658] + +use std::mem::Assume; +//~^ ERROR use of unstable library feature 'transmutability' [E0658] diff --git a/src/test/ui/transmutability/malformed-program-gracefulness/feature-missing.stderr b/src/test/ui/transmutability/malformed-program-gracefulness/feature-missing.stderr index 4b51850634af1..ba8093f861465 100644 --- a/src/test/ui/transmutability/malformed-program-gracefulness/feature-missing.stderr +++ b/src/test/ui/transmutability/malformed-program-gracefulness/feature-missing.stderr @@ -4,8 +4,18 @@ error[E0658]: use of unstable library feature 'transmutability' LL | use std::mem::BikeshedIntrinsicFrom; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: see issue #99571 for more information = help: add `#![feature(transmutability)]` to the crate attributes to enable -error: aborting due to previous error +error[E0658]: use of unstable library feature 'transmutability' + --> $DIR/feature-missing.rs:8:5 + | +LL | use std::mem::Assume; + | ^^^^^^^^^^^^^^^^ + | + = note: see issue #99571 for more information + = help: add `#![feature(transmutability)]` to the crate attributes to enable + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0658`. From 226860304603f63440e9d097cd09dce45160bfbb Mon Sep 17 00:00:00 2001 From: Jack Wrenn Date: Thu, 21 Jul 2022 18:22:04 +0000 Subject: [PATCH 15/19] safe transmute: tweak `Nfa::union` to consume params by value ref: https://github.com/rust-lang/rust/pull/92268#discussion_r925274516 --- compiler/rustc_transmute/src/layout/nfa.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_transmute/src/layout/nfa.rs b/compiler/rustc_transmute/src/layout/nfa.rs index 817e426ba274e..3b2548e7aedf7 100644 --- a/compiler/rustc_transmute/src/layout/nfa.rs +++ b/compiler/rustc_transmute/src/layout/nfa.rs @@ -92,7 +92,7 @@ where let mut alts = alts.into_iter().map(Self::from_tree); let mut nfa = alts.next().ok_or(Uninhabited)??; for alt in alts { - nfa = nfa.union(&alt?); + nfa = nfa.union(alt?); } nfa } @@ -136,7 +136,7 @@ where } /// Compute the union of two `Nfa`s. - pub(crate) fn union(&self, other: &Self) -> Self { + pub(crate) fn union(self, other: Self) -> Self { let start = self.start; let accepting = self.accepting; From aee5f31c682664bd2e42be6b3fefdd3dd8a390e8 Mon Sep 17 00:00:00 2001 From: Jack Wrenn Date: Thu, 21 Jul 2022 21:57:51 +0000 Subject: [PATCH 16/19] safe transmute: lowercase tracing levels ref: https://github.com/rust-lang/rust/pull/92268#discussion_r927095154 --- compiler/rustc_transmute/src/layout/dfa.rs | 2 +- compiler/rustc_transmute/src/maybe_transmutable/mod.rs | 8 ++++---- .../src/maybe_transmutable/query_context.rs | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_transmute/src/layout/dfa.rs b/compiler/rustc_transmute/src/layout/dfa.rs index f2742dc8ee5ad..09a60cf6a626a 100644 --- a/compiler/rustc_transmute/src/layout/dfa.rs +++ b/compiler/rustc_transmute/src/layout/dfa.rs @@ -103,7 +103,7 @@ where Self { transitions, start, accepting } } - #[instrument(level = "DEBUG")] + #[instrument(level = "debug")] #[cfg_attr(feature = "rustc", allow(rustc::potential_query_instability))] pub(crate) fn from_nfa(nfa: Nfa) -> Self { let Nfa { transitions: nfa_transitions, start: nfa_start, accepting: nfa_accepting } = nfa; diff --git a/compiler/rustc_transmute/src/maybe_transmutable/mod.rs b/compiler/rustc_transmute/src/maybe_transmutable/mod.rs index 8fb85527a0f0a..076d922d1b72b 100644 --- a/compiler/rustc_transmute/src/maybe_transmutable/mod.rs +++ b/compiler/rustc_transmute/src/maybe_transmutable/mod.rs @@ -64,7 +64,7 @@ mod rustc { impl<'tcx> MaybeTransmutableQuery, TyCtxt<'tcx>> { /// This method begins by converting `src` and `dst` from `Ty`s to `Tree`s, /// then computes an answer using those trees. - #[instrument(level = "DEBUG", skip(self), fields(src = ?self.src, dst = ?self.dst))] + #[instrument(level = "debug", skip(self), fields(src = ?self.src, dst = ?self.dst))] pub fn answer(self) -> Answer< as QueryContext>::Ref> { let query_or_answer = self.map_layouts(|src, dst, scope, &context| { // Convert `src` and `dst` from their rustc representations, to `Tree`-based @@ -103,7 +103,7 @@ where /// This method begins by de-def'ing `src` and `dst`, and prunes private paths from `dst`, /// then converts `src` and `dst` to `Nfa`s, and computes an answer using those NFAs. #[inline(always)] - #[instrument(level = "DEBUG", skip(self), fields(src = ?self.src, dst = ?self.dst))] + #[instrument(level = "debug", skip(self), fields(src = ?self.src, dst = ?self.dst))] pub(crate) fn answer(self) -> Answer<::Ref> { let assume_visibility = self.assume.visibility; let query_or_answer = self.map_layouts(|src, dst, scope, context| { @@ -152,7 +152,7 @@ where /// /// This method converts `src` and `dst` to DFAs, then computes an answer using those DFAs. #[inline(always)] - #[instrument(level = "DEBUG", skip(self), fields(src = ?self.src, dst = ?self.dst))] + #[instrument(level = "debug", skip(self), fields(src = ?self.src, dst = ?self.dst))] pub(crate) fn answer(self) -> Answer<::Ref> { let query_or_answer = self .map_layouts(|src, dst, scope, context| Ok((Dfa::from_nfa(src), Dfa::from_nfa(dst)))); @@ -192,7 +192,7 @@ where } #[inline(always)] - #[instrument(level = "DEBUG", skip(self))] + #[instrument(level = "debug", skip(self))] fn answer_memo( &self, cache: &mut Map<(dfa::State, dfa::State), Answer<::Ref>>, diff --git a/compiler/rustc_transmute/src/maybe_transmutable/query_context.rs b/compiler/rustc_transmute/src/maybe_transmutable/query_context.rs index 1a66b6cfe00ef..9c2cf4c9a9238 100644 --- a/compiler/rustc_transmute/src/maybe_transmutable/query_context.rs +++ b/compiler/rustc_transmute/src/maybe_transmutable/query_context.rs @@ -52,7 +52,7 @@ mod rustc { type Scope = Ty<'tcx>; - #[instrument(level = "DEBUG", skip(self))] + #[instrument(level = "debug", skip(self))] fn is_accessible_from(&self, def: Self::Def, scope: Self::Scope) -> bool { use layout::rustc::Def; use rustc_middle::ty; From 8aca8835a0667c29e5d4af0c32bfae172c3b66fd Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Wed, 27 Jul 2022 11:04:54 -0700 Subject: [PATCH 17/19] rustdoc: remove Clean trait impl for ty::Term --- src/librustdoc/clean/mod.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 2f3ca41723d85..0c4851732f68b 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -398,12 +398,10 @@ fn clean_type_outlives_predicate<'tcx>( }) } -impl<'tcx> Clean<'tcx, Term> for ty::Term<'tcx> { - fn clean(&self, cx: &mut DocContext<'tcx>) -> Term { - match self { - ty::Term::Ty(ty) => Term::Type(clean_middle_ty(*ty, cx, None)), - ty::Term::Const(c) => Term::Constant(clean_middle_const(*c, cx)), - } +fn clean_middle_term<'tcx>(term: ty::Term<'tcx>, cx: &mut DocContext<'tcx>) -> Term { + match term { + ty::Term::Ty(ty) => Term::Type(clean_middle_ty(ty, cx, None)), + ty::Term::Const(c) => Term::Constant(clean_middle_const(c, cx)), } } @@ -426,7 +424,7 @@ fn clean_projection_predicate<'tcx>( let ty::ProjectionPredicate { projection_ty, term } = pred; WherePredicate::EqPredicate { lhs: clean_projection(projection_ty, cx, None), - rhs: term.clean(cx), + rhs: clean_middle_term(term, cx), } } @@ -1682,7 +1680,9 @@ pub(crate) fn clean_middle_ty<'tcx>( .projection_ty, cx, ), - kind: TypeBindingKind::Equality { term: pb.skip_binder().term.clean(cx) }, + kind: TypeBindingKind::Equality { + term: clean_middle_term(pb.skip_binder().term, cx), + }, }); } @@ -1746,7 +1746,7 @@ pub(crate) fn clean_middle_ty<'tcx>( Some(TypeBinding { assoc: projection_to_path_segment(proj.projection_ty, cx), kind: TypeBindingKind::Equality { - term: proj.term.clean(cx), + term: clean_middle_term(proj.term, cx), }, }) } else { From 3ea99166253021bd6f8c429b253d694572605bca Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Wed, 27 Jul 2022 11:08:22 -0700 Subject: [PATCH 18/19] rustdoc: remove Clean trait impl for hir::Term --- src/librustdoc/clean/mod.rs | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 0c4851732f68b..c7845172d48d6 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -405,14 +405,12 @@ fn clean_middle_term<'tcx>(term: ty::Term<'tcx>, cx: &mut DocContext<'tcx>) -> T } } -impl<'tcx> Clean<'tcx, Term> for hir::Term<'tcx> { - fn clean(&self, cx: &mut DocContext<'tcx>) -> Term { - match self { - hir::Term::Ty(ty) => Term::Type(clean_ty(ty, cx)), - hir::Term::Const(c) => { - let def_id = cx.tcx.hir().local_def_id(c.hir_id); - Term::Constant(clean_middle_const(ty::Const::from_anon_const(cx.tcx, def_id), cx)) - } +fn clean_hir_term<'tcx>(term: &hir::Term<'tcx>, cx: &mut DocContext<'tcx>) -> Term { + match term { + hir::Term::Ty(ty) => Term::Type(clean_ty(ty, cx)), + hir::Term::Const(c) => { + let def_id = cx.tcx.hir().local_def_id(c.hir_id); + Term::Constant(clean_middle_const(ty::Const::from_anon_const(cx.tcx, def_id), cx)) } } } @@ -2283,7 +2281,7 @@ impl<'tcx> Clean<'tcx, TypeBindingKind> for hir::TypeBindingKind<'tcx> { fn clean(&self, cx: &mut DocContext<'tcx>) -> TypeBindingKind { match *self { hir::TypeBindingKind::Equality { ref term } => { - TypeBindingKind::Equality { term: term.clean(cx) } + TypeBindingKind::Equality { term: clean_hir_term(term, cx) } } hir::TypeBindingKind::Constraint { bounds } => TypeBindingKind::Constraint { bounds: bounds.iter().filter_map(|b| b.clean(cx)).collect(), From 2f03cbdc8e51e6af9b4cc2ef99818e826e76e8ac Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Wed, 27 Jul 2022 11:13:39 -0700 Subject: [PATCH 19/19] rustdoc: remove Clean trait impl for ty::GenericParamDef --- src/librustdoc/clean/mod.rs | 81 ++++++++++++++++++------------------- 1 file changed, 39 insertions(+), 42 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index c7845172d48d6..2f2fbc9d4ba8d 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -470,47 +470,44 @@ fn projection_to_path_segment<'tcx>( } } -impl<'tcx> Clean<'tcx, GenericParamDef> for ty::GenericParamDef { - fn clean(&self, cx: &mut DocContext<'tcx>) -> GenericParamDef { - let (name, kind) = match self.kind { - ty::GenericParamDefKind::Lifetime => { - (self.name, GenericParamDefKind::Lifetime { outlives: vec![] }) - } - ty::GenericParamDefKind::Type { has_default, synthetic, .. } => { - let default = if has_default { - Some(clean_middle_ty(cx.tcx.type_of(self.def_id), cx, Some(self.def_id))) - } else { - None - }; - ( - self.name, - GenericParamDefKind::Type { - did: self.def_id, - bounds: vec![], // These are filled in from the where-clauses. - default: default.map(Box::new), - synthetic, - }, - ) - } - ty::GenericParamDefKind::Const { has_default } => ( - self.name, - GenericParamDefKind::Const { - did: self.def_id, - ty: Box::new(clean_middle_ty( - cx.tcx.type_of(self.def_id), - cx, - Some(self.def_id), - )), - default: match has_default { - true => Some(Box::new(cx.tcx.const_param_default(self.def_id).to_string())), - false => None, - }, +fn clean_generic_param_def<'tcx>( + def: &ty::GenericParamDef, + cx: &mut DocContext<'tcx>, +) -> GenericParamDef { + let (name, kind) = match def.kind { + ty::GenericParamDefKind::Lifetime => { + (def.name, GenericParamDefKind::Lifetime { outlives: vec![] }) + } + ty::GenericParamDefKind::Type { has_default, synthetic, .. } => { + let default = if has_default { + Some(clean_middle_ty(cx.tcx.type_of(def.def_id), cx, Some(def.def_id))) + } else { + None + }; + ( + def.name, + GenericParamDefKind::Type { + did: def.def_id, + bounds: vec![], // These are filled in from the where-clauses. + default: default.map(Box::new), + synthetic, }, - ), - }; + ) + } + ty::GenericParamDefKind::Const { has_default } => ( + def.name, + GenericParamDefKind::Const { + did: def.def_id, + ty: Box::new(clean_middle_ty(cx.tcx.type_of(def.def_id), cx, Some(def.def_id))), + default: match has_default { + true => Some(Box::new(cx.tcx.const_param_default(def.def_id).to_string())), + false => None, + }, + }, + ), + }; - GenericParamDef { name, kind } - } + GenericParamDef { name, kind } } fn clean_generic_param<'tcx>( @@ -668,7 +665,7 @@ fn clean_ty_generics<'tcx>( .iter() .filter_map(|param| match param.kind { ty::GenericParamDefKind::Lifetime if param.name == kw::UnderscoreLifetime => None, - ty::GenericParamDefKind::Lifetime => Some(param.clean(cx)), + ty::GenericParamDefKind::Lifetime => Some(clean_generic_param_def(param, cx)), ty::GenericParamDefKind::Type { synthetic, .. } => { if param.name == kw::SelfUpper { assert_eq!(param.index, 0); @@ -678,9 +675,9 @@ fn clean_ty_generics<'tcx>( impl_trait.insert(param.index.into(), vec![]); return None; } - Some(param.clean(cx)) + Some(clean_generic_param_def(param, cx)) } - ty::GenericParamDefKind::Const { .. } => Some(param.clean(cx)), + ty::GenericParamDefKind::Const { .. } => Some(clean_generic_param_def(param, cx)), }) .collect::>();