]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
gccrs: derive(Ord, Eq): Use different node IDs for variant paths
authorArthur Cohen <arthur.cohen@embecosm.com>
Tue, 10 Jun 2025 13:03:03 +0000 (15:03 +0200)
committerArthur Cohen <arthur.cohen@embecosm.com>
Tue, 5 Aug 2025 14:36:48 +0000 (16:36 +0200)
gcc/rust/ChangeLog:

* expand/rust-derive-cmp-common.cc (EnumMatchBuilder::tuple): Create two different
variant paths.
(EnumMatchBuilder::strukt): Likewise.
* expand/rust-derive-cmp-common.h: Change API.
* expand/rust-derive-ord.cc (DeriveOrd::visit_enum): Use new EnumMatchBuilder API.
* expand/rust-derive-partial-eq.cc (DerivePartialEq::visit_enum): Likewise.

gcc/testsuite/ChangeLog:

* rust/compile/derive_partial_ord1.rs: New test.

gcc/rust/expand/rust-derive-cmp-common.cc
gcc/rust/expand/rust-derive-cmp-common.h
gcc/rust/expand/rust-derive-ord.cc
gcc/rust/expand/rust-derive-partial-eq.cc
gcc/testsuite/rust/compile/derive_partial_ord1.rs [new file with mode: 0644]

index 83913784e971fd62795e96618c8c534082fd76e7..22ca16f17729f72a8af75136e9f5d204b9d0b213 100644 (file)
@@ -96,6 +96,10 @@ EnumMatchBuilder::tuple (EnumItem &variant_raw)
       });
     }
 
+  // TODO: Replace with `reconstruct()` instead of building these twice
+  auto self_variant_path = builder.variant_path (enum_path, variant_path);
+  auto other_variant_path = builder.variant_path (enum_path, variant_path);
+
   auto self_pattern_items = std::unique_ptr<TupleStructItems> (
     new TupleStructItemsNoRange (std::move (self_patterns)));
   auto other_pattern_items = std::unique_ptr<TupleStructItems> (
@@ -103,12 +107,12 @@ EnumMatchBuilder::tuple (EnumItem &variant_raw)
 
   auto self_pattern = std::unique_ptr<Pattern> (
     new ReferencePattern (std::unique_ptr<Pattern> (new TupleStructPattern (
-                           variant_path, std::move (self_pattern_items))),
-                         false, false, builder.loc));
-  auto other_pattern = std::unique_ptr<Pattern> (
-    new ReferencePattern (std::unique_ptr<Pattern> (new TupleStructPattern (
-                           variant_path, std::move (other_pattern_items))),
+                           self_variant_path, std::move (self_pattern_items))),
                          false, false, builder.loc));
+  auto other_pattern = std::unique_ptr<Pattern> (new ReferencePattern (
+    std::unique_ptr<Pattern> (new TupleStructPattern (
+      other_variant_path, std::move (other_pattern_items))),
+    false, false, builder.loc));
 
   auto tuple_items = std::make_unique<TuplePatternItemsMultiple> (
     vec (std::move (self_pattern), std::move (other_pattern)));
@@ -155,16 +159,21 @@ EnumMatchBuilder::strukt (EnumItem &variant_raw)
       });
     }
 
+  // TODO: Replace with `reconstruct()` instead of building these twice
+  auto self_variant_path = builder.variant_path (enum_path, variant_path);
+  auto other_variant_path = builder.variant_path (enum_path, variant_path);
+
   auto self_elts = StructPatternElements (std::move (self_fields));
   auto other_elts = StructPatternElements (std::move (other_fields));
 
