Skip to content

Commit ad38cff

Browse files
committed
gccrs: Emit error when borrowing immutable variable as mutable
Fixes #4289 Rust rules strictly forbid creating a mutable reference ('&mut T') to an immutable binding. Previously, the compiler failed to validate the mutability of the source variable when using a 'ref mut' pattern. This patch adds verification logic to TypeCheckStmt to check the mutability status of the variable definition. gcc/rust/ChangeLog: * typecheck/rust-hir-type-check-stmt.cc (TypeCheckStmt::visit): Add check to ensure 'ref mut' patterns bind to mutable variables. gcc/testsuite/ChangeLog: * rust/compile/issue-4289.rs: New test. Signed-off-by: Jayant Chauhan <[email protected]>
1 parent 32622b7 commit ad38cff

File tree

2 files changed

+92
-2
lines changed

2 files changed

+92
-2
lines changed

gcc/rust/typecheck/rust-hir-type-check-stmt.cc

Lines changed: 82 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,10 +84,90 @@ TypeCheckStmt::visit (HIR::LetStmt &stmt)
8484
auto &stmt_pattern = stmt.get_pattern ();
8585
TyTy::BaseType *init_expr_ty = nullptr;
8686
location_t init_expr_locus = UNKNOWN_LOCATION;
87+
8788
if (stmt.has_init_expr ())
8889
{
89-
init_expr_locus = stmt.get_init_expr ().get_locus ();
90-
init_expr_ty = TypeCheckExpr::Resolve (stmt.get_init_expr ());
90+
HIR::Expr &init = stmt.get_init_expr ();
91+
init_expr_locus = init.get_locus ();
92+
init_expr_ty = TypeCheckExpr::Resolve (init);
93+
94+
if (stmt_pattern.get_pattern_type ()
95+
== HIR::Pattern::PatternType::IDENTIFIER)
96+
{
97+
auto &ident = static_cast<HIR::IdentifierPattern &> (stmt_pattern);
98+
99+
if (ident.get_is_ref () && ident.is_mut ())
100+
{
101+
NodeId def_id = UNKNOWN_NODEID;
102+
bool found = false;
103+
auto resolver = Rust::Resolver::Resolver::get ();
104+
105+
if (resolver->lookup_resolved_name (
106+
init.get_mappings ().get_nodeid (), &def_id))
107+
{
108+
found = true;
109+
}
110+
else if (init.get_expression_type () == HIR::Expr::ExprType::Path)
111+
{
112+
auto &path_expr = static_cast<HIR::PathInExpression &> (init);
113+
114+
if (resolver->lookup_resolved_name (
115+
path_expr.get_mappings ().get_nodeid (), &def_id))
116+
{
117+
found = true;
118+
}
119+
else
120+
{
121+
for (auto &seg : path_expr.get_segments ())
122+
{
123+
if (resolver->lookup_resolved_name (
124+
seg.get_mappings ().get_nodeid (), &def_id))
125+
{
126+
found = true;
127+
break;
128+
}
129+
}
130+
}
131+
}
132+
133+
if (found)
134+
{
135+
bool is_mutable = false;
136+
auto &mappings = Analysis::Mappings::get ();
137+
138+
auto result_hir_id = mappings.lookup_node_to_hir (def_id);
139+
if (result_hir_id.has_value ())
140+
{
141+
HirId var_hir_id = result_hir_id.value ();
142+
auto result_pattern
143+
= mappings.lookup_hir_pattern (var_hir_id);
144+
145+
if (result_pattern.has_value ())
146+
{
147+
HIR::Pattern *def_pattern = result_pattern.value ();
148+
149+
if (def_pattern
150+
&& def_pattern->get_pattern_type ()
151+
== HIR::Pattern::PatternType::IDENTIFIER)
152+
{
153+
auto def_ident
154+
= static_cast<HIR::IdentifierPattern *> (
155+
def_pattern);
156+
157+
if (def_ident->is_mut ())
158+
is_mutable = true;
159+
}
160+
}
161+
}
162+
163+
if (!is_mutable)
164+
rust_error_at (
165+
stmt_pattern.get_locus (),
166+
"cannot borrow immutable local variable as mutable");
167+
}
168+
}
169+
}
170+
91171
if (init_expr_ty->get_kind () == TyTy::TypeKind::ERROR)
92172
return;
93173

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// { dg-options "-fsyntax-only" }
2+
pub fn a() {
3+
let v = 10;
4+
let ref mut r = v; // { dg-error "cannot borrow immutable local variable as mutable" }
5+
}
6+
7+
pub fn b() {
8+
let mut v2 = 10;
9+
let ref mut r2 = v2; // Should compile fine
10+
}

0 commit comments

Comments
 (0)