diff options
author | Philip Herron <herron.philip@googlemail.com> | 2024-12-16 14:51:17 +0000 |
---|---|---|
committer | Philip Herron <philip.herron@embecosm.com> | 2025-01-10 10:43:13 +0000 |
commit | c957f18575fbe8208e01674cd446652323a7eb1b (patch) | |
tree | 09ea31fe6aae2b177cd467f8090ad8c1ea0f19c9 /gcc | |
parent | f68fbff016d4faacd54de63549d43255e1193688 (diff) | |
download | gcc-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.cc | 54 | ||||
-rw-r--r-- | gcc/testsuite/rust/compile/mutability_checks1.rs | 15 | ||||
-rw-r--r-- | gcc/testsuite/rust/execute/torture/builtin_macro_include_bytes.rs | 2 |
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 |