[gccrs COMMIT] gccrs: Add flag to unify of expect never

gerris.rs@gmail.com gerris.rs@gmail.com
Fri Sep 18 19:26:19 GMT 2026


From: Philip Herron <herron.philip@googlemail.com>

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 <herron.philip@googlemail.com>
---
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



More information about the Gcc-rust mailing list