From: Philip Herron <[email protected]>

Fixes Rust-GCC/gccrs#4918

gcc/rust/ChangeLog:

        * typecheck/rust-coercion.cc (TypeCoercionRules::TryCoerce): add flag
        (TypeCoercionRules::TypeCoercionRules): Likewise.
        (TypeCoercionRules::do_coercion): Likewise.
        (TypeCoercionRules::coerce_unsafe_ptr): Likewise.
        (TypeCoercionRules::coerce_borrowed_pointer): Likewise.
        (TypeCoercionRules::select): Likewise.
        * typecheck/rust-coercion.h: Likewise.
        * typecheck/rust-hir-dot-operator.cc 
(MethodResolver::try_select_predicate_candidates):
        Likewise.
        * typecheck/rust-type-util.cc (unify_site_and): Likewise.
        * typecheck/rust-type-util.h (unify_site_and): Likewise.
        * typecheck/rust-unify.cc (UnifyRules::UnifyRules): Likewise.
        (UnifyRules::Resolve): Likewise.
        (UnifyRules::resolve_subtype): Likewise.
        (UnifyRules::expect_never): Likewise.
        * typecheck/rust-unify.h: Likewise.

gcc/testsuite/ChangeLog:

        * rust/compile/issues/4918.rs: New test.

Signed-off-by: Philip Herron <[email protected]>
---
This change was merged into the gccrs repository and is posted here for
upstream visibility and potential drive-by review, as requested by GCC
release managers.
Each commit email contains a link to its details on github from where you can
find the Pull-Request and associated discussions.


Commit on github: 
https://github.com/Rust-GCC/gccrs/commit/215416773ce7d0dcd27a9593d05563facc5c7e56

The commit has been mentioned in the following issue(s):
 - Rust-GCC/gccrs#4918: https://github.com/Rust-GCC/gccrs/issues/4918

The commit has been mentioned in the following pull-request(s):
 - https://github.com/Rust-GCC/gccrs/pull/4919

 gcc/rust/typecheck/rust-coercion.cc         | 23 +++++++++-----
 gcc/rust/typecheck/rust-coercion.h          |  6 ++--
 gcc/rust/typecheck/rust-hir-dot-operator.cc | 12 ++++++--
 gcc/rust/typecheck/rust-type-util.cc        |  5 ++--
 gcc/rust/typecheck/rust-type-util.h         |  3 +-
 gcc/rust/typecheck/rust-unify.cc            | 24 ++++++++++-----
 gcc/rust/typecheck/rust-unify.h             |  6 ++--
 gcc/testsuite/rust/compile/issues/4918.rs   | 33 +++++++++++++++++++++
 8 files changed, 86 insertions(+), 26 deletions(-)
 create mode 100644 gcc/testsuite/rust/compile/issues/4918.rs

diff --git a/gcc/rust/typecheck/rust-coercion.cc 
b/gcc/rust/typecheck/rust-coercion.cc
index 4df9934d8..9d4de57db 100644
--- a/gcc/rust/typecheck/rust-coercion.cc
+++ b/gcc/rust/typecheck/rust-coercion.cc
@@ -37,10 +37,11 @@ TypeCoercionRules::Coerce (TyTy::BaseType *receiver, 
TyTy::BaseType *expected,
 TypeCoercionRules::CoercionResult
 TypeCoercionRules::TryCoerce (TyTy::BaseType *receiver,
                              TyTy::BaseType *expected, location_t locus,
-                             bool allow_autoderef, bool is_cast_site)
+                             bool allow_autoderef, bool is_cast_site,
+                             bool allow_never_coercion)
 {
   TypeCoercionRules resolver (expected, locus, false, allow_autoderef, true,
-                             is_cast_site);
+                             is_cast_site, allow_never_coercion);
   bool ok = resolver.do_coercion (receiver);
   return ok ? resolver.try_result : CoercionResult::get_error ();
 }
@@ -48,11 +49,13 @@ TypeCoercionRules::TryCoerce (TyTy::BaseType *receiver,
 TypeCoercionRules::TypeCoercionRules (TyTy::BaseType *expected,
                                      location_t locus, bool emit_errors,
                                      bool allow_autoderef, bool try_flag,
-                                     bool is_cast_site)
+                                     bool is_cast_site,
+                                     bool allow_never_coercion)
   : AutoderefCycle (!allow_autoderef), mappings (Analysis::Mappings::get ()),
     context (TypeCheckContext::get ()), expected (expected), locus (locus),
     try_result (CoercionResult::get_error ()), emit_errors (emit_errors),
-    try_flag (try_flag), is_cast_site (is_cast_site)
+    try_flag (try_flag), is_cast_site (is_cast_site),
+    allow_never_coercion (allow_never_coercion)
 {}
 
 bool
