Skip to content

Commit c3f8c28

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 <0001jayant@gmail.com>
1 parent 32622b7 commit c3f8c28

File tree

2 files changed

+93
-2
lines changed

2 files changed

+93
-2
lines changed

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

Lines changed: 83 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,10 +84,91 @@ 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 (init.get_expression_type () == HIR::Expr::ExprType::Path)
106+
{
107+
auto &path_expr = static_cast<HIR::PathInExpression &> (init);
108+
109+
if (resolver->lookup_resolved_name (
110+
path_expr.get_mappings ().get_nodeid (), &def_id))
111+
{
112+
found = true;
113+
}
114+
else if (path_expr.get_segments ().size () > 0)
115+
{
116+
NodeId segment_id = path_expr.get_segments ()
117+
.back ()
118+
.get_mappings ()
119+
.get_nodeid ();
120+
if (resolver->lookup_resolved_name (segment_id, &def_id))
121+
{
122+
found = true;
123+
}
124+
}
125+
}
126+
127+
if (!found
128+
&& resolver->lookup_resolved_name (
129+
init.get_mappings ().get_nodeid (), &def_id))
130+
{
131+
found = true;
132+
}
133+
134+
if (found)
135+
{
136+
bool is_mutable = false;
137+
auto &mappings = Analysis::Mappings::get ();
138+
139+
auto result_hir_id = mappings.lookup_node_to_hir (def_id);
140+
if (result_hir_id.has_value ())
141+
{
142+
HirId var_hir_id = result_hir_id.value ();
143+
auto result_pattern
144+
= mappings.lookup_hir_pattern (var_hir_id);
145+
146+
if (result_pattern.has_value ())
147+
{
148+
HIR::Pattern *def_pattern = result_pattern.value ();
149+
150+
if (def_pattern
151+
&& def_pattern->get_pattern_type ()
152+
== HIR::Pattern::PatternType::IDENTIFIER)
153+
{
154+
auto def_ident
155+
= static_cast<HIR::IdentifierPattern *> (
156+
def_pattern);
157+
158+
if (def_ident->is_mut ())
159+
is_mutable = true;
160+
}
161+
}
162+
}
163+
164+
if (!is_mutable)
165+
rust_error_at (
166+
stmt_pattern.get_locus (),
167+
"cannot borrow immutable local variable as mutable");
168+
}
169+
}
170+
}
171+
91172
if (init_expr_ty->get_kind () == TyTy::TypeKind::ERROR)
92173
return;
93174

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)