From: Arthur Cohen Date: Tue, 10 Jun 2025 13:03:03 +0000 (+0200) Subject: gccrs: derive(Ord, Eq): Use different node IDs for variant paths X-Git-Url: http://git.ipfire.org/gitweb/gitweb.cgi?a=commitdiff_plain;h=cfd2dd925dadadc573d97ee624ed3f6bef94fbba;p=thirdparty%2Fgcc.git gccrs: derive(Ord, Eq): Use different node IDs for variant paths 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. --- diff --git a/gcc/rust/expand/rust-derive-cmp-common.cc b/gcc/rust/expand/rust-derive-cmp-common.cc index 83913784e97..22ca16f1772 100644 --- a/gcc/rust/expand/rust-derive-cmp-common.cc +++ b/gcc/rust/expand/rust-derive-cmp-common.cc @@ -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 ( new TupleStructItemsNoRange (std::move (self_patterns))); auto other_pattern_items = std::unique_ptr ( @@ -103,12 +107,12 @@ EnumMatchBuilder::tuple (EnumItem &variant_raw) auto self_pattern = std::unique_ptr ( new ReferencePattern (std::unique_ptr (new TupleStructPattern ( - variant_path, std::move (self_pattern_items))), - false, false, builder.loc)); - auto other_pattern = std::unique_ptr ( - new ReferencePattern (std::unique_ptr (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 (new ReferencePattern ( + std::unique_ptr (new TupleStructPattern ( + other_variant_path, std::move (other_pattern_items))), + false, false, builder.loc)); auto tuple_items = std::make_unique ( 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 ( - new ReferencePattern (std::unique_ptr (new StructPattern ( - variant_path, builder.loc, std::move (self_elts))), - false, false, builder.loc)); + auto self_pattern = std::unique_ptr (new ReferencePattern ( + std::unique_ptr (new StructPattern (self_variant_path, builder.loc, + std::move (self_elts))), + false, false, builder.loc)); auto other_pattern = std::unique_ptr ( - new ReferencePattern (std::unique_ptr (new StructPattern ( - variant_path, builder.loc, std::move (other_elts))), + new ReferencePattern (std::unique_ptr ( + new StructPattern (other_variant_path, builder.loc, + std::move (other_elts))), false, false, builder.loc)); auto tuple_items = std::make_unique ( diff --git a/gcc/rust/expand/rust-derive-cmp-common.h b/gcc/rust/expand/rust-derive-cmp-common.h index 5902bb03b03..4efbed82aaa 100644 --- a/gcc/rust/expand/rust-derive-cmp-common.h +++ b/gcc/rust/expand/rust-derive-cmp-common.h @@ -65,8 +65,11 @@ public: using ExprFn = std::function (std::vector &&)>; - 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; }; diff --git a/gcc/rust/expand/rust-derive-ord.cc b/gcc/rust/expand/rust-derive-ord.cc index dfc014446fa..afc4b71676a 100644 --- a/gcc/rust/expand/rust-derive-ord.cc +++ b/gcc/rust/expand/rust-derive-ord.cc @@ -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 ()) { diff --git a/gcc/rust/expand/rust-derive-partial-eq.cc b/gcc/rust/expand/rust-derive-partial-eq.cc index ea6a995c4f1..a0bf87a32dd 100644 --- a/gcc/rust/expand/rust-derive-partial-eq.cc +++ b/gcc/rust/expand/rust-derive-partial-eq.cc @@ -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 index 00000000000..1f74b4dc903 --- /dev/null +++ b/gcc/testsuite/rust/compile/derive_partial_ord1.rs @@ -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 { + /// 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; + + #[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 { + /// 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 { + // 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: PartialEq { + /// 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; + + /// 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 { + /// This method returns an [`Ordering`] between `self` and `other`. + /// + /// By convention, `self.cmp(&other)` returns the ordering matching the expression + /// `self 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(v: &T) -> ::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 { + 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 { + 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"), + } +}