[gccrs COMMIT] gccrs: improve handling of defered operator overload handling

gerris.rs@gmail.com gerris.rs@gmail.com
Sun Sep 6 20:10:07 GMT 2026


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

When we are compiling libcore each operation +-/* etc all resolve to libcore
implementations of these that define the semantics but what can happen is
because of infer vars its ambigious what implementation this should
specialize to untill more type hints are applied so we return an infer
variable result so type checking can continue and we try to resolve at
the end.

gcc/rust/ChangeLog:

	* typecheck/rust-hir-dot-operator.cc (MethodResolver::Select): optional result type
	* typecheck/rust-hir-dot-operator.h: likewise
	* typecheck/rust-hir-type-check-expr.cc (TypeCheckExpr::ResolveOpOverload): defer flag
	(TypeCheckExpr::visit): pass throw the borrow
	* typecheck/rust-hir-type-check-expr.h: likewise
	* typecheck/rust-hir-type-check.h (struct DeferredOpOverload): new
	* typecheck/rust-type-util.cc (unify_site): like parameter ordering
	(unify_site_and): likewise
	* typecheck/rust-typecheck-context.cc (TypeCheckContext::compute_ambigious_op_overload): new
	(TypeCheckContext::compute_inference_variables): likewise
	(TypeCheckContext::compute_infer_var): likewise
	* typecheck/rust-unify.cc (UnifyRules::Resolve): fix arguments
	(UnifyRules::resolve_subtype):likewise
	* typecheck/rust-unify.h: likewise

gcc/testsuite/ChangeLog:

	* rust/execute/torture/deferred-add-partial-ord.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/0e58f6bbbee5064865c166d30f849ae3dd3f4e22

The commit has NOT been mentioned in any issue.

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

 gcc/rust/typecheck/rust-hir-dot-operator.cc   | 18 ++++-
 gcc/rust/typecheck/rust-hir-dot-operator.h    |  3 +-
 .../typecheck/rust-hir-type-check-expr.cc     | 77 +++++++++----------
 gcc/rust/typecheck/rust-hir-type-check-expr.h |  8 +-
 gcc/rust/typecheck/rust-hir-type-check.h      | 12 +--
 gcc/rust/typecheck/rust-type-util.cc          |  6 +-
 gcc/rust/typecheck/rust-typecheck-context.cc  | 67 +++++++++++++---
 gcc/rust/typecheck/rust-unify.cc              |  7 +-
 gcc/rust/typecheck/rust-unify.h               |  4 +-
 .../torture/deferred-add-partial-ord.rs       | 58 ++++++++++++++
 10 files changed, 189 insertions(+), 71 deletions(-)
 create mode 100644 gcc/testsuite/rust/execute/torture/deferred-add-partial-ord.rs

diff --git a/gcc/rust/typecheck/rust-hir-dot-operator.cc b/gcc/rust/typecheck/rust-hir-dot-operator.cc
index 89a596a28..8fd7f1d00 100644
--- a/gcc/rust/typecheck/rust-hir-dot-operator.cc
+++ b/gcc/rust/typecheck/rust-hir-dot-operator.cc
@@ -46,7 +46,8 @@ MethodResolver::Probe (TyTy::BaseType *receiver,
 std::set<MethodCandidate>
 MethodResolver::Select (std::set<MethodCandidate> &candidates,
 			TyTy::BaseType *receiver,
-			std::vector<TyTy::BaseType *> arguments)
+			std::vector<TyTy::BaseType *> arguments,
+			TyTy::BaseType *result_type)
 {
   std::set<MethodCandidate> selected;
   for (auto &candidate : candidates)
@@ -78,6 +79,21 @@ MethodResolver::Select (std::set<MethodCandidate> &candidates,
 	    }
 	}
 
+      if (!failed && result_type != nullptr)
+	{
+	  TyTy::BaseType *return_type = fn.get_return_type ();
+	  rust_debug ("method candidate output check fn=%s expected=%s "
+		      "return=%s",
+		      fn.debug_str ().c_str (),
+		      result_type->debug_str ().c_str (),
+		      return_type->debug_str ().c_str ());
+	  failed = !types_compatable (TyTy::TyWithLocation (result_type),
+				      TyTy::TyWithLocation (return_type),
+				      UNDEF_LOCATION, false /* emit_errors */);
+	  rust_debug ("method candidate output check result=%s",
+		      failed ? "rejected" : "accepted");
+	}
+
       if (!failed)
 	selected.insert (candidate);
     }
