diff --git a/gcc/rust/typecheck/rust-hir-type-check-stmt.cc b/gcc/rust/typecheck/rust-hir-type-check-stmt.cc index e3d92a53c905..6b2b1e906a6d 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-stmt.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-stmt.cc @@ -84,10 +84,90 @@ TypeCheckStmt::visit (HIR::LetStmt &stmt) auto &stmt_pattern = stmt.get_pattern (); TyTy::BaseType *init_expr_ty = nullptr; location_t init_expr_locus = UNKNOWN_LOCATION; + if (stmt.has_init_expr ()) { - init_expr_locus = stmt.get_init_expr ().get_locus (); - init_expr_ty = TypeCheckExpr::Resolve (stmt.get_init_expr ()); + HIR::Expr &init = stmt.get_init_expr (); + init_expr_locus = init.get_locus (); + init_expr_ty = TypeCheckExpr::Resolve (init); + + if (stmt_pattern.get_pattern_type () + == HIR::Pattern::PatternType::IDENTIFIER) + { + auto &ident = static_cast (stmt_pattern); + + if (ident.get_is_ref () && ident.is_mut ()) + { + NodeId def_id = UNKNOWN_NODEID; + bool found = false; + auto resolver = Rust::Resolver::Resolver::get (); + + if (resolver->lookup_resolved_name ( + init.get_mappings ().get_nodeid (), &def_id)) + { + found = true; + } + else if (init.get_expression_type () == HIR::Expr::ExprType::Path) + { + auto &path_expr = static_cast (init); + + if (resolver->lookup_resolved_name ( + path_expr.get_mappings ().get_nodeid (), &def_id)) + { + found = true; + } + else + { + for (auto &seg : path_expr.get_segments ()) + { + if (resolver->lookup_resolved_name ( + seg.get_mappings ().get_nodeid (), &def_id)) + { + found = true; + break; + } + } + } + } + + if (found) + { + bool is_mutable = false; + auto &mappings = Analysis::Mappings::get (); + + auto result_hir_id = mappings.lookup_node_to_hir (def_id); + if (result_hir_id.has_value ()) + { + HirId var_hir_id = result_hir_id.value (); + auto result_pattern + = mappings.lookup_hir_pattern (var_hir_id); + + if (result_pattern.has_value ()) + { + HIR::Pattern *def_pattern = result_pattern.value (); + + if (def_pattern + && def_pattern->get_pattern_type () + == HIR::Pattern::PatternType::IDENTIFIER) + { + auto def_ident + = static_cast ( + def_pattern); + + if (def_ident->is_mut ()) + is_mutable = true; + } + } + } + + if (!is_mutable) + rust_error_at ( + stmt_pattern.get_locus (), + "cannot borrow immutable local variable as mutable"); + } + } + } + if (init_expr_ty->get_kind () == TyTy::TypeKind::ERROR) return; diff --git a/gcc/testsuite/rust/compile/issue-4289.rs b/gcc/testsuite/rust/compile/issue-4289.rs new file mode 100644 index 000000000000..65b479c8d4c2 --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-4289.rs @@ -0,0 +1,19 @@ +// { dg-options "-frust-incomplete-and-experimental-compiler-do-not-use" } +#![feature(no_core)] +#![feature(lang_items)] +#![no_core] + +#[lang = "sized"] +pub trait Sized {} + +pub fn a() { + let v = 10; + let ref mut r = v; // { dg-error "cannot borrow immutable local variable as mutable" } +} + +pub fn b() { + let mut v2 = 10; + let ref mut r2 = v2; // Should compile fine +} + +fn main() {} \ No newline at end of file