@@ -121,7 +124,8 @@ TypeCoercionRules::do_coercion (TyTy::BaseType *receiver)
                            TyTy::TyWithLocation (receiver),
                            locus /*unify_locus*/, false /*emit_errors*/,
                            !try_flag /*commit_if_ok*/, try_flag /*infer*/,
-                           try_flag /*cleanup on error*/);
+                           try_flag /*cleanup on error*/,
+                           true /*check_bounds*/, allow_never_coercion);
        if (result->get_kind () != TyTy::TypeKind::ERROR)
          {
            try_result = CoercionResult{{}, result};
@@ -248,7 +252,8 @@ TypeCoercionRules::coerce_unsafe_ptr (TyTy::BaseType 
*receiver,
                      locus /*unify_locus*/, !try_flag /*emit_errors*/,
                      !try_flag /*commit_if_ok*/,
                      try_flag && !is_cast_site /*infer*/,
-                     try_flag /*cleanup on error*/);
+                     try_flag /*cleanup on error*/, true /*check_bounds*/,
+                     allow_never_coercion);
   bool unsafe_ptr_coerceion_ok = result->get_kind () != TyTy::TypeKind::ERROR;
   if (unsafe_ptr_coerceion_ok)
     return CoercionResult{{}, result};
@@ -284,7 +289,8 @@ TypeCoercionRules::coerce_borrowed_pointer (TyTy::BaseType 
*receiver,
                            TyTy::TyWithLocation (expected), locus,
                            false /*emit_errors*/, !try_flag /*commit_if_ok*/,
                            try_flag /* infer */,
-                           try_flag /*cleanup_on_failure*/);
+                           try_flag /*cleanup_on_failure*/,
+                           true /*check_bounds*/, allow_never_coercion);
        bool default_coerceion_ok
          = result->get_kind () != TyTy::TypeKind::ERROR;
        if (default_coerceion_ok)
@@ -625,7 +631,8 @@ TypeCoercionRules::select (TyTy::BaseType &autoderefed)
                      TyTy::TyWithLocation (&autoderefed),
                      UNDEF_LOCATION /* locus */, false /*emit_errors*/,
                      !try_flag /*commit_if_ok*/, try_flag /*infer*/,
-                     try_flag /*cleanup*/);
+                     try_flag /*cleanup*/, true /*check_bounds*/,
+                     allow_never_coercion);
   bool ok = result->get_kind () != TyTy::TypeKind::ERROR;
   if (!ok)
     return false;
diff --git a/gcc/rust/typecheck/rust-coercion.h 
b/gcc/rust/typecheck/rust-coercion.h
index 0674cf5df..be5daf39f 100644
--- a/gcc/rust/typecheck/rust-coercion.h
+++ b/gcc/rust/typecheck/rust-coercion.h
@@ -56,7 +56,8 @@ public:
   static CoercionResult TryCoerce (TyTy::BaseType *receiver,
                                   TyTy::BaseType *expected, location_t locus,
                                   bool allow_autoderef,
-                                  bool is_cast_site = false);
+                                  bool is_cast_site = false,
+                                  bool allow_never_coercion = true);
 
   CoercionResult coerce_never (TyTy::BaseType *receiver);
   CoercionResult coerce_unsafe_ptr (TyTy::BaseType *receiver,
@@ -82,7 +83,7 @@ public:
 protected:
   TypeCoercionRules (TyTy::BaseType *expected, location_t locus,
                     bool emit_errors, bool allow_autoderef, bool try_flag,
-                    bool is_cast_site);
+                    bool is_cast_site, bool allow_never_coercion = true);
 
   bool select (TyTy::BaseType &autoderefed) override;
 
@@ -124,6 +125,7 @@ private:
   bool emit_errors;
   bool try_flag;
   bool is_cast_site;
+  bool allow_never_coercion;
 };
 
 } // namespace Resolver