diff --git a/gcc/rust/typecheck/rust-hir-dot-operator.h b/gcc/rust/typecheck/rust-hir-dot-operator.h
index 79c5db1c0..78c33217b 100644
--- a/gcc/rust/typecheck/rust-hir-dot-operator.h
+++ b/gcc/rust/typecheck/rust-hir-dot-operator.h
@@ -64,7 +64,8 @@ public:
 
   static std::set<MethodCandidate>
   Select (std::set<MethodCandidate> &candidates, TyTy::BaseType *receiver,
-	  std::vector<TyTy::BaseType *> arguments);
+	  std::vector<TyTy::BaseType *> arguments,
+	  TyTy::BaseType *result_type = nullptr);
 
   static std::vector<predicate_candidate> get_predicate_items (
     const HIR::PathIdentSegment &segment_name, const TyTy::BaseType &receiver,
diff --git a/gcc/rust/typecheck/rust-hir-type-check-expr.cc b/gcc/rust/typecheck/rust-hir-type-check-expr.cc
index 4824209ae..cc967d4b3 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-expr.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check-expr.cc
@@ -73,12 +73,13 @@ TyTy::BaseType *
 TypeCheckExpr::ResolveOpOverload (LangItem::Kind lang_item_type,
 				  HIR::OperatorExprMeta expr,
 				  TyTy::BaseType *lhs, TyTy::BaseType *rhs,
-				  HIR::PathIdentSegment specified_segment)
+				  HIR::PathIdentSegment specified_segment,
+				  TyTy::BaseType *result_type)
 {
   TypeCheckExpr resolver;
 
   resolver.resolve_operator_overload (lang_item_type, expr, lhs, rhs,
-				      specified_segment);
+				      specified_segment, false, result_type);
   return resolver.infered;
 }
 
@@ -505,6 +506,11 @@ TypeCheckExpr::visit (HIR::ComparisonExpr &expr)
   auto lhs = TypeCheckExpr::Resolve (expr.get_lhs ());
   auto rhs = TypeCheckExpr::Resolve (expr.get_rhs ());
 
+  auto borrowed_lhs
+    = new TyTy::ReferenceType (mappings.get_next_hir_id (),
+			       TyTy::TyVar (lhs->get_ref ()), Mutability::Imm);
+  context->insert_implicit_type (borrowed_lhs->get_ref (), borrowed_lhs);
+
   auto borrowed_rhs
     = new TyTy::ReferenceType (mappings.get_next_hir_id (),
 			       TyTy::TyVar (rhs->get_ref ()), Mutability::Imm);
@@ -516,7 +522,7 @@ TypeCheckExpr::visit (HIR::ComparisonExpr &expr)
 
   bool operator_overloaded
     = resolve_operator_overload (lang_item_type, expr, lhs, borrowed_rhs,
-				 segment);
+				 segment, true, nullptr, borrowed_lhs);
   if (operator_overloaded)
     return;
 