-  auto self_pattern = std::unique_ptr<Pattern> (
-    new ReferencePattern (std::unique_ptr<Pattern> (new StructPattern (
-                           variant_path, builder.loc, std::move (self_elts))),
-                         false, false, builder.loc));
+  auto self_pattern = std::unique_ptr<Pattern> (new ReferencePattern (
+    std::unique_ptr<Pattern> (new StructPattern (self_variant_path, builder.loc,
+                                                std::move (self_elts))),
+    false, false, builder.loc));
   auto other_pattern = std::unique_ptr<Pattern> (
-    new ReferencePattern (std::unique_ptr<Pattern> (new StructPattern (
-                           variant_path, builder.loc, std::move (other_elts))),
+    new ReferencePattern (std::unique_ptr<Pattern> (
+                           new StructPattern (other_variant_path, builder.loc,
+                                              std::move (other_elts))),
                          false, false, builder.loc));
 
   auto tuple_items = std::make_unique<TuplePatternItemsMultiple> (
index 5902bb03b036e6ab5b4e4e3093d40ed5c0b46d9b..4efbed82aaa00b9e79d9bdc1cd466e627295ecc0 100644 (file)
@@ -65,8 +65,11 @@ public:
   using ExprFn
     = std::function<std::unique_ptr<Expr> (std::vector<SelfOther> &&)>;
 
-  EnumMatchBuilder (PathInExpression &variant_path, ExprFn fn, Builder &builder)
-    : variant_path (variant_path), fn (fn), builder (builder)
+  EnumMatchBuilder (const std::string &enum_path,
+                   const std::string &variant_path, ExprFn fn,
+                   Builder &builder)
+    : enum_path (enum_path), variant_path (variant_path), fn (fn),
+      builder (builder)
   {}
 
   /**
@@ -84,7 +87,8 @@ public:
   MatchCase strukt (EnumItem &variant);
 
 private:
-  PathInExpression &variant_path;
+  const std::string &enum_path;
+  const std::string &variant_path;
   ExprFn fn;
   Builder &builder;
 };
index dfc014446fa20bc371bf1e10d9d6db8bbb1a4a71..afc4b71676a145b4de6a64c36175071f8a74c837 100644 (file)
@@ -274,11 +274,9 @@ DeriveOrd::visit_enum (Enum &item)
 
   for (auto &variant : item.get_variants ())
     {
-      auto variant_path
-       = builder.variant_path (type_name,
-                               variant->get_identifier ().as_string ());
       auto enum_builder
-       = EnumMatchBuilder (variant_path, recursive_match_fn, builder);
+       = EnumMatchBuilder (type_name, variant->get_identifier ().as_string (),
+                           recursive_match_fn, builder);
 
       switch (variant->get_enum_item_kind ())
        {
index ea6a995c4f100fbc88a9121fa68fe5047067bb96..a0bf87a32ddbed573d83e656a36684499b32afd0 100644 (file)
@@ -287,11 +287,9 @@ DerivePartialEq::visit_enum (Enum &item)
 
   for (auto &variant : item.get_variants ())
     {
-      auto variant_path
-       = builder.variant_path (type_name,
-                               variant->get_identifier ().as_string ());
-
-      auto enum_builder = EnumMatchBuilder (variant_path, eq_expr_fn, builder);
+      auto enum_builder
+       = EnumMatchBuilder (type_name, variant->get_identifier ().as_string (),
+                           eq_expr_fn, builder);
 
       switch (variant->get_enum_item_kind ())
        {
diff --git a/gcc/testsuite/rust/compile/derive_partial_ord1.rs b/gcc/testsuite/rust/compile/derive_partial_ord1.rs
new file mode 100644 (file)
index 0000000..1f74b4d
--- /dev/null
@@ -0,0 +1,464 @@
+// { dg-additional-options "-frust-compile-until=typecheck" }
+
+#![feature(intrinsics)]
+
+mod core {
+    mod option {
+        // #[rustc_diagnostic_item = "option_type"]
+        #[stable(feature = "rust1", since = "1.0.0")]
+        pub enum Option<T> {
+            /// No value
+            #[lang = "None"]
+            #[stable(feature = "rust1", since = "1.0.0")]
+            None,
+            /// Some value `T`
+            #[lang = "Some"]
+            #[stable(feature = "rust1", since = "1.0.0")]
+            Some(#[stable(feature = "rust1", since = "1.0.0")] T),
+        }
+    }
+
+    mod marker {
+        #[lang = "phantom_data"]
+        #[stable(feature = "rust1", since = "1.0.0")]
+        pub struct PhantomData<T: ?Sized>;
+
+        #[unstable(feature = "structural_match", issue = "31434")]
+        // #[rustc_on_unimplemented(message = "the type `{Self}` does not `#[derive(PartialEq)]`")]
+        #[lang = "structural_peq"]
+        pub trait StructuralPartialEq {
+            // Empty.
+        }
+
+        #[unstable(feature = "structural_match", issue = "31434")]
+        // #[rustc_on_unimplemented(message = "the type `{Self}` does not `#[derive(Eq)]`")]
+        #[lang = "structural_teq"]
+        pub trait StructuralEq {
+            // Empty.
+        }
+
+        #[stable(feature = "rust1", since = "1.0.0")]
+        #[lang = "sized"]
+        // #[rustc_on_unimplemented(
+        //     message = "the size for values of type `{Self}` cannot be known at compilation time",
+        //     label = "doesn't have a size known at compile-time"
+        // )]
+        // #[fundamental] // for Default, for example, which requires that `[T]: !Default` be evaluatable
+        // #[rustc_specialization_trait]
+        pub trait Sized {
+            // Empty.
+        }
+    }
+
+    mod cmp {
+        use super::marker::Sized;
+        use super::option::Option;
+
+        // #[derive(Clone, Copy, PartialEq, Debug, Hash)]
+        #[stable(feature = "rust1", since = "1.0.0")]
+        pub enum Ordering {
+            /// An ordering where a compared value is less than another.
+            #[stable(feature = "rust1", since = "1.0.0")]
+            Less = -1,
+            /// An ordering where a compared value is equal to another.
+            #[stable(feature = "rust1", since = "1.0.0")]
+            Equal = 0,
+            /// An ordering where a compared value is greater than another.
+            #[stable(feature = "rust1", since = "1.0.0")]
+            Greater = 1,
+        }
+
+        #[lang = "eq"]
+        #[stable(feature = "rust1", since = "1.0.0")]
+        #[doc(alias = "==")]
+        #[doc(alias = "!=")]
+        // #[rustc_on_unimplemented(
+        //     message = "can't compare `{Self}` with `{Rhs}`",
+        //     label = "no implementation for `{Self} == {Rhs}`"
+        // )]
+        pub trait PartialEq<Rhs: ?Sized = Self> {
+            /// This method tests for `self` and `other` values to be equal, and is used
+            /// by `==`.
+            #[must_use]
+            #[stable(feature = "rust1", since = "1.0.0")]
+            fn eq(&self, other: &Rhs) -> bool;
+
+            fn ne(&self, other: &Rhs) -> bool {
+                !self.eq(other)
+            }
+        }
+
+        #[doc(alias = "==")]
+        #[doc(alias = "!=")]
+        #[stable(feature = "rust1", since = "1.0.0")]
+        pub trait Eq: PartialEq<Self> {
+            // this method is used solely by #[deriving] to assert
+            // that every component of a type implements #[deriving]
+            // itself, the current deriving infrastructure means doing this
+            // assertion without using a method on this trait is nearly
+            // impossible.
+            //
+            // This should never be implemented by hand.
+            #[doc(hidden)]
+            #[stable(feature = "rust1", since = "1.0.0")]
+            fn assert_receiver_is_total_eq(&self) {}
+        }
+
+        #[lang = "partial_ord"]
+        #[stable(feature = "rust1", since = "1.0.0")]
+        #[doc(alias = ">")]
+        #[doc(alias = "<")]
+        #[doc(alias = "<=")]
+        #[doc(alias = ">=")]
+        // #[rustc_on_unimplemented(
+        //     message = "can't compare `{Self}` with `{Rhs}`",
+        //     label = "no implementation for `{Self} < {Rhs}` and `{Self} > {Rhs}`"
+        // )]
+        pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> {
+            /// This method returns an ordering between `self` and `other` values if one exists.
+            ///
+            /// # Examples
+            ///
+            /// ```
+            /// use std::cmp::Ordering;
+            ///
+            /// let result = 1.0.partial_cmp(&2.0);
+            /// assert_eq!(result, Some(Ordering::Less));
+            ///
+            /// let result = 1.0.partial_cmp(&1.0);
+            /// assert_eq!(result, Some(Ordering::Equal));
+            ///
+            /// let result = 2.0.partial_cmp(&1.0);
+            /// assert_eq!(result, Some(Ordering::Greater));
+            /// ```
+            ///
+            /// When comparison is impossible:
+            ///
+            /// ```
+            /// let result = f64::NAN.partial_cmp(&1.0);
+            /// assert_eq!(result, None);
+            /// ```
+            #[must_use]
+            #[stable(feature = "rust1", since = "1.0.0")]
+            fn partial_cmp(&self, other: &Rhs) -> Option<Ordering>;
+
+            /// This method tests less than (for `self` and `other`) and is used by the `<` operator.
+            ///
+            /// # Examples
+            ///
+            /// ```
+            /// let result = 1.0 < 2.0;
+            /// assert_eq!(result, true);
+            ///
+            /// let result = 2.0 < 1.0;
+            /// assert_eq!(result, false);
+            /// ```
+            #[inline]
+            #[must_use]
+            #[stable(feature = "rust1", since = "1.0.0")]
+            fn lt(&self, other: &Rhs) -> bool {
+                match self.partial_cmp(other) {
+                    Option::Some(Ordering::Less) => true,
+                    _ => false,
+                }
+            }
+
+            /// This method tests less than or equal to (for `self` and `other`) and is used by the `<=`
+            /// operator.
+            ///
+            /// # Examples
+            ///
+            /// ```
+            /// let result = 1.0 <= 2.0;
+            /// assert_eq!(result, true);
+            ///
+            /// let result = 2.0 <= 2.0;
+            /// assert_eq!(result, true);
+            /// ```
+            #[inline]
+            #[must_use]
+            #[stable(feature = "rust1", since = "1.0.0")]
+            fn le(&self, other: &Rhs) -> bool {
+                match self.partial_cmp(other) {
+                    Option::Some(Ordering::Less | Ordering::Equal) => true,
+                    _ => false,
+                }
+            }
+
+            /// This method tests greater than (for `self` and `other`) and is used by the `>` operator.
+            ///
+            /// # Examples
+            ///
+            /// ```
+            /// let result = 1.0 > 2.0;
+            /// assert_eq!(result, false);
+            ///
+            /// let result = 2.0 > 2.0;
+            /// assert_eq!(result, false);
+            /// ```
+            #[inline]
+            #[must_use]
+            #[stable(feature = "rust1", since = "1.0.0")]
+            fn gt(&self, other: &Rhs) -> bool {
+                match self.partial_cmp(other) {
+                    Option::Some(Ordering::Greater) => true,
+                    _ => false,
+                }
+            }
+
+            /// This method tests greater than or equal to (for `self` and `other`) and is used by the `>=`
+            /// operator.
+            ///
+            /// # Examples
+            ///
+            /// ```
+            /// let result = 2.0 >= 1.0;
+            /// assert_eq!(result, true);
+            ///
+            /// let result = 2.0 >= 2.0;
+            /// assert_eq!(result, true);
+            /// ```
+            #[inline]
+            #[must_use]
+            #[stable(feature = "rust1", since = "1.0.0")]
+            fn ge(&self, other: &Rhs) -> bool {
+                match self.partial_cmp(other) {
+                    Option::Some(Ordering::Greater | Ordering::Equal) => true,
+                    _ => false,
+                }
+            }
+        }
+
+        #[doc(alias = "<")]
+        #[doc(alias = ">")]
+        #[doc(alias = "<=")]
+        #[doc(alias = ">=")]
+        #[stable(feature = "rust1", since = "1.0.0")]
+        pub trait Ord: Eq + PartialOrd<Self> {
+            /// This method returns an [`Ordering`] between `self` and `other`.
+            ///
+            /// By convention, `self.cmp(&other)` returns the ordering matching the expression
+            /// `self <operator> other` if true.
+            ///
+            /// # Examples
+            ///
+            /// ```
+            /// use std::cmp::Ordering;
+            ///
+            /// assert_eq!(5.cmp(&10), Ordering::Less);
+            /// assert_eq!(10.cmp(&5), Ordering::Greater);
+            /// assert_eq!(5.cmp(&5), Ordering::Equal);
+            /// ```
+            #[must_use]
+            #[stable(feature = "rust1", since = "1.0.0")]
+            fn cmp(&self, other: &Self) -> Ordering;
+
+            /// Compares and returns the maximum of two values.
+            ///
+            /// Returns the second argument if the comparison determines them to be equal.
+            ///
+            /// # Examples
+            ///
+            /// ```
+            /// assert_eq!(2, 1.max(2));
+            /// assert_eq!(2, 2.max(2));
+            /// ```
+            #[stable(feature = "ord_max_min", since = "1.21.0")]
+            #[must_use]
+            fn max(self, other: Self) -> Self
+            where
+                Self: Sized,
+            {
+                self
+            }
+
+            /// Compares and returns the minimum of two values.
+            ///
+            /// Returns the first argument if the comparison determines them to be equal.
+            ///
+            /// # Examples
+            ///
+            /// ```
+            /// assert_eq!(1, 1.min(2));
+            /// assert_eq!(2, 2.min(2));
+            /// ```
+            #[stable(feature = "ord_max_min", since = "1.21.0")]
+            #[must_use]
+            fn min(self, other: Self) -> Self
+            where
+                Self: Sized,
+            {
+                self
+            }
+
+            /// Restrict a value to a certain interval.
+            ///
+            /// Returns `max` if `self` is greater than `max`, and `min` if `self` is
+            /// less than `min`. Otherwise this returns `self`.
+            ///
+            /// # Panics
+            ///
+            /// Panics if `min > max`.
+            ///
+            /// # Examples
+            ///
+            /// ```
+            /// #![feature(clamp)]
+            ///
+            /// assert!((-3).clamp(-2, 1) == -2);
+            /// assert!(0.clamp(-2, 1) == 0);
+            /// assert!(2.clamp(-2, 1) == 1);
+            /// ```
+            #[must_use]
+            #[unstable(feature = "clamp", issue = "44095")]
+            fn clamp(self, min: Self, max: Self) -> Self
+            where
+                Self: Sized,
+            {
+                if self < min {
+                    min
+                } else if self > max {
+                    max
+                } else {
+                    self
+                }
+            }
+        }
+    }
+
+    pub mod intrinsics {
+        #[lang = "discriminant_kind"]
+        pub trait DiscriminantKind {
+            #[lang = "discriminant_type"]
+            type Discriminant;
+        }
+
+        extern "rust-intrinsic" {
+            pub fn discriminant_value<T>(v: &T) -> <T as DiscriminantKind>::Discriminant;
+        }
+    }
+}
+
+use core::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd};
+use core::marker::Sized;
+use core::option::Option;
+
+// for comparing discriminant_value
+impl PartialEq for isize {
+    fn eq(&self, other: &Self) -> bool {
+        *self == *other
+    }
+}
+
+// for comparing discriminant_value
+impl PartialOrd for isize {
+    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+        if *self > *other {
+            Option::Some(Ordering::Greater)
+        } else if *self < *other {
+            Option::Some(Ordering::Less)
+        } else {
+            Option::Some(Ordering::Equal)
+        }
+    }
+
+    fn lt(&self, other: &Self) -> bool {
+        *self < *other
+    }
+    fn le(&self, other: &Self) -> bool {
+        *self <= *other
+    }
+    fn ge(&self, other: &Self) -> bool {
+        *self >= *other
+    }
+    fn gt(&self, other: &Self) -> bool {
+        *self > *other
+    }
+}
+
+impl PartialEq for i32 {
+    fn eq(&self, other: &Self) -> bool {
+        *self == *other
+    }
+}
+
+impl PartialOrd for i32 {
+    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+        if *self > *other {
+            Option::Some(Ordering::Greater)
+        } else if *self < *other {
+            Option::Some(Ordering::Less)
+        } else {
+            Option::Some(Ordering::Equal)
+        }
+    }
+
+    fn lt(&self, other: &Self) -> bool {
+        *self < *other
+    }
+    fn le(&self, other: &Self) -> bool {
+        *self <= *other
+    }
+    fn ge(&self, other: &Self) -> bool {
+        *self >= *other
+    }
+    fn gt(&self, other: &Self) -> bool {
+        *self > *other
+    }
+}
+
+impl Ord for i32 {
+    fn cmp(&self, other: &Self) -> Ordering {
+        if *self > *other {
+            Ordering::Greater
+        } else if *self < *other {
+            Ordering::Less
+        } else {
+            Ordering::Equal
+        }
+    }
+}
+
+impl Eq for i32 {}
+
+#[derive(PartialEq, PartialOrd)]
+enum Foo {
+    A,
+    B(i32, i32, i32),
+    C { inner: i32, outer: i32 },
+}
+
+#[derive(Ord, PartialOrd, PartialEq, Eq)]
+struct Bar {
+    a: i32,
+}
+
+#[derive(Ord, PartialOrd, PartialEq, Eq)]
+struct BarFull {
+    a: i32,
+    b: i32,
+    c: i32,
+    d: i32,
+}
+
+extern "C" {
+    fn puts(s: *const i8);
+}
+
+fn print(s: &str) {
+    unsafe {
+        puts(s as *const str as *const i8);
+    }
+}
+
+fn main() {
+    let a = Foo::A;
+    let b = Foo::B(15, 14, 13);
+
+    match a.partial_cmp(&b) {
+        Option::Some(Ordering::Less) => print("less"),
+        Option::Some(Ordering::Greater) => print("greater"),
+        Option::Some(Ordering::Equal) => print("equal"),
+        _ => print("uuuuh woops lol"),
+    }
+}