Skip to content

Commit

Permalink
gccrs: improve mutability checks
Browse files Browse the repository at this point in the history
This ensures that we handle var decls readonly checks much better

Addresses: #807 #3287

gcc/rust/ChangeLog:

	* checks/errors/rust-readonly-check.cc (check_decl): improve mut check
	(emit_error): helper
	(check_modify_expr): likewise
	(readonly_walk_fn): reuse helper
	(ReadonlyCheck::Lint): cleanup context each run

gcc/testsuite/ChangeLog:

	* rust/execute/torture/builtin_macro_include_bytes.rs: missing mut

Signed-off-by: Philip Herron <[email protected]>
  • Loading branch information
philberty committed Dec 18, 2024
1 parent daa2977 commit 95baad8
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 10 deletions.
54 changes: 45 additions & 9 deletions gcc/rust/checks/errors/rust-readonly-check.cc
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,13 @@
#include "rust-readonly-check.h"
#include "rust-tree.h"
#include "rust-gcc.h"
#include "print-tree.h"

namespace Rust {
namespace Analysis {

static std::map<tree, int> assignment_map = {};

// ported over from c-family/c-warn.cc
void
readonly_error (location_t loc, tree arg, enum lvalue_use use)
Expand Down Expand Up @@ -106,37 +109,68 @@ readonly_error (location_t loc, tree arg, enum lvalue_use use)
}

static void
check_decl (tree *t)
emit_error (tree *t, tree lhs, enum lvalue_use use)
{
if (TREE_CODE (*t) == MODIFY_EXPR)
readonly_error (EXPR_LOCATION (*t), lhs, use);
TREE_OPERAND (*t, 0) = error_mark_node;
}

static void
check_modify_expr (tree *t)
{
tree lhs = TREE_OPERAND (*t, 0);
if (TREE_CODE (lhs) == ARRAY_REF || TREE_CODE (lhs) == COMPONENT_REF)
lhs = TREE_OPERAND (lhs, 0);

tree lhs_type = TREE_TYPE (lhs);
if (TYPE_READONLY (lhs_type) || TREE_READONLY (lhs) || TREE_CONSTANT (lhs))
{
tree lhs = TREE_OPERAND (*t, 0);
if (TREE_READONLY (lhs) || TREE_CONSTANT (lhs))
if (TREE_CODE (lhs) != VAR_DECL)
emit_error (t, lhs, lv_assign);
else if (!DECL_ARTIFICIAL (lhs))
{
readonly_error (EXPR_LOCATION (*t), lhs, lv_assign);
TREE_OPERAND (*t, 0) = error_mark_node;
if (DECL_INITIAL (lhs) != NULL)
emit_error (t, lhs, lv_assign);
else
{
if (assignment_map.find (lhs) == assignment_map.end ())
{
assignment_map.insert ({lhs, 0});
}
assignment_map[lhs]++;

if (assignment_map[lhs] > 1)
emit_error (t, lhs, lv_assign);
}
}
}
}

static tree
readonly_walk_fn (tree *t, int *, void *)
static void
check_decl (tree *t)
{
switch (TREE_CODE (*t))
{
case MODIFY_EXPR:
check_decl (t);
check_modify_expr (t);
break;

default:
break;
}
}

static tree
readonly_walk_fn (tree *t, int *, void *)
{
check_decl (t);
return NULL_TREE;
}

void
ReadonlyCheck::Lint (Compile::Context &ctx)
{
assignment_map.clear ();
for (auto &fndecl : ctx.get_func_decls ())
{
for (tree p = DECL_ARGUMENTS (fndecl); p != NULL_TREE; p = DECL_CHAIN (p))
Expand All @@ -148,12 +182,14 @@ ReadonlyCheck::Lint (Compile::Context &ctx)
&readonly_walk_fn, &ctx);
}

assignment_map.clear ();
for (auto &var : ctx.get_var_decls ())
{
tree decl = var->get_decl ();
check_decl (&decl);
}

assignment_map.clear ();
for (auto &const_decl : ctx.get_const_decls ())
{
check_decl (&const_decl);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ fn print_int(value: i32) {
fn check_bytes(bytes: &[u8; 16]) {
let the_bytes = b"hello, include!\n";

let x = true;
let mut x = true;
let mut i = 0;

// X is true iff bytes == the_bytes
Expand Down

0 comments on commit 95baad8

Please sign in to comment.