diff --git a/gcc/rust/typecheck/rust-hir-dot-operator.cc 
b/gcc/rust/typecheck/rust-hir-dot-operator.cc
index 06d9aa88e..24b8b8ccc 100644
--- a/gcc/rust/typecheck/rust-hir-dot-operator.cc
+++ b/gcc/rust/typecheck/rust-hir-dot-operator.cc
@@ -364,7 +364,9 @@ MethodResolver::try_select_predicate_candidates 
(TyTy::BaseType &receiver)
 
       auto res
        = TypeCoercionRules::TryCoerce (&receiver, fn_self, UNDEF_LOCATION,
-                                       false /*allow-autoderef*/);
+                                       false /*allow-autoderef*/,
+                                       false /*is_cast_site*/,
+                                       false /*allow_never_coercion*/);
       bool ok = !res.is_error ();
       if (ok)
        {
@@ -415,7 +417,9 @@ MethodResolver::try_select_inherent_impl_candidates (
 
       auto res
        = TypeCoercionRules::TryCoerce (&receiver, fn_self, UNDEF_LOCATION,
-                                       false /*allow-autoderef*/);
+                                       false /*allow-autoderef*/,
+                                       false /*is_cast_site*/,
+                                       false /*allow_never_coercion*/);
       bool ok = !res.is_error ();
       if (ok)
        {
@@ -451,7 +455,9 @@ MethodResolver::try_select_trait_impl_candidates (
 
       auto res
        = TypeCoercionRules::TryCoerce (&receiver, fn_self, UNDEF_LOCATION,
-                                       false /*allow-autoderef*/);
+                                       false /*allow-autoderef*/,
+                                       false /*is_cast_site*/,
+                                       false /*allow_never_coercion*/);
       bool ok = !res.is_error ();
       if (ok)
        {
diff --git a/gcc/rust/typecheck/rust-type-util.cc 
b/gcc/rust/typecheck/rust-type-util.cc
index 2234f89e0..7df36f0d3 100644
--- a/gcc/rust/typecheck/rust-type-util.cc
+++ b/gcc/rust/typecheck/rust-type-util.cc
@@ -281,7 +281,8 @@ unify_site (HirId id, TyTy::TyWithLocation lhs, 
TyTy::TyWithLocation rhs,
 TyTy::BaseType *
 unify_site_and (HirId id, TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs,
                location_t unify_locus, bool emit_errors, bool commit_if_ok,
-               bool implicit_infer_vars, bool cleanup, bool check_bounds)
+               bool implicit_infer_vars, bool cleanup, bool check_bounds,
+               bool allow_never_coercion)
 {
   TypeCheckContext &context = *TypeCheckContext::get ();
 
@@ -301,7 +302,7 @@ unify_site_and (HirId id, TyTy::TyWithLocation lhs, 
TyTy::TyWithLocation rhs,
   TyTy::BaseType *result
     = UnifyRules::Resolve (lhs, rhs, unify_locus, false /*commit inline*/,
                           emit_errors, check_bounds, implicit_infer_vars,
-                          commits, infers);
+                          commits, infers, nullptr, allow_never_coercion);
   bool ok = result->get_kind () != TyTy::TypeKind::ERROR;
 
   rust_debug_loc (unify_locus,
diff --git a/gcc/rust/typecheck/rust-type-util.h 
b/gcc/rust/typecheck/rust-type-util.h
index 860f23cfc..89687d9f2 100644
--- a/gcc/rust/typecheck/rust-type-util.h
+++ b/gcc/rust/typecheck/rust-type-util.h
@@ -38,7 +38,8 @@ TyTy::BaseType *unify_site_and (HirId id, 
TyTy::TyWithLocation lhs,
                                TyTy::TyWithLocation rhs,
                                location_t unify_locus, bool emit_errors,
                                bool commit_if_ok, bool implicit_infer_vars,
-                               bool cleanup, bool check_bounds = true);
+                               bool cleanup, bool check_bounds = true,
+                               bool allow_never_coercion = true);
 
 TyTy::BaseType *coercion_site (HirId id, TyTy::TyWithLocation lhs,
                               TyTy::TyWithLocation rhs,
diff --git a/gcc/rust/typecheck/rust-unify.cc b/gcc/rust/typecheck/rust-unify.cc
index 417804b44..db6dabcf8 100644
--- a/gcc/rust/typecheck/rust-unify.cc
+++ b/gcc/rust/typecheck/rust-unify.cc
@@ -39,12 +39,13 @@ UnifyRules::UnifyRules (TyTy::TyWithLocation lhs, 
TyTy::TyWithLocation rhs,
                        bool check_bounds, bool infer,
                        std::vector<CommitSite> &commits,
                        std::vector<InferenceSite> &infers,
-                       ActiveADTs &active_adts)
+                       ActiveADTs &active_adts, bool allow_never_coercion)
   : lhs (lhs), rhs (rhs), locus (locus), commit_flag (commit_flag),
     emit_error (emit_error), infer_flag (infer),
-    check_bounds_flag (check_bounds), commits (commits), infers (infers),
-    active_adts (active_adts), mappings (Analysis::Mappings::get ()),
-    context (*TypeCheckContext::get ())
+    check_bounds_flag (check_bounds),
+    allow_never_coercion (allow_never_coercion), commits (commits),
+    infers (infers), active_adts (active_adts),
+    mappings (Analysis::Mappings::get ()), context (*TypeCheckContext::get ())
 {}
 
 TyTy::BaseType *
@@ -53,14 +54,14 @@ UnifyRules::Resolve (TyTy::TyWithLocation lhs, 
TyTy::TyWithLocation rhs,
                     bool check_bounds, bool infer,
                     std::vector<CommitSite> &commits,
                     std::vector<InferenceSite> &infers,
-                    ActiveADTs *active_adts)
+                    ActiveADTs *active_adts, bool allow_never_coercion)
 {
   ActiveADTs root_active_adts;
   if (active_adts == nullptr)
     active_adts = &root_active_adts;
 
   UnifyRules r (lhs, rhs, locus, commit_flag, emit_error, check_bounds, infer,
-               commits, infers, *active_adts);
+               commits, infers, *active_adts, allow_never_coercion);
 
   TyTy::BaseType *result = r.go ();
   bool failed = result->get_kind () == TyTy::TypeKind::ERROR;
@@ -84,7 +85,7 @@ UnifyRules::resolve_subtype (TyTy::TyWithLocation lhs, 
TyTy::TyWithLocation rhs)
   TyTy::BaseType *result
     = UnifyRules::Resolve (lhs, rhs, locus, commit_flag, emit_error,
                           check_bounds_flag, infer_flag, commits, infers,
-                          &active_adts);
+                          &active_adts, allow_never_coercion);
 
   // If the recursive call resulted in an error and would have emitted an error
   // message, disable error emission for the current level to avoid duplicate
@@ -1835,8 +1836,15 @@ UnifyRules::expect_never (TyTy::NeverType *ltype, 
TyTy::BaseType *rtype)
       }
       break;
 
+    case TyTy::NEVER:
+      return ltype;
+
     default:
-      return rtype;
+      {
+       if (allow_never_coercion)
+         return rtype;
+      }
+      break;
     }
   return unify_error_type_node ();
 }
