Thanks for using Compiler Explorer
Sponsors
Jakt
C++
Ada
Algol68
Analysis
Android Java
Android Kotlin
Assembly
C
C3
Carbon
C with Coccinelle
C++ with Coccinelle
C++ (Circle)
CIRCT
Clean
CMake
CMakeScript
COBOL
C++ for OpenCL
MLIR
Cppx
Cppx-Blue
Cppx-Gold
Cpp2-cppfront
Crystal
C#
CUDA C++
D
Dart
Elixir
Erlang
Fortran
F#
GLSL
Go
Haskell
HLSL
Hook
Hylo
IL
ispc
Java
Julia
Kotlin
LLVM IR
LLVM MIR
Modula-2
Mojo
Nim
Numba
Nix
Objective-C
Objective-C++
OCaml
Odin
OpenCL C
Pascal
Pony
PTX
Python
Racket
Raku
Ruby
Rust
Sail
Snowball
Scala
Slang
Solidity
Spice
SPIR-V
Swift
LLVM TableGen
Toit
Triton
TypeScript Native
V
Vala
Visual Basic
Vyper
WASM
Zig
Javascript
GIMPLE
Ygen
sway
rust source #1
Output
Compile to binary object
Link to binary
Execute the code
Intel asm syntax
Demangle identifiers
Verbose demangling
Filters
Unused labels
Library functions
Directives
Comments
Horizontal whitespace
Debug intrinsics
Compiler
mrustc (master)
rustc 1.0.0
rustc 1.1.0
rustc 1.10.0
rustc 1.11.0
rustc 1.12.0
rustc 1.13.0
rustc 1.14.0
rustc 1.15.1
rustc 1.16.0
rustc 1.17.0
rustc 1.18.0
rustc 1.19.0
rustc 1.2.0
rustc 1.20.0
rustc 1.21.0
rustc 1.22.0
rustc 1.23.0
rustc 1.24.0
rustc 1.25.0
rustc 1.26.0
rustc 1.27.0
rustc 1.27.1
rustc 1.28.0
rustc 1.29.0
rustc 1.3.0
rustc 1.30.0
rustc 1.31.0
rustc 1.32.0
rustc 1.33.0
rustc 1.34.0
rustc 1.35.0
rustc 1.36.0
rustc 1.37.0
rustc 1.38.0
rustc 1.39.0
rustc 1.4.0
rustc 1.40.0
rustc 1.41.0
rustc 1.42.0
rustc 1.43.0
rustc 1.44.0
rustc 1.45.0
rustc 1.45.2
rustc 1.46.0
rustc 1.47.0
rustc 1.48.0
rustc 1.49.0
rustc 1.5.0
rustc 1.50.0
rustc 1.51.0
rustc 1.52.0
rustc 1.53.0
rustc 1.54.0
rustc 1.55.0
rustc 1.56.0
rustc 1.57.0
rustc 1.58.0
rustc 1.59.0
rustc 1.6.0
rustc 1.60.0
rustc 1.61.0
rustc 1.62.0
rustc 1.63.0
rustc 1.64.0
rustc 1.65.0
rustc 1.66.0
rustc 1.67.0
rustc 1.68.0
rustc 1.69.0
rustc 1.7.0
rustc 1.70.0
rustc 1.71.0
rustc 1.72.0
rustc 1.73.0
rustc 1.74.0
rustc 1.75.0
rustc 1.76.0
rustc 1.77.0
rustc 1.78.0
rustc 1.79.0
rustc 1.8.0
rustc 1.80.0
rustc 1.81.0
rustc 1.82.0
rustc 1.83.0
rustc 1.84.0
rustc 1.85.0
rustc 1.86.0
rustc 1.87.0
rustc 1.88.0
rustc 1.89.0
rustc 1.9.0
rustc beta
rustc nightly
rustc-cg-gcc (master)
x86-64 GCCRS (GCC master)
x86-64 GCCRS (GCCRS master)
x86-64 GCCRS 14.1 (GCC assertions)
x86-64 GCCRS 14.1 (GCC)
x86-64 GCCRS 14.2 (GCC assertions)
x86-64 GCCRS 14.2 (GCC)
x86-64 GCCRS 14.3 (GCC assertions)
x86-64 GCCRS 14.3 (GCC)
x86-64 GCCRS 15.1 (GCC assertions)
x86-64 GCCRS 15.1 (GCC)
x86-64 GCCRS 15.2 (GCC assertions)
x86-64 GCCRS 15.2 (GCC)
Options
Source code
#![allow(warnings)] extern crate core; use core::mem::MaybeUninit; /// A container which supports field projection of its contained type. /// /// `F` is the type of a field which can be projected into, and `W` is the wrapped version /// of that type; when projecting into a field of type `F`, the resulting value will be of type `W`, /// which is presumed to be equal to the container type instantiated with `F`. pub unsafe trait Projectable<F: ?Sized, W: ?Sized> { /// The inner type. type Inner: ?Sized; } unsafe impl<T, F> Projectable<F, MaybeUninit<F>> for MaybeUninit<T> { type Inner = T; } /// Performs field projection on `outer`, projecting into the field of type `F` /// at the address provided by `inner_to_field`. /// /// `outer_to_inner` and `field_to_wrapped_field` each perform only a /// raw pointer cast. These can't be performed inside of `project` because, /// in that context, the pointer types are generic, and so Rust doesn't know /// that fat pointer conversions are guaranteed to be valid (e.g., that we're /// never converting from a thin pointer to a fat pointer or between incompatible /// fat pointer types). In the context of `project!`, these types are concrete, /// and so this isn't an issue. #[doc(hidden)] #[inline(always)] pub fn project<P, F, W, OuterToInner, InnerToField, FieldToWrappedField>( _unsafe: unsafe_token::UnsafeToken, outer: &P, outer_to_inner: OuterToInner, inner_to_field: InnerToField, field_to_wrapped_field: FieldToWrappedField, ) -> &W where P: Projectable<F, W> + ?Sized, // NOTE: This bound will be unnecessary once `Unalign` is removed and // we support unsized types. P::Inner: Sized, F: ?Sized, W: ?Sized, OuterToInner: Fn(*const P) -> *const Unalign<P::Inner>, InnerToField: Fn(*const Unalign<P::Inner>) -> *const F, FieldToWrappedField: Fn(*const F) -> *const W, { let outer: *const P = outer; let inner = outer_to_inner(outer); let field = inner_to_field(inner); let wrapped_field = field_to_wrapped_field(field); unsafe { &*wrapped_field } } // `project_mut`, which is the mutable equivalent of `project`, is omitted for brevity /// Performs field projection. /// /// Given a wrapper, `w: W<T>`, and a field type in `T`, `f: F`, /// `project!(&w.f)` returns a reference to a `W<F>`. Any "place expression" /// on `w` is supported (`w.a.b.c`, `w[0]`, `w[3..5]`, etc). Mutable references /// are also supported. /// /// # Safety /// /// It is unsound to project using a sequence of accesses that invoke /// [`Deref::deref`] or [`DerefMut::deref_mut`]. #[macro_export] macro_rules! project { // Mutable versions of these matches are omitted for brevity. (&$c:ident $($f:tt)*) => { $crate::project!(&($c) $($f)*) }; (&($c:expr) $($f:tt)*) => {{ // This function does nothing, but is unsafe to call, and so has the // effect of requiring that the caller only invoke `project!` inside of // an `unsafe` block. $crate::promise_no_deref(); // We generate an `UnsafeToken` so that `project` can itself be // safe, and thus we don't need to wrap the entire call to `project` // in `unsafe { ... }`. This, in turn, is done so that the // meta-variables `$c` and `$($f)*` are not expanded inside of an // `unsafe { ... }`, which would allow safe Rust code to smuggle in // unsafe code via a call to `project!` without needing to write the // `unsafe` keyword. // // Note that this doesn't currently provide any benefits - the user // still has to write `unsafe` thanks to the call to `promise_no_deref` // - but this ensures that a future change in which we are able to // make this macro safe will have as small a diff as possible. let token = unsafe { $crate::unsafe_token::UnsafeToken::new() }; use ::core::borrow::Borrow as _; $crate::project( token, $c.borrow(), |outer| outer as *const _, |inner| if false { // This branch is never executed, but allows us to ensure that // `$($f)*` doesn't contain any unsafe code that isn't wrapped // in an `unsafe` block. If it does, then wrapping it in // `unsafe` - as we do in the `else` branch - would allow users // to write unsafe code without needing to write `unsafe`. // // The way we accomplish this is to generate a reference from // `inner` (which is a raw pointer). That allows us to extract // the unsafe operation of converting to a reference and wrap it // in `unsafe { ... }` on its own, while leaving the `$($f)*` // not wrapped in `unsafe { ... }`. Note that this is NOT sound // to execute in the general case, but that's okay because we're // in an `if false` branch. For example, if the wrapper type is // `#[repr(packed)]`, then `inner_ref` may not be validly // aligned, which is unsound. let inner_ref = unsafe { &*inner }; ::core::ptr::addr_of!(inner_ref .0 $($f)*) } else { unsafe { ::core::ptr::addr_of!((*inner) .0 $($f)* ) } }, |field| field as *const _, ) }}; } #[doc(hidden)] #[inline(always)] pub const unsafe fn promise_no_deref() {} #[doc(hidden)] #[repr(packed)] pub struct Unalign<T>(pub T); #[doc(hidden)] pub mod unsafe_token { /// A token used to prove that the `unsafe` keyword has been written /// somewhere. pub struct UnsafeToken(()); impl UnsafeToken { /// Constructs a new `UnsafeToken`. /// /// # Safety /// /// The caller is responsible for ensuring that they uphold the safety /// invariants of any APIs which consume this token. pub unsafe fn new() -> UnsafeToken { UnsafeToken(()) } } } pub fn project_maybe_uninit_tuple(m: &MaybeUninit<(u8, u16)>) -> &MaybeUninit<u16> { unsafe { project!(&m.1) } }
Become a Patron
Sponsor on GitHub
Donate via PayPal
Compiler Explorer Shop
Source on GitHub
Mailing list
Installed libraries
Wiki
Report an issue
How it works
Contact the author
CE on Mastodon
CE on Bluesky
Statistics
Changelog
Version tree