[COMMITTED 58/83] gccrs: improve handling of defered operator overload handling
arthur.cohen@opensrcsec.com
arthur.cohen@opensrcsec.com
Wed Sep 16 12:30:17 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>
---
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 89a596a2827..8fd7f1d0093 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 79c5db1c079..78c33217bc4 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 4824209aecb..cc967d4b301 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 100dc0ccf35..f7a97086c68 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 1e830713ee8..f1db16c5f18 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 005defb50a6..f90c959532d 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 44744730b53..57fc768cb62 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 e6a863a5bd0..c8dee621452 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 c812cfb2f13..f57914032d4 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 00000000000..6d23dd5f539
--- /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
+}
--
2.50.1
More information about the Gcc-rust
mailing list