From: Utkarsh Bahuguna <[email protected]>
Expressions that failed to type check never put their error type in the
context, so a later lookup got null and crashed. Keep it. Operators and
array literals now also bail on an operand that already errored instead
of stacking mismatched types on top, and consts keep their declared type
when the init fails.
Fixes Rust-GCC/gccrs#5039
Assisted-by: Claude Opus (Anthropic)
gcc/rust/ChangeLog:
* typecheck/rust-hir-type-check-expr.cc (TypeCheckExpr::Resolve):
Keep the error type in the context.
(TypeCheckExpr::visit (AssignmentExpr)): Bail out on an error
operand.
(TypeCheckExpr::visit (CompoundAssignmentExpr)): Likewise.
(TypeCheckExpr::visit (ArithmeticOrLogicalExpr)): Likewise.
(TypeCheckExpr::visit (ComparisonExpr)): Likewise.
(TypeCheckExpr::visit (LazyBooleanExpr)): Likewise.
(TypeCheckExpr::visit (NegationExpr)): Likewise.
(TypeCheckExpr::visit (ArrayExpr)): Bail out on an error element.
* typecheck/rust-hir-type-check-item.cc (TypeCheckItem::visit
(StaticItem)): Keep the declared type when the initializer failed.
(TypeCheckItem::visit (ConstantItem)): Likewise.
gcc/testsuite/ChangeLog:
* rust/compile/issues/4165.rs: Drop the follow-up error.
* rust/compile/issues/issue-5039.rs: New test.
* rust/compile/issues/issue-5039-2.rs: New test.
Signed-off-by: Utkarsh Bahuguna <[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/73d92a68d41785df58d1b356a57b78a80d3142e9
The commit has been mentioned in the following issue(s):
- Rust-GCC/gccrs#5039: https://github.com/Rust-GCC/gccrs/issues/5039
The commit has been mentioned in the following pull-request(s):
- https://github.com/Rust-GCC/gccrs/pull/5040
.../typecheck/rust-hir-type-check-expr.cc | 30 ++++++++++++++++++-
.../typecheck/rust-hir-type-check-item.cc | 26 +++++++++-------
gcc/testsuite/rust/compile/issues/4165.rs | 1 -
.../rust/compile/issues/issue-5039-2.rs | 14 +++++++++
.../rust/compile/issues/issue-5039.rs | 25 ++++++++++++++++
5 files changed, 83 insertions(+), 13 deletions(-)
create mode 100644 gcc/testsuite/rust/compile/issues/issue-5039-2.rs
create mode 100644 gcc/testsuite/rust/compile/issues/issue-5039.rs
diff --git a/gcc/rust/typecheck/rust-hir-type-check-expr.cc
b/gcc/rust/typecheck/rust-hir-type-check-expr.cc
index b7acb787f..db88c8c1b 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-expr.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check-expr.cc
@@ -50,8 +50,10 @@ TypeCheckExpr::Resolve (HIR::Expr &expr)
TypeCheckExpr resolver;
expr.accept_vis (resolver);
+ // the error type has to go in the context like any other, autoderef
+ // looks this expression's type up by ref later and would get nullptr
if (resolver.infered == nullptr)
- return new TyTy::ErrorType (expr.get_mappings ().get_hirid ());
+ resolver.infered = new TyTy::ErrorType (expr.get_mappings ().get_hirid ());
if (resolver.infered->get_kind () != TyTy::TypeKind::CONST)
{
@@ -405,6 +407,9 @@ TypeCheckExpr::visit (HIR::AssignmentExpr &expr)
auto lhs = TypeCheckExpr::Resolve (expr.get_lhs ());
auto rhs = TypeCheckExpr::Resolve (expr.get_rhs ());
+ if (lhs->is<TyTy::ErrorType> () || rhs->is<TyTy::ErrorType> ())
+ return;
+
coercion_site (expr.get_mappings ().get_hirid (),
TyTy::TyWithLocation (lhs, expr.get_lhs ().get_locus ()),
TyTy::TyWithLocation (rhs, expr.get_rhs ().get_locus ()),
@@ -419,6 +424,9 @@ TypeCheckExpr::visit (HIR::CompoundAssignmentExpr &expr)
auto lhs = TypeCheckExpr::Resolve (expr.get_lhs ());
auto rhs = TypeCheckExpr::Resolve (expr.get_rhs ());
+ if (lhs->is<TyTy::ErrorType> () || rhs->is<TyTy::ErrorType> ())
+ return;
+
auto lang_item_type
= LangItem::CompoundAssignmentOperatorToLangItem (expr.get_expr_type ());
bool operator_overloaded
@@ -472,6 +480,9 @@ TypeCheckExpr::visit (HIR::ArithmeticOrLogicalExpr &expr)
auto lhs = TypeCheckExpr::Resolve (expr.get_lhs ());
auto rhs = TypeCheckExpr::Resolve (expr.get_rhs ());
+ if (lhs->is<TyTy::ErrorType> () || rhs->is<TyTy::ErrorType> ())
+ return;
+
auto lang_item_type = LangItem::OperatorToLangItem (expr.get_expr_type ());
bool operator_overloaded
= resolve_operator_overload (lang_item_type, expr, lhs, rhs);
@@ -520,6 +531,9 @@ TypeCheckExpr::visit (HIR::ComparisonExpr &expr)
auto lhs = TypeCheckExpr::Resolve (expr.get_lhs ());
auto rhs = TypeCheckExpr::Resolve (expr.get_rhs ());
+ if (lhs->is<TyTy::ErrorType> () || rhs->is<TyTy::ErrorType> ())
+ return;
+
auto borrowed_lhs
= new TyTy::ReferenceType (mappings.get_next_hir_id (),
TyTy::TyVar (lhs->get_ref ()), Mutability::Imm);
@@ -555,6 +569,9 @@ TypeCheckExpr::visit (HIR::LazyBooleanExpr &expr)
auto lhs = TypeCheckExpr::Resolve (expr.get_lhs ());
auto rhs = TypeCheckExpr::Resolve (expr.get_rhs ());
+ if (lhs->is<TyTy::ErrorType> () || rhs->is<TyTy::ErrorType> ())
+ return;
+
// we expect the lhs and rhs must be bools at this point
TyTy::BaseType *boolean_node = nullptr;
bool ok = context->lookup_builtin ("bool", &boolean_node);
@@ -585,6 +602,9 @@ TypeCheckExpr::visit (HIR::NegationExpr &expr)
{
auto negated_expr_ty = TypeCheckExpr::Resolve (expr.get_expr ());
+ if (negated_expr_ty->is<TyTy::ErrorType> ())
+ return;
+
// check for operator overload
auto lang_item_type
= LangItem::NegationOperatorToLangItem (expr.get_expr_type ());
@@ -1232,6 +1252,9 @@ TypeCheckExpr::visit (HIR::ArrayExpr &expr)
= TyTy::TyVar::get_implicit_infer_var (expr.get_locus ()).get_tyty ();
for (auto &type : types)
{
+ if (type->is<TyTy::ErrorType> ())
+ return;
+
element_type
= unify_site (expr.get_mappings ().get_hirid (),
TyTy::TyWithLocation (element_type),
@@ -1239,6 +1262,11 @@ TypeCheckExpr::visit (HIR::ArrayExpr &expr)
expr.get_locus ());
}
+ // a failed unify leaves the shared error node here, whose ref
+ // isn't in the context
+ if (element_type->is<TyTy::ErrorType> ())
+ return;
+
auto crate_num = mappings.crate.get_current_crate ();
Analysis::NodeMapping mapping (crate_num, UNKNOWN_NODEID,
mappings.get_next_hir_id (crate_num),
diff --git a/gcc/rust/typecheck/rust-hir-type-check-item.cc
b/gcc/rust/typecheck/rust-hir-type-check-item.cc
index 1f66d68ac..1b974b5cf 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-item.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check-item.cc
@@ -738,12 +738,13 @@ TypeCheckItem::visit (HIR::StaticItem &var)
TyTy::BaseType *type = TypeCheckType::Resolve (var.get_type ());
TyTy::BaseType *expr_type = TypeCheckExpr::Resolve (var.get_expr ());
- TyTy::BaseType *unified
- = coercion_site (var.get_mappings ().get_hirid (),
- TyTy::TyWithLocation (type, var.get_type ().get_locus ()),
- TyTy::TyWithLocation (expr_type,
- var.get_expr ().get_locus ()),
- var.get_locus ());
+ TyTy::BaseType *unified = type;
+ if (!expr_type->is<TyTy::ErrorType> ())
+ unified = coercion_site (
+ var.get_mappings ().get_hirid (),
+ TyTy::TyWithLocation (type, var.get_type ().get_locus ()),
+ TyTy::TyWithLocation (expr_type, var.get_expr ().get_locus ()),
+ var.get_locus ());
context->insert_type (var.get_mappings (), unified);
infered = unified;
}
@@ -756,11 +757,14 @@ TypeCheckItem::visit (HIR::ConstantItem &constant)
TyTy::BaseType *expr_type = TypeCheckExpr::Resolve (constant.get_expr ());
context->pop_const_context ();
- TyTy::BaseType *unified = coercion_site (
- constant.get_mappings ().get_hirid (),
- TyTy::TyWithLocation (type, constant.get_type ().get_locus ()),
- TyTy::TyWithLocation (expr_type, constant.get_expr ().get_locus ()),
- constant.get_locus ());
+ // the declared type stands if the initializer failed
+ TyTy::BaseType *unified = type;
+ if (!expr_type->is<TyTy::ErrorType> ())
+ unified = coercion_site (
+ constant.get_mappings ().get_hirid (),
+ TyTy::TyWithLocation (type, constant.get_type ().get_locus ()),
+ TyTy::TyWithLocation (expr_type, constant.get_expr ().get_locus ()),
+ constant.get_locus ());
context->insert_type (constant.get_mappings (), unified);
infered = unified;
}
diff --git a/gcc/testsuite/rust/compile/issues/4165.rs
b/gcc/testsuite/rust/compile/issues/4165.rs
index 673c44702..e5fd9fec9 100644
--- a/gcc/testsuite/rust/compile/issues/4165.rs
+++ b/gcc/testsuite/rust/compile/issues/4165.rs
@@ -7,7 +7,6 @@ const ARR: [i32; N] = [42; X];
// { dg-error {mismatched types, expected .usize. but got .bool. \[E0308\]} ""
{ target *-*-* } .-2 }
const X: bool = (N[0] == 99) && (ARR[0] == 0);
// { dg-error {the type .usize. cannot be indexed by .<integer>. \[E0277\]} ""
{ target *-*-* } .-1 }
-// { dg-error {mismatched types, expected .<tyty::error>. but got .<integer>.
\[E0308\]} "" { target *-*-* } .-2 }
fn main() {
let _ = X;
diff --git a/gcc/testsuite/rust/compile/issues/issue-5039-2.rs
b/gcc/testsuite/rust/compile/issues/issue-5039-2.rs
new file mode 100644
index 000000000..71a7fdb84
--- /dev/null
+++ b/gcc/testsuite/rust/compile/issues/issue-5039-2.rs
@@ -0,0 +1,14 @@
+#![feature(no_core, lang_items)]
+#![no_core]
+
+// Rust-GCC/gccrs#5039: an error-typed array element crashed when the array
+// was coerced to a slice.
+
+#[lang = "sized"]
+pub trait Sized {}
+
+pub fn g(_s: &[u32]) {}
+
+pub fn f(v: &[u32]) {
+ g(&[v.nope(), 1]); // { dg-error "no method named .nope." }
+}
diff --git a/gcc/testsuite/rust/compile/issues/issue-5039.rs
b/gcc/testsuite/rust/compile/issues/issue-5039.rs
new file mode 100644
index 000000000..6a508c00f
--- /dev/null
+++ b/gcc/testsuite/rust/compile/issues/issue-5039.rs
@@ -0,0 +1,25 @@
+#![feature(no_core, lang_items)]
+#![no_core]
+
+// Rust-GCC/gccrs#5039: applying an operator to an error-typed value crashed
+// while resolving the operator overload.
+
+#[lang = "sized"]
+pub trait Sized {}
+
+#[lang = "mul"]
+pub trait Mul<Rhs> {
+ type Output;
+ fn mul(self, rhs: Rhs) -> Self::Output;
+}
+
+impl Mul<i32> for i32 {
+ type Output = i32;
+ fn mul(self, rhs: i32) -> i32 {
+ self
+ }
+}
+
+pub fn f(v: &[u32]) {
+ let _ = v.nope() * 2; // { dg-error "no method named .nope." }
+}
base-commit: ff803d56a0b12e64a48cf213bc1508cdebd9a73d
--
2.56.0