@@ -2014,7 +2020,8 @@ bool
 TypeCheckExpr::resolve_operator_overload (
   LangItem::Kind lang_item_type, HIR::OperatorExprMeta expr,
   TyTy::BaseType *lhs, TyTy::BaseType *rhs,
-  HIR::PathIdentSegment specified_segment)
+  HIR::PathIdentSegment specified_segment, bool allow_defer,
+  TyTy::BaseType *result_type, TyTy::BaseType *probe_lhs)
 {
   // look up lang item for arithmetic type
   std::string associated_item_name = LangItem::ToString (lang_item_type);
@@ -2031,8 +2038,6 @@ TypeCheckExpr::resolve_operator_overload (
   HIR::Item *def_item = def_lookup.value ();
   rust_assert (def_item->get_item_kind () == HIR::Item::ItemKind::Trait);
   HIR::Trait &trait = *static_cast<HIR::Trait *> (def_item);
-  TraitReference *defid_trait_reference = TraitResolver::Resolve (trait);
-  rust_assert (!defid_trait_reference->is_error ());
 
   // we might be in a static or const context and unknown is fine
   TypeCheckContextItem current_context = TypeCheckContextItem::get_error ();
@@ -2044,7 +2049,9 @@ TypeCheckExpr::resolve_operator_overload (
   auto segment = specified_segment.is_error ()
 		   ? HIR::PathIdentSegment (associated_item_name)
 		   : specified_segment;
-  auto candidates = MethodResolver::Probe (lhs, segment, false, &trait);
+  TyTy::BaseType *method_receiver = probe_lhs == nullptr ? lhs : probe_lhs;
+  auto candidates
+    = MethodResolver::Probe (method_receiver, segment, false, &trait);
 
   // remove any recursive candidates
   std::set<MethodCandidate> resolved_candidates;
@@ -2068,7 +2075,8 @@ TypeCheckExpr::resolve_operator_overload (
   if (rhs != nullptr)
     select_args = {rhs};
   auto selected_candidates
-    = MethodResolver::Select (resolved_candidates, lhs, select_args);
+    = MethodResolver::Select (resolved_candidates, method_receiver, select_args,
+			      result_type);
 
   bool have_implementation_for_lang_item = selected_candidates.size () > 0;
   if (!have_implementation_for_lang_item)
@@ -2076,48 +2084,33 @@ TypeCheckExpr::resolve_operator_overload (
 
   if (selected_candidates.size () > 1)
     {
-      auto infer
-	= TyTy::TyVar::get_implicit_infer_var (expr.get_locus ()).get_tyty ();
-      auto trait_subst = defid_trait_reference->get_trait_substs ();
-      rust_assert (trait_subst.size () > 0);
-
-      TyTy::TypeBoundPredicate pred (respective_lang_item_id, trait_subst,
-				     BoundPolarity::RegularBound,
-				     expr.get_locus ());
-
-      std::vector<TyTy::SubstitutionArg> mappings;
-      auto &self_param_mapping = trait_subst[0];
-      mappings.emplace_back (&self_param_mapping, lhs);
-
-      if (rhs != nullptr)
-	{
-	  rust_assert (trait_subst.size () == 2);
-	  auto &rhs_param_mapping = trait_subst[1];
-	  mappings.emplace_back (&rhs_param_mapping, lhs);
-	}
-
-      std::map<std::string, TyTy::BaseType *> binding_args;
-      binding_args["Output"] = infer;
-
-      TyTy::SubstitutionArgumentMappings arg_mappings (mappings, binding_args,
-						       TyTy::RegionParamList (
-							 trait_subst.size ()),
-						       expr.get_locus ());
-      pred.apply_argument_mappings (arg_mappings, false);
-
-      infer->inherit_bounds ({pred});
+      if (!allow_defer)
+	return false;
+
+      TyTy::TyVar result_type
+	= TyTy::TyVar::get_implicit_infer_var (expr.get_locus ());
+      TyTy::BaseType *result_tyty = result_type.get_tyty ();
+      rust_assert (result_tyty != nullptr);
+      rust_debug ("deferring operator expr=%u result-ref=%u result-ty-ref=%u "
+		  "lhs-ref=%u rhs-ref=%u",
+		  expr.get_mappings ().get_hirid (), result_type.get_ref (),
+		  result_tyty->get_ty_ref (), lhs->get_ref (),
+		  rhs == nullptr ? UNKNOWN_HIRID : rhs->get_ref ());
       DeferredOpOverload defer (expr.get_mappings ().get_hirid (),
-				lang_item_type, specified_segment, pred, expr);
+				lang_item_type, specified_segment, expr,
+				result_type);
       context->insert_deferred_operator_overload (std::move (defer));
 
-      infered = unify_site (expr.get_mappings ().get_hirid (),
-			    TyTy::TyWithLocation (lhs),
-			    TyTy::TyWithLocation (infer), expr.get_locus ());
+      infered = result_tyty;
       return true;
     }
 
   // Get the adjusted self
   MethodCandidate candidate = *selected_candidates.begin ();
+  if (probe_lhs != nullptr)
+    candidate.adjustments.insert (
+      candidate.adjustments.begin (),
+      Adjustment (Adjustment::AdjustmentType::IMM_REF, lhs, probe_lhs));
   Adjuster adj (lhs);
   TyTy::BaseType *adjusted_self = adj.adjust_type (candidate.adjustments);
 
diff --git a/gcc/rust/typecheck/rust-hir-type-check-expr.h b/gcc/rust/typecheck/rust-hir-type-check-expr.h
index 100dc0ccf..f7a97086c 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-expr.h
+++ b/gcc/rust/typecheck/rust-hir-type-check-expr.h
@@ -35,7 +35,8 @@ public:
   static TyTy::BaseType *
   ResolveOpOverload (LangItem::Kind lang_item_type, HIR::OperatorExprMeta expr,
 		     TyTy::BaseType *lhs, TyTy::BaseType *rhs,
-		     HIR::PathIdentSegment specified_segment);
+		     HIR::PathIdentSegment specified_segment,
+		     TyTy::BaseType *result_type);
 
   void visit (HIR::TupleIndexExpr &expr) override;
   void visit (HIR::TupleExpr &expr) override;
@@ -109,7 +110,10 @@ protected:
 				  HIR::OperatorExprMeta expr,
 				  TyTy::BaseType *lhs, TyTy::BaseType *rhs,
 				  HIR::PathIdentSegment specified_segment
-				  = HIR::PathIdentSegment::create_error ());
+				  = HIR::PathIdentSegment::create_error (),
+				  bool allow_defer = true,
+				  TyTy::BaseType *result_type = nullptr,
+				  TyTy::BaseType *probe_lhs = nullptr);
 
   bool resolve_fn_trait_call (HIR::CallExpr &expr,
 			      TyTy::BaseType *function_tyty,
diff --git a/gcc/rust/typecheck/rust-hir-type-check.h b/gcc/rust/typecheck/rust-hir-type-check.h
index 1e830713e..f1db16c5f 100644
--- a/gcc/rust/typecheck/rust-hir-type-check.h
+++ b/gcc/rust/typecheck/rust-hir-type-check.h
@@ -164,21 +164,20 @@ struct DeferredOpOverload
   HirId expr_id;
   LangItem::Kind lang_item_type;
   HIR::PathIdentSegment specified_segment;
-  TyTy::TypeBoundPredicate predicate;
   HIR::OperatorExprMeta op;
+  TyTy::TyVar result_type;
 
   DeferredOpOverload (HirId expr_id, LangItem::Kind lang_item_type,
 		      HIR::PathIdentSegment specified_segment,
-		      TyTy::TypeBoundPredicate &predicate,
-		      HIR::OperatorExprMeta op)
+		      HIR::OperatorExprMeta op, TyTy::TyVar result_type)
     : expr_id (expr_id), lang_item_type (lang_item_type),
-      specified_segment (specified_segment), predicate (predicate), op (op)
+      specified_segment (specified_segment), op (op), result_type (result_type)
   {}
 
   DeferredOpOverload (const struct DeferredOpOverload &other)
     : expr_id (other.expr_id), lang_item_type (other.lang_item_type),
-      specified_segment (other.specified_segment), predicate (other.predicate),
-      op (other.op)
+      specified_segment (other.specified_segment), op (other.op),
+      result_type (other.result_type)
   {}
 
   DeferredOpOverload &operator= (struct DeferredOpOverload const &other)
@@ -187,6 +186,7 @@ struct DeferredOpOverload
     lang_item_type = other.lang_item_type;
     specified_segment = other.specified_segment;
     op = other.op;
+    result_type = other.result_type;
 
     return *this;
   }
diff --git a/gcc/rust/typecheck/rust-type-util.cc b/gcc/rust/typecheck/rust-type-util.cc
index 005defb50..f90c95953 100644
--- a/gcc/rust/typecheck/rust-type-util.cc
+++ b/gcc/rust/typecheck/rust-type-util.cc
@@ -257,8 +257,8 @@ unify_site (HirId id, TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs,
   std::vector<UnifyRules::CommitSite> commits;
   std::vector<UnifyRules::InferenceSite> infers;
   return UnifyRules::Resolve (lhs, rhs, unify_locus, true /*commit*/,
-			      true /*emit_error*/, false /*infer*/,
-			      true /*check_bounds*/, commits, infers);
+			      true /*emit_error*/, true /*check_bounds*/,
+			      false /*infer*/, commits, infers);
 }
 
 TyTy::BaseType *
@@ -283,7 +283,7 @@ unify_site_and (HirId id, TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs,
   std::vector<UnifyRules::InferenceSite> infers;
   TyTy::BaseType *result
     = UnifyRules::Resolve (lhs, rhs, unify_locus, false /*commit inline*/,
-			   emit_errors, implicit_infer_vars, check_bounds,
+			   emit_errors, check_bounds, implicit_infer_vars,
 			   commits, infers);
   bool ok = result->get_kind () != TyTy::TypeKind::ERROR;
 
diff --git a/gcc/rust/typecheck/rust-typecheck-context.cc b/gcc/rust/typecheck/rust-typecheck-context.cc
index 44744730b..57fc768cb 100644
--- a/gcc/rust/typecheck/rust-typecheck-context.cc
+++ b/gcc/rust/typecheck/rust-typecheck-context.cc
@@ -725,8 +725,7 @@ bool
 TypeCheckContext::compute_ambigious_op_overload (HirId id,
 						 DeferredOpOverload &op)
 {
-  rust_debug ("attempting resolution of op overload: %s",
-	      op.predicate.as_string ().c_str ());
+  rust_debug ("attempting resolution of deferred operator overload");
 
   TyTy::BaseType *lhs = nullptr;
   bool ok = lookup_type (op.op.get_lvalue_mappings ().get_hirid (), &lhs);
@@ -739,8 +738,28 @@ TypeCheckContext::compute_ambigious_op_overload (HirId id,
       rust_assert (ok);
     }
 
-  TypeCheckExpr::ResolveOpOverload (op.lang_item_type, op.op, lhs, rhs,
-				    op.specified_segment);
+  TyTy::BaseType *current_result = op.result_type.get_tyty ();
+  rust_assert (current_result != nullptr);
+
+  rust_debug ("deferred operator expr=%u lhs=%s rhs=%s "
+	      "stored-result=%s current-result=%s result-ref=%u ty-ref=%u",
+	      id, lhs->debug_str ().c_str (),
+	      rhs == nullptr ? "<none>" : rhs->debug_str ().c_str (),
+	      current_result->debug_str ().c_str (),
+	      current_result->debug_str ().c_str (), op.result_type.get_ref (),
+	      current_result->get_ty_ref ());
+
+  TyTy::BaseType *resolved
+    = TypeCheckExpr::ResolveOpOverload (op.lang_item_type, op.op, lhs, rhs,
+					op.specified_segment, current_result);
+  if (resolved == nullptr)
+    return false;
+
+  TyTy::BaseType *result
+    = unify_site (id, TyTy::TyWithLocation (current_result),
+		  TyTy::TyWithLocation (resolved), op.op.get_locus ());
+  rust_assert (result != nullptr);
+  rust_assert (result->get_kind () != TyTy::TypeKind::ERROR);
 
   return true;
 }
@@ -748,14 +767,33 @@ TypeCheckContext::compute_ambigious_op_overload (HirId id,
 void
 TypeCheckContext::compute_inference_variables (bool emit_error)
 {
-  iterate_deferred_operator_overloads (
-    [&] (HirId id, DeferredOpOverload &op) mutable -> bool {
-      return compute_ambigious_op_overload (id, op);
-    });
+  auto resolve_deferred_operator_overloads = [this] () {
+    bool progress;
+    do
+      {
+	progress = false;
+	for (auto it = deferred_operator_overloads.begin ();
+	     it != deferred_operator_overloads.end ();)
+	  {
+	    if (compute_ambigious_op_overload (it->first, it->second))
+	      {
+		it = deferred_operator_overloads.erase (it);
+		progress = true;
+	      }
+	    else
+	      ++it;
+	  }
+      }
+    while (progress);
+  };
+
+  resolve_deferred_operator_overloads ();
 
   iterate ([&] (HirId id, TyTy::BaseType *ty) mutable -> bool {
     return compute_infer_var (id, ty, emit_error);
   });
+
+  resolve_deferred_operator_overloads ();
 }
 
 bool
@@ -771,9 +809,15 @@ TypeCheckContext::compute_infer_var (HirId id, TyTy::BaseType *ty,
   TyTy::InferType *infer_var = static_cast<TyTy::InferType *> (ty);
   TyTy::BaseType *default_type;
 
+  TyTy::BaseType *current = TyTy::TyVar (ty->get_ref ()).get_tyty ();
+  rust_assert (current != nullptr);
+
   rust_debug_loc (mappings.lookup_location (id),
-		  "trying to default infer-var: %s",
-		  infer_var->as_string ().c_str ());
+		  "trying to default infer-var id=%u ref=%u ty-ref=%u "
+		  "stored=%s current=%s",
+		  id, ty->get_ref (), ty->get_ty_ref (),
+		  infer_var->debug_str ().c_str (),
+		  current->debug_str ().c_str ());
   bool ok = infer_var->default_type (&default_type);
   if (!ok)
     {
@@ -783,6 +827,9 @@ TypeCheckContext::compute_infer_var (HirId id, TyTy::BaseType *ty,
       return true;
     }
 
+  rust_debug_loc (mappings.lookup_location (id), "default type selected: %s",
+		  default_type->debug_str ().c_str ());
+
   auto result
     = unify_site (id, TyTy::TyWithLocation (ty),
 		  TyTy::TyWithLocation (default_type), UNDEF_LOCATION);
diff --git a/gcc/rust/typecheck/rust-unify.cc b/gcc/rust/typecheck/rust-unify.cc
index e6a863a5b..c8dee6214 100644
--- a/gcc/rust/typecheck/rust-unify.cc
+++ b/gcc/rust/typecheck/rust-unify.cc
@@ -18,7 +18,6 @@
 
 #include "rust-unify.h"
 #include "fold-const.h"
-#include "rust-substitution-mapper.h"
 #include "rust-tyty-util.h"
 #include "rust-tyty.h"
 #include "rust-type-util.h"
@@ -53,7 +52,7 @@ UnifyRules::Resolve (TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs,
 		     std::vector<CommitSite> &commits,
 		     std::vector<InferenceSite> &infers)
 {
-  UnifyRules r (lhs, rhs, locus, commit_flag, emit_error, infer, check_bounds,
+  UnifyRules r (lhs, rhs, locus, commit_flag, emit_error, check_bounds, infer,
 		commits, infers);
 
   TyTy::BaseType *result = r.go ();
@@ -76,8 +75,8 @@ TyTy::BaseType *
 UnifyRules::resolve_subtype (TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs)
 {
   TyTy::BaseType *result
-    = UnifyRules::Resolve (lhs, rhs, locus, commit_flag, emit_error, infer_flag,
-			   check_bounds_flag, commits, infers);
+    = UnifyRules::Resolve (lhs, rhs, locus, commit_flag, emit_error,
+			   check_bounds_flag, infer_flag, commits, infers);
 
   // 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
diff --git a/gcc/rust/typecheck/rust-unify.h b/gcc/rust/typecheck/rust-unify.h
index c812cfb2f..f57914032 100644
--- a/gcc/rust/typecheck/rust-unify.h
+++ b/gcc/rust/typecheck/rust-unify.h
@@ -54,8 +54,8 @@ public:
 
   static TyTy::BaseType *Resolve (TyTy::TyWithLocation lhs,
 				  TyTy::TyWithLocation rhs, location_t locus,
-				  bool commit_flag, bool emit_error, bool infer,
-				  bool check_bounds,
+				  bool commit_flag, bool emit_error,
+				  bool check_bounds, bool infer,
 				  std::vector<CommitSite> &commits,
 				  std::vector<InferenceSite> &infers);
 
diff --git a/gcc/testsuite/rust/execute/torture/deferred-add-partial-ord.rs b/gcc/testsuite/rust/execute/torture/deferred-add-partial-ord.rs
new file mode 100644
index 000000000..6d23dd5f5
--- /dev/null
+++ b/gcc/testsuite/rust/execute/torture/deferred-add-partial-ord.rs
@@ -0,0 +1,58 @@
+// { dg-additional-options "-w" }
+#![feature(no_core)]
+#![no_core]
+
+#![feature(rustc_attrs, lang_items)]
+
+#[lang = "sized"]
+trait Sized {}
+
+#[lang = "add"]
+trait Add<Rhs = Self> {
+    type Output;
+
+    fn add(self, rhs: Rhs) -> Self::Output;
+}
+
+#[lang = "partial_ord"]
+trait PartialOrd<Rhs: ?Sized = Self> {
+    fn lt(&self, other: &Rhs) -> bool;
+}
+
+macro_rules! add_impl {
+    ($($t:ty)*) => ($(
+        impl Add for $t {
+            type Output = $t;
+
+            #[inline]
+            #[rustc_inherit_overflow_checks]
+            fn add(self, other: $t) -> $t { self + other }
+        }
+    )*)
+}
+
+macro_rules! partial_ord_impl {
+    ($($t:ty)*) => ($(
+        impl PartialOrd for $t {
+            fn lt(&self, other: &$t) -> bool { *self < *other }
+        }
+    )*)
+}
+
+add_impl! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 isize }
+partial_ord_impl! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 isize }
+
+fn test(len: usize) -> u64 {
+    let mut i = 0;
+    let mut out = 0;
+    if i + 3 < len {
+        out = 123;
+    } else {
+        out = 456;
+    }
+    out
+}
+
+fn main() -> i32 {
+    test(4) as i32 - 123 + test(3) as i32 - 456
+}

base-commit: 32c84030f87e29d0ddf080ff746dcd131b909c70
-- 
2.55.0



More information about the Gcc-rust mailing list