aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorPhilip Herron <herron.philip@googlemail.com>2024-12-16 14:51:17 +0000
committerPhilip Herron <philip.herron@embecosm.com>2025-01-10 10:43:13 +0000
commitc957f18575fbe8208e01674cd446652323a7eb1b (patch)
tree09ea31fe6aae2b177cd467f8090ad8c1ea0f19c9 /gcc
parentf68fbff016d4faacd54de63549d43255e1193688 (diff)
downloadgcc-c957f18575fbe8208e01674cd446652323a7eb1b.zip
gcc-c957f18575fbe8208e01674cd446652323a7eb1b.tar.gz
gcc-c957f18575fbe8208e01674cd446652323a7eb1b.tar.bz2
gccrs: improve mutability checks
This ensures that we handle var decls readonly checks much better Addresses: Rust-GCC#807 Rust-GCC#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: needs mut * rust/compile/mutability_checks1.rs: New test. Signed-off-by: Philip Herron <herron.philip@googlemail.com>
Diffstat (limited to 'gcc')
-rw-r--r--gcc/rust/checks/errors/rust-readonly-check.cc54
-rw-r--r--gcc/testsuite/rust/compile/mutability_checks1.rs15
-rw-r--r--gcc/testsuite/rust/execute/torture/builtin_macro_include_bytes.rs2
3 files changed, 61 insertions, 10 deletions
diff --git a/gcc/rust/checks/errors/rust-readonly-check.cc b/gcc/rust/checks/errors/rust-readonly-check.cc
index 324e54b..0893689 100644
--- a/gcc/rust/checks/errors/rust-readonly-check.cc
+++ b/gcc/rust/checks/errors/rust-readonly-check.cc
@@ -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)
@@ -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))
@@ -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);
diff --git a/gcc/testsuite/rust/compile/mutability_checks1.rs b/gcc/testsuite/rust/compile/mutability_checks1.rs
new file mode 100644
index 0000000..4affae0
--- /dev/null
+++ b/gcc/testsuite/rust/compile/mutability_checks1.rs
@@ -0,0 +1,15 @@
+pub fn test() {
+ let a;
+ a = 1;
+ a = 2 + 1;
+ // { dg-error "assignment of read-only variable" "" { target *-*-* } .-1 }
+
+ struct Foo(i32);
+ let a = Foo(1);
+ a.0 = 2;
+ // { dg-error "assignment of read-only variable" "" { target *-*-* } .-1 }
+
+ let a = [1, 2, 3, 4];
+ a[0] = 1 + 2;
+ // { dg-error "assignment of read-only variable" "" { target *-*-* } .-1 }
+}
diff --git a/gcc/testsuite/rust/execute/torture/builtin_macro_include_bytes.rs b/gcc/testsuite/rust/execute/torture/builtin_macro_include_bytes.rs
index 6aec417..c8a2dae 100644
--- a/gcc/testsuite/rust/execute/torture/builtin_macro_include_bytes.rs
+++ b/gcc/testsuite/rust/execute/torture/builtin_macro_include_bytes.rs
@@ -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