https://gcc.gnu.org/g:7ee78472f023cd1f1ca266318135d477d8fb5460
commit r17-5147-g7ee78472f023cd1f1ca266318135d477d8fb5460 Author: Philip Herron <[email protected]> Date: Fri Sep 18 19:00:40 2026 +0100 gccrs: Add flag to unify of expect never 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]> Diff: --- 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(-) diff --git a/gcc/rust/typecheck/rust-coercion.cc b/gcc/rust/typecheck/rust-coercion.cc index 4df9934d81c5..9d4de57db752 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 0674cf5df568..be5daf39f2a6 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 06d9aa88ecb5..24b8b8ccc172 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 2234f89e0e03..7df36f0d3cff 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 860f23cfc1ef..89687d9f2f1f 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 417804b447bb..db6dabcf8d39 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 2091bd1b14bc..29938cfffca7 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 000000000000..b378d1b35641 --- /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); +}
