https://gcc.gnu.org/g:626812ff966a58fc5f233bbe5d4cdacc32a8db4f
commit r16-4865-g626812ff966a58fc5f233bbe5d4cdacc32a8db4f Author: Owen Avery <[email protected]> Date: Tue Sep 16 19:31:39 2025 -0400 gccrs: Improve FFIOpt Also fixes https://github.com/Rust-GCC/gccrs/issues/4171. gcc/rust/ChangeLog: * ast/rust-fmt.h (class FFIOpt): Adjust internal structure to match a repr(C) rust enum. libgrust/ChangeLog: * libformat_parser/src/lib.rs (struct FFIOpt): Likewise and remove some now-redundant methods. Signed-off-by: Owen Avery <[email protected]> Diff: --- gcc/rust/ast/rust-fmt.h | 77 +++++++++++++++++++++++---------- libgrust/libformat_parser/src/lib.rs | 84 ++++-------------------------------- 2 files changed, 63 insertions(+), 98 deletions(-) diff --git a/gcc/rust/ast/rust-fmt.h b/gcc/rust/ast/rust-fmt.h index c23499c3709a..e59bed3e9d29 100644 --- a/gcc/rust/ast/rust-fmt.h +++ b/gcc/rust/ast/rust-fmt.h @@ -83,38 +83,41 @@ public: const T *end () const { return data + len; } }; -template <typename T> class FFIOpt +// https://github.com/rust-lang/rfcs/blob/master/text/2195-really-tagged-unions.md +template <typename T, + typename = + typename std::enable_if<std::is_standard_layout<T>::value>::type> +class FFIOpt { - struct alignas (T) Inner - { - char data[sizeof (T)]; - } inner; - bool is_some; - public: - template <typename U> FFIOpt (U &&val) : is_some (true) - { - new (inner.data) T (std::forward<U> (val)); - } + template <typename U> + FFIOpt (U &&val) : some{Some::KIND, std::forward<U> (val)} + {} - FFIOpt () : is_some (false) {} + FFIOpt () : none{None::KIND} {} - FFIOpt (const FFIOpt &other) : is_some (other.is_some) + FFIOpt (const FFIOpt &other) { - if (is_some) - new (inner.data) T (*(const T *) other.inner.data); + if (other.has_value ()) + new (&some) Some{Some::KIND, other.some.val}; + else + new (&none) None{None::KIND}; } - FFIOpt (FFIOpt &&other) : is_some (other.is_some) + FFIOpt (FFIOpt &&other) { - if (is_some) - new (inner.data) T (std::move (*(const T *) other.inner.data)); + if (other.has_value ()) + new (&some) Some{Some::KIND, std::move (other.some.val)}; + else + new (&none) None{None::KIND}; } ~FFIOpt () { - if (is_some) - ((T *) inner.data)->~T (); + if (has_value ()) + some.~Some (); + else + none.~None (); } FFIOpt &operator= (const FFIOpt &other) @@ -133,13 +136,43 @@ public: tl::optional<std::reference_wrapper<T>> get_opt () { - return (T *) inner.data; + if (has_value ()) + return std::ref (some.val); + else + return tl::nullopt; } tl::optional<std::reference_wrapper<const T>> get_opt () const { - return (const T *) inner.data; + if (has_value ()) + return std::ref (some.val); + else + return tl::nullopt; } + + bool has_value () const { return some.kind == Some::KIND; } + + operator bool () const { return has_value (); } + +private: + struct Some + { + static constexpr uint8_t KIND = 0; + uint8_t kind; + T val; + }; + + struct None + { + static constexpr uint8_t KIND = 1; + uint8_t kind; + }; + + union + { + Some some; + None none; + }; }; struct RustHamster diff --git a/libgrust/libformat_parser/src/lib.rs b/libgrust/libformat_parser/src/lib.rs index 049403db0b7f..efb5d00f6784 100644 --- a/libgrust/libformat_parser/src/lib.rs +++ b/libgrust/libformat_parser/src/lib.rs @@ -83,87 +83,19 @@ pub mod ffi { } } - #[repr(C)] - pub struct FFIOpt<T> { - val: MaybeUninit<T>, - is_some: bool - } - - impl<T> Clone for FFIOpt<T> - where - T: Clone - { - fn clone(&self) -> Self { - match self.get_opt_ref() { - Some(r) => FFIOpt::new_val(r.clone()), - None => FFIOpt::new_none() - } - } - } - - impl<T> PartialEq for FFIOpt<T> - where - T: PartialEq - { - fn eq(&self, other: &Self) -> bool { - match (self.get_opt_ref(), other.get_opt_ref()) { - (Some(a), Some(b)) => a.eq(b), - _ => false - } - } - } - - impl<T> Eq for FFIOpt<T> - where - T: Eq - {} - - impl<T> Drop for FFIOpt<T> - { - fn drop(&mut self) { - if self.is_some { - unsafe { std::ptr::drop_in_place(self.val.as_mut_ptr()) } - } - } + // https://github.com/rust-lang/rfcs/blob/master/text/2195-really-tagged-unions.md + #[repr(u8)] + #[derive(Copy, Clone, PartialEq, Eq)] + pub enum FFIOpt<T> { + Some(T), + None } impl<T> IntoFFI<FFIOpt<T>> for Option<T> { fn into_ffi(self) -> FFIOpt<T> { match self { - Some(v) => FFIOpt::new_val(v), - None => FFIOpt::new_none() - } - } - } - - impl<T> FFIOpt<T> { - pub fn new_val(v: T) -> Self { - FFIOpt { - val: MaybeUninit::new(v), - is_some: true - } - } - - pub fn new_none() -> Self { - FFIOpt { - val: MaybeUninit::uninit(), - is_some: false - } - } - - pub fn get_opt_ref(&self) -> Option<&T> { - if self.is_some { - Some(unsafe {&*self.val.as_ptr()}) - } else { - None - } - } - - pub fn get_opt_ref_mut(&mut self) -> Option<&mut T> { - if self.is_some { - Some(unsafe {&mut *self.val.as_mut_ptr()}) - } else { - None + Some(v) => FFIOpt::Some(v), + None => FFIOpt::None } } }