diff --git a/gcc/rust/typecheck/rust-unify.h b/gcc/rust/typecheck/rust-unify.h
index 2091bd1b1..29938cfff 100644
--- a/gcc/rust/typecheck/rust-unify.h
+++ b/gcc/rust/typecheck/rust-unify.h
@@ -90,7 +90,7 @@ public:
   Resolve (TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs, location_t 
locus,
           bool commit_flag, bool emit_error, bool check_bounds, bool infer,
           std::vector<CommitSite> &commits, std::vector<InferenceSite> &infers,
-          ActiveADTs *active_adts = nullptr);
+          ActiveADTs *active_adts = nullptr, bool allow_never_coercion = true);
 
   static void commit (TyTy::BaseType *base, TyTy::BaseType *other,
                      TyTy::BaseType *resolved);
@@ -135,7 +135,8 @@ private:
   UnifyRules (TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs,
              location_t locus, bool commit_flag, bool emit_error, bool infer,
              bool check_bounds, std::vector<CommitSite> &commits,
-             std::vector<InferenceSite> &infers, ActiveADTs &active_adts);
+             std::vector<InferenceSite> &infers, ActiveADTs &active_adts,
+             bool allow_never_coercion);
 
   TyTy::BaseType *resolve_subtype (TyTy::TyWithLocation lhs,
                                   TyTy::TyWithLocation rhs);
@@ -156,6 +157,7 @@ private:
   bool emit_error;
   bool infer_flag;
   bool check_bounds_flag;
+  bool allow_never_coercion;
   std::vector<CommitSite> &commits;
   std::vector<InferenceSite> &infers;
 
diff --git a/gcc/testsuite/rust/compile/issues/4918.rs 
b/gcc/testsuite/rust/compile/issues/4918.rs
new file mode 100644
index 000000000..b378d1b35
--- /dev/null
+++ b/gcc/testsuite/rust/compile/issues/4918.rs
@@ -0,0 +1,33 @@
+#![feature(no_core, lang_items)]
+#![no_core]
+
+#[lang = "sized"]
+pub trait Sized {}
+
+pub enum Ordering {
+    Less,
+    Equal,
+    Greater,
+}
+
+pub trait Ord {
+    fn cmp(&self, other: &Self) -> Ordering;
+}
+
+impl Ord for i32 {
+    fn cmp(&self, _other: &i32) -> Ordering {
+        Ordering::Equal
+    }
+}
+
+impl Ord for ! {
+    fn cmp(&self, _other: &!) -> Ordering {
+        Ordering::Equal
+    }
+}
+
+fn main() {
+    let left: i32 = 1;
+    let right: i32 = 2;
+    let _ = left.cmp(&right);
+}

base-commit: 5870b08eac1603169553d896c128fd886523f6af
-- 
2.55.0

Reply via email to