https://gcc.gnu.org/g:1223585918cf691ebd0214f4c5134cbf355c54bc
commit r16-2878-g1223585918cf691ebd0214f4c5134cbf355c54bc Author: Philip Herron <herron.phi...@googlemail.com> Date: Tue Jun 17 11:32:21 2025 +0100 gccrs: Fix issues around PartialEq Eq Ord Partial Ord There is still an issue with derive on PartialOrd but this adds good tests and fixes a bug we had handling the default Rhs = Self generic type param substitutions on the comparison traits. gcc/rust/ChangeLog: * typecheck/rust-tyty.cc (ParamType::handle_substitions): make this consistent gcc/testsuite/ChangeLog: * rust/compile/bug-with-default-generic.rs: New test. * rust/execute/torture/partial-eq-1.rs: New test. * rust/execute/torture/partial-eq-2.rs: New test. * rust/execute/torture/partial-eq-3.rs: New test. * rust/execute/torture/partial-eq-4.rs: New test. * rust/execute/torture/partial-ord-1.rs: New test. * rust/execute/torture/partial-ord-2.rs: New test. * rust/execute/torture/partial-ord-3.rs: New test. * rust/execute/torture/partial-ord-4.rs: New test. * rust/execute/torture/partial-ord-5.rs: New test. Signed-off-by: Philip Herron <herron.phi...@googlemail.com> Diff: --- gcc/rust/typecheck/rust-tyty.cc | 10 +- .../rust/compile/bug-with-default-generic.rs | 15 + gcc/testsuite/rust/execute/torture/partial-eq-1.rs | 103 +++++ gcc/testsuite/rust/execute/torture/partial-eq-2.rs | 60 +++ gcc/testsuite/rust/execute/torture/partial-eq-3.rs | 457 +++++++++++++++++++ gcc/testsuite/rust/execute/torture/partial-eq-4.rs | 457 +++++++++++++++++++ .../rust/execute/torture/partial-ord-1.rs | 101 +++++ .../rust/execute/torture/partial-ord-2.rs | 469 ++++++++++++++++++++ .../rust/execute/torture/partial-ord-3.rs | 489 +++++++++++++++++++++ .../rust/execute/torture/partial-ord-4.rs | 115 +++++ .../rust/execute/torture/partial-ord-5.rs | 487 ++++++++++++++++++++ 11 files changed, 2758 insertions(+), 5 deletions(-) diff --git a/gcc/rust/typecheck/rust-tyty.cc b/gcc/rust/typecheck/rust-tyty.cc index 91c68efe972d..e2dfa743b9aa 100644 --- a/gcc/rust/typecheck/rust-tyty.cc +++ b/gcc/rust/typecheck/rust-tyty.cc @@ -3545,12 +3545,12 @@ ParamType::handle_substitions (SubstitutionArgumentMappings &subst_mappings) ParamType *p = static_cast<ParamType *> (clone ()); subst_mappings.on_param_subst (*p, arg); - // there are two cases one where we substitute directly to a new PARAM and - // otherwise - if (arg.get_tyty ()->get_kind () == TyTy::TypeKind::PARAM) + const BaseType *resolved = arg.get_tyty (); + if (resolved->get_kind () == TyTy::TypeKind::PARAM) { - p->set_ty_ref (arg.get_tyty ()->get_ref ()); - return p; + const ParamType &pp = *static_cast<const ParamType *> (resolved); + if (pp.can_resolve ()) + resolved = pp.resolve (); } // this is the new subst that this needs to pass diff --git a/gcc/testsuite/rust/compile/bug-with-default-generic.rs b/gcc/testsuite/rust/compile/bug-with-default-generic.rs new file mode 100644 index 000000000000..25f46a09c7dc --- /dev/null +++ b/gcc/testsuite/rust/compile/bug-with-default-generic.rs @@ -0,0 +1,15 @@ +#[lang = "sized"] +pub trait Sized {} + +pub trait MyBinaryTrait<Rhs = Self> { + fn do_something(&self, rhs: &Rhs); +} + +struct Foo<T> { + // { dg-warning "struct is never constructed" "" { target *-*-* } .-1 } + value: T, +} + +impl<T> MyBinaryTrait for Foo<T> { + fn do_something(&self, _rhs: &Self) {} +} diff --git a/gcc/testsuite/rust/execute/torture/partial-eq-1.rs b/gcc/testsuite/rust/execute/torture/partial-eq-1.rs new file mode 100644 index 000000000000..db123a1b5e7d --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/partial-eq-1.rs @@ -0,0 +1,103 @@ +/* { dg-output "a == b\r*\na != c\r*\n" }*/ +/* { dg-options "-w" } */ + +mod core { + mod marker { + #[lang = "phantom_data"] + #[stable(feature = "rust1", since = "1.0.0")] + pub struct PhantomData<T: ?Sized>; + + #[unstable(feature = "structural_match", issue = "31434")] + #[lang = "structural_peq"] + pub trait StructuralPartialEq { + // Empty. + } + + #[unstable(feature = "structural_match", issue = "31434")] + #[lang = "structural_teq"] + pub trait StructuralEq { + // Empty. + } + + #[lang = "sized"] + pub trait Sized {} + } + + pub mod cmp { + use super::marker::Sized; + + #[lang = "eq"] + pub trait PartialEq<Rhs: ?Sized = Self> { + fn eq(&self, other: &Rhs) -> bool; + + fn ne(&self, other: &Rhs) -> bool { + !self.eq(other) + } + } + + pub trait Eq: PartialEq<Self> { + fn assert_receiver_is_total_eq(&self) {} + } + } +} + +use core::cmp::{Eq, PartialEq}; + +// PartialEq for i32 and u32 so we can compare across types +impl PartialEq<u32> for i32 { + fn eq(&self, other: &u32) -> bool { + *self >= 0 && (*self as u32) == *other + } +} +impl PartialEq<i32> for u32 { + fn eq(&self, other: &i32) -> bool { + *other >= 0 && *self == *other as u32 + } +} + +// Our generic struct +struct Foo<T> { + value: T, +} + +// Manual impl of PartialEq for different generic params +impl<T, U> PartialEq<Foo<U>> for Foo<T> +where + T: PartialEq<U>, +{ + fn eq(&self, other: &Foo<U>) -> bool { + self.value.eq(&other.value) + } +} + +impl<T: PartialEq> Eq for Foo<T> {} + +extern "C" { + fn puts(s: *const i8); +} + +fn print(s: &str) { + unsafe { + puts(s as *const str as *const i8); + } +} + +fn main() -> i32 { + let a = Foo { value: 42i32 }; + let b = Foo { value: 42u32 }; + let c = Foo { value: 7u32 }; + + if a == b { + print("a == b"); + } else { + print("a != b"); + } + + if a == c { + print("a == c"); + } else { + print("a != c"); + } + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/partial-eq-2.rs b/gcc/testsuite/rust/execute/torture/partial-eq-2.rs new file mode 100644 index 000000000000..debed8c83f32 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/partial-eq-2.rs @@ -0,0 +1,60 @@ +/* { dg-output "a == b\r*\na != c\r*\n" }*/ +/* { dg-options "-w" } */ + +#[lang = "sized"] +pub trait Sized {} + +#[lang = "eq"] +pub trait PartialEq<Rhs: ?Sized = Self> { + fn eq(&self, other: &Rhs) -> bool; + + fn ne(&self, other: &Rhs) -> bool { + !self.eq(other) + } +} + +impl PartialEq for i32 { + fn eq(&self, other: &Self) -> bool { + *self == *other + } +} + +struct Foo<T> { + value: T, +} + +impl<T: PartialEq> PartialEq for Foo<T> { + fn eq(&self, other: &Self) -> bool { + self.value.eq(&other.value) + } +} + +extern "C" { + fn puts(s: *const i8); +} + +fn print(s: &str) { + unsafe { + puts(s as *const str as *const i8); + } +} + +fn main() -> i32 { + let a = Foo { value: 42i32 }; + let b = Foo { value: 42i32 }; + let c = Foo { value: 99i32 }; + + if a == b { + print("a == b"); + } else { + print("a != b"); + } + + if a == c { + print("a == c"); + } else { + print("a != c"); + } + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/partial-eq-3.rs b/gcc/testsuite/rust/execute/torture/partial-eq-3.rs new file mode 100644 index 000000000000..849910afc832 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/partial-eq-3.rs @@ -0,0 +1,457 @@ +/* { dg-output "a == b\r*\na != c\r*\n" }*/ +/* { dg-options "-w" } */ + +#![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 Eq for i32 {} + +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 + } + } +} + +#[derive(PartialEq)] +struct Foo { + a: i32, +} + +extern "C" { + fn puts(s: *const i8); +} + +fn print(s: &str) { + unsafe { + puts(s as *const str as *const i8); + } +} + +fn main() -> i32 { + let a = Foo { a: 42i32 }; + let b = Foo { a: 42i32 }; + let c = Foo { a: 7i32 }; + + if a == b { + print("a == b"); + } else { + print("a != b"); + } + + if a == c { + print("a == c"); + } else { + print("a != c"); + } + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/partial-eq-4.rs b/gcc/testsuite/rust/execute/torture/partial-eq-4.rs new file mode 100644 index 000000000000..b6997d8592fa --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/partial-eq-4.rs @@ -0,0 +1,457 @@ +/* { dg-output "a == b\r*\na != c\r*\n" }*/ +/* { dg-options "-w" } */ + +#![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 Eq for i32 {} + +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 + } + } +} + +#[derive(PartialEq, Eq)] +struct Foo { + a: i32, +} + +extern "C" { + fn puts(s: *const i8); +} + +fn print(s: &str) { + unsafe { + puts(s as *const str as *const i8); + } +} + +fn main() -> i32 { + let a = Foo { a: 42i32 }; + let b = Foo { a: 42i32 }; + let c = Foo { a: 7i32 }; + + if a == b { + print("a == b"); + } else { + print("a != b"); + } + + if a == c { + print("a == c"); + } else { + print("a != c"); + } + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/partial-ord-1.rs b/gcc/testsuite/rust/execute/torture/partial-ord-1.rs new file mode 100644 index 000000000000..a3558e7cb7a9 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/partial-ord-1.rs @@ -0,0 +1,101 @@ +/* { dg-output "x == y\r*\nx > z\r*\n" }*/ +#[lang = "sized"] +pub trait Sized {} + +pub enum Option<T> { + #[lang = "None"] + None, + #[lang = "Some"] + Some(T), +} + +use Option::{None, Some}; + +#[lang = "eq"] +pub trait PartialEq<Rhs: ?Sized = Self> { + fn eq(&self, other: &Rhs) -> bool; + + fn ne(&self, other: &Rhs) -> bool { + !self.eq(other) + } +} + +pub enum Ordering { + Less = -1, + Equal = 0, + Greater = 1, +} + +#[lang = "partial_ord"] +pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> { + fn partial_cmp(&self, other: &Rhs) -> Option<Ordering>; +} + +// Implement for i32 +impl PartialEq for i32 { + fn eq(&self, other: &Self) -> bool { + *self == *other + } +} + +// Implement PartialOrd for i32 +impl PartialOrd for i32 { + fn partial_cmp(&self, other: &Self) -> Option<Ordering> { + if *self < *other { + Some(Ordering::Less) + } else if *self > *other { + Some(Ordering::Greater) + } else { + Some(Ordering::Equal) + } + } +} + +// Struct with manual PartialEq +struct Foo { + a: i32, +} + +impl PartialEq for Foo { + fn eq(&self, other: &Self) -> bool { + self.a.eq(&other.a) + } +} + +impl PartialOrd for Foo { + fn partial_cmp(&self, other: &Self) -> Option<Ordering> { + self.a.partial_cmp(&other.a) + } +} + +extern "C" { + fn puts(s: *const i8); +} + +fn print(s: &str) { + unsafe { + puts(s as *const str as *const i8); + } +} + +fn main() -> i32 { + let x = Foo { a: 42 }; + let y = Foo { a: 42 }; + let z = Foo { a: 7 }; + + match x.partial_cmp(&y) { + Some(Ordering::Equal) => print("x == y"), + Some(Ordering::Less) => print("x < y"), + Some(Ordering::Greater) => print("x > y"), + None => print("x ? y"), + } + + match x.partial_cmp(&z) { + Some(Ordering::Equal) => print("x == z"), + Some(Ordering::Less) => print("x < z"), + Some(Ordering::Greater) => print("x > z"), + None => print("x ? z"), + } + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/partial-ord-2.rs b/gcc/testsuite/rust/execute/torture/partial-ord-2.rs new file mode 100644 index 000000000000..d3b713fc5e26 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/partial-ord-2.rs @@ -0,0 +1,469 @@ +/* { dg-output "x == y\r*\nx > z\r*\n" }*/ + +#![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 Eq for i32 {} + +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 + } + } +} + +struct Foo { + a: i32, +} + +impl PartialEq for Foo { + fn eq(&self, other: &'_ Self) -> bool { + self.a == other.a + } +} + +impl PartialOrd for Foo { + fn partial_cmp(&self, other: &'_ Foo) -> Option<::core::cmp::Ordering> { + self.a.partial_cmp(&other.a) + } +} + +extern "C" { + fn puts(s: *const i8); +} + +fn print(s: &str) { + unsafe { + puts(s as *const str as *const i8); + } +} + +fn main() -> i32 { + let x = Foo { a: 42 }; + let y = Foo { a: 42 }; + let z = Foo { a: 7 }; + + match x.partial_cmp(&y) { + Option::Some(Ordering::Equal) => print("x == y"), + Option::Some(Ordering::Less) => print("x < y"), + Option::Some(Ordering::Greater) => print("x > y"), + Option::None => print("x ? y"), + } + + match x.partial_cmp(&z) { + Option::Some(Ordering::Equal) => print("x == z"), + Option::Some(Ordering::Less) => print("x < z"), + Option::Some(Ordering::Greater) => print("x > z"), + Option::None => print("x ? z"), + } + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/partial-ord-3.rs b/gcc/testsuite/rust/execute/torture/partial-ord-3.rs new file mode 100644 index 000000000000..7aec07c5caaa --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/partial-ord-3.rs @@ -0,0 +1,489 @@ +/* { dg-output "x == y\r*\nx > z\r*\nx < z\r*\nx >= y\r*\nx <= y\r*\n" } */ +/* { dg-options "-w" } */ + +#![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 Eq for i32 {} + +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 + } + } +} + +struct Foo { + a: i32, +} + +impl PartialEq for Foo { + fn eq(&self, other: &Self) -> bool { + self.a == other.a + } +} +impl Eq for Foo {} + +impl PartialOrd for Foo { + fn partial_cmp(&self, other: &Self) -> Option<Ordering> { + self.a.partial_cmp(&other.a) + } +} + +impl Ord for Foo { + fn cmp(&self, other: &Self) -> Ordering { + self.a.cmp(&other.a) + } +} + +extern "C" { + fn puts(s: *const i8); +} + +fn print(s: &str) { + unsafe { + puts(s as *const str as *const i8); + } +} + +fn main() -> i32 { + let x = Foo { a: 42 }; + let y = Foo { a: 42 }; + let z = Foo { a: 7 }; + + // test direct equality + if x == y { + print("x == y"); + } + + // test PartialOrd via match + match x.partial_cmp(&z) { + Option::Some(Ordering::Greater) => print("x > z"), + _ => print("x ? z"), + } + + // test `<` directly + if z < x { + print("x < z"); + } + + // test `>=` + if x >= y { + print("x >= y"); + } + + // test `<=` + if x <= y { + print("x <= y"); + } + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/partial-ord-4.rs b/gcc/testsuite/rust/execute/torture/partial-ord-4.rs new file mode 100644 index 000000000000..fd52f328c58b --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/partial-ord-4.rs @@ -0,0 +1,115 @@ +/* { dg-output "a == b\r*\na != c\r*\n" }*/ +/* { dg-options "-w" } */ + +#![feature(intrinsics)] + +mod core { + mod option { + pub enum Option<T> { + #[lang = "None"] + None, + #[lang = "Some"] + Some(T), + } + } + + mod marker { + #[lang = "sized"] + pub trait Sized {} + } + + mod cmp { + use super::marker::Sized; + use super::option::Option; + + pub enum Ordering { + Less = -1, + Equal = 0, + Greater = 1, + } + + #[lang = "eq"] + pub trait PartialEq<Rhs: ?Sized = Self> { + fn eq(&self, other: &Rhs) -> bool; + + fn ne(&self, other: &Rhs) -> bool { + !self.eq(other) + } + } + + #[lang = "partial_ord"] + pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> { + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn partial_cmp(&self, other: &Rhs) -> Option<Ordering>; + } + } +} + +use core::cmp::{Ordering, PartialEq, PartialOrd}; +use core::marker::Sized; +use core::option::Option; + +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) + } + } +} + +struct Foo { + a: i32, +} + +impl PartialEq for Foo { + fn eq(&self, other: &'_ Self) -> bool { + self.a == other.a + } +} + +impl PartialOrd for Foo { + fn partial_cmp(&self, other: &'_ Foo) -> Option<::core::cmp::Ordering> { + ::core::cmp::PartialOrd::partial_cmp(&self.a, &other.a) + } +} + +extern "C" { + fn puts(s: *const i8); +} + +fn print(s: &str) { + unsafe { + puts(s as *const str as *const i8); + } +} + +fn main() -> i32 { + let a = Foo { a: 42i32 }; + let b = Foo { a: 42i32 }; + let c = Foo { a: 7i32 }; + + if a == b { + print("a == b"); + } else { + print("a != b"); + } + + if a == c { + print("a == c"); + } else { + print("a != c"); + } + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/partial-ord-5.rs b/gcc/testsuite/rust/execute/torture/partial-ord-5.rs new file mode 100644 index 000000000000..721d2aa00655 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/partial-ord-5.rs @@ -0,0 +1,487 @@ +/* { dg-output "a == b\r*\na != c\r*\na >= c\r*\na <= b\r*\na > c\r*\nc < b\r*\n" } */ +/* { dg-options "-w" } */ + +#![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 Eq for i32 {} + +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 + } + } +} + +#[derive(PartialEq, Eq, Ord)] +struct Foo { + a: i32, +} + +impl PartialOrd for Foo { + fn partial_cmp(&self, other: &'_ Foo) -> Option<::core::cmp::Ordering> { + self.a.partial_cmp(&other.a) + } +} + +extern "C" { + fn puts(s: *const i8); +} + +fn print(s: &str) { + unsafe { + puts(s as *const str as *const i8); + } +} + +fn main() -> i32 { + let a = Foo { a: 42 }; + let b = Foo { a: 42 }; + let c = Foo { a: 7 }; + + if a == b { + print("a == b"); + } else { + print("a != b"); + } + + if a != c { + print("a != c"); + } else { + print("a == c"); + } + + if a < c { + print("a < c"); + } else { + print("a >= c"); + } + + if a <= b { + print("a <= b"); + } else { + print("a > b"); + } + + if a > c { + print("a > c"); + } else { + print("a <= c"); + } + + if c >= b { + print("c >= b"); + } else { + print("c < b"); + } + + 0 +}