]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
gccrs: Improve FFIOpt
authorOwen Avery <powerboat9.gamer@gmail.com>
Tue, 16 Sep 2025 23:31:39 +0000 (19:31 -0400)
committerArthur Cohen <arthur.cohen@embecosm.com>
Thu, 30 Oct 2025 20:30:51 +0000 (21:30 +0100)
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 <powerboat9.gamer@gmail.com>
gcc/rust/ast/rust-fmt.h
libgrust/libformat_parser/src/lib.rs

index c23499c3709a0961f74fbb6381c8a7a78e718b7c..e59bed3e9d29a17e4eebce45aca434f192e98ded 100644 (file)
@@ -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
index 049403db0b7fb301eb543e3a61a6a0b86d2d4339..efb5d00f6784cd285142efe39dd0432a43d98860 100644 (file)
@@ -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
             }
         }
     }