Skip to content

Commit f9455fb

Browse files
committed
gccrs: port over readonly_error from c-family for lvalue assignment checks
Fixes #2391 gcc/rust/ChangeLog: * Make-lang.in: fixup formatting * resolve/rust-ast-resolve-expr.cc (ResolveExpr::visit): remove old check * rust-session-manager.cc (Session::compile_crate): call new lint * resolve/rust-ast-verify-assignee.h: Removed. * checks/errors/rust-readonly-check.cc: New file. * checks/errors/rust-readonly-check.h: New file. gcc/testsuite/ChangeLog: * rust/compile/wrong_lhs_assignment.rs: update error message * rust/compile/issue-2391.rs: New test. Signed-off-by: Philip Herron <[email protected]>
1 parent a2d5250 commit f9455fb

File tree

8 files changed

+227
-107
lines changed

8 files changed

+227
-107
lines changed

gcc/rust/Make-lang.in

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -86,12 +86,12 @@ GRS_OBJS = \
8686
rust/rust-compile-resolve-path.o \
8787
rust/rust-macro-expand.o \
8888
rust/rust-cfg-strip.o \
89-
rust/rust-expand-visitor.o \
90-
rust/rust-ast-builder.o \
91-
rust/rust-derive.o \
92-
rust/rust-derive-clone.o \
93-
rust/rust-derive-copy.o \
94-
rust/rust-proc-macro.o \
89+
rust/rust-expand-visitor.o \
90+
rust/rust-ast-builder.o \
91+
rust/rust-derive.o \
92+
rust/rust-derive-clone.o \
93+
rust/rust-derive-copy.o \
94+
rust/rust-proc-macro.o \
9595
rust/rust-macro-invoc-lexer.o \
9696
rust/rust-proc-macro-invoc-lexer.o \
9797
rust/rust-macro-substitute-ctx.o \
@@ -101,19 +101,19 @@ GRS_OBJS = \
101101
rust/rust-attributes.o \
102102
rust/rust-abi.o \
103103
rust/rust-token-converter.o \
104-
rust/rust-macro.o \
104+
rust/rust-macro.o \
105105
rust/rust-ast-lower.o \
106106
rust/rust-ast-lower-base.o \
107107
rust/rust-ast-lower-pattern.o \
108108
rust/rust-ast-lower-item.o \
109109
rust/rust-ast-lower-expr.o \
110110
rust/rust-ast-lower-type.o \
111-
rust/rust-ast-lower-stmt.o \
112-
rust/rust-rib.o \
113-
rust/rust-name-resolution-context.o \
114-
rust/rust-default-resolver.o \
111+
rust/rust-ast-lower-stmt.o \
112+
rust/rust-rib.o \
113+
rust/rust-name-resolution-context.o \
114+
rust/rust-default-resolver.o \
115115
rust/rust-toplevel-name-resolver-2.0.o \
116-
rust/rust-early-name-resolver-2.0.o \
116+
rust/rust-early-name-resolver-2.0.o \
117117
rust/rust-early-name-resolver.o \
118118
rust/rust-name-resolver.o \
119119
rust/rust-ast-resolve.o \
@@ -160,6 +160,7 @@ GRS_OBJS = \
160160
rust/rust-const-checker.o \
161161
rust/rust-lint-marklive.o \
162162
rust/rust-lint-unused-var.o \
163+
rust/rust-readonly-check.o \
163164
rust/rust-hir-type-check-path.o \
164165
rust/rust-unsafe-checker.o \
165166
rust/rust-compile-intrinsic.o \
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
// Copyright (C) 2021-2023 Free Software Foundation, Inc.
2+
3+
// This file is part of GCC.
4+
5+
// GCC is free software; you can redistribute it and/or modify it under
6+
// the terms of the GNU General Public License as published by the Free
7+
// Software Foundation; either version 3, or (at your option) any later
8+
// version.
9+
10+
// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
11+
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
12+
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13+
// for more details.
14+
15+
// You should have received a copy of the GNU General Public License
16+
// along with GCC; see the file COPYING3. If not see
17+
// <http://www.gnu.org/licenses/>.
18+
19+
#include "rust-readonly-check.h"
20+
#include "rust-tree.h"
21+
#include "rust-gcc.h"
22+
23+
namespace Rust {
24+
namespace Analysis {
25+
26+
// ported over from c-family/c-warn.cc
27+
void
28+
readonly_error (location_t loc, tree arg, enum lvalue_use use)
29+
{
30+
gcc_assert (use == lv_assign || use == lv_increment || use == lv_decrement
31+
|| use == lv_asm);
32+
STRIP_ANY_LOCATION_WRAPPER (arg);
33+
/* Using this macro rather than (for example) arrays of messages
34+
ensures that all the format strings are checked at compile
35+
time. */
36+
#define READONLY_MSG(A, I, D, AS) \
37+
(use == lv_assign \
38+
? (A) \
39+
: (use == lv_increment ? (I) : (use == lv_decrement ? (D) : (AS))))
40+
if (TREE_CODE (arg) == COMPONENT_REF)
41+
{
42+
if (TYPE_READONLY (TREE_TYPE (TREE_OPERAND (arg, 0))))
43+
error_at (loc,
44+
READONLY_MSG (G_ ("assignment of member "
45+
"%qD in read-only object"),
46+
G_ ("increment of member "
47+
"%qD in read-only object"),
48+
G_ ("decrement of member "
49+
"%qD in read-only object"),
50+
G_ ("member %qD in read-only object "
51+
"used as %<asm%> output")),
52+
TREE_OPERAND (arg, 1));
53+
else
54+
error_at (
55+
loc,
56+
READONLY_MSG (G_ ("assignment of read-only member %qD"),
57+
G_ ("increment of read-only member %qD"),
58+
G_ ("decrement of read-only member %qD"),
59+
G_ ("read-only member %qD used as %<asm%> output")),
60+
TREE_OPERAND (arg, 1));
61+
}
62+
else if (VAR_P (arg))
63+
error_at (loc,
64+
READONLY_MSG (G_ ("assignment of read-only variable %qD"),
65+
G_ ("increment of read-only variable %qD"),
66+
G_ ("decrement of read-only variable %qD"),
67+
G_ (
68+
"read-only variable %qD used as %<asm%> output")),
69+
arg);
70+
else if (TREE_CODE (arg) == PARM_DECL)
71+
error_at (loc,
72+
READONLY_MSG (G_ ("assignment of read-only parameter %qD"),
73+
G_ ("increment of read-only parameter %qD"),
74+
G_ ("decrement of read-only parameter %qD"),
75+
G_ (
76+
"read-only parameter %qD use as %<asm%> output")),
77+
arg);
78+
else if (TREE_CODE (arg) == RESULT_DECL)
79+
{
80+
error_at (loc,
81+
READONLY_MSG (G_ ("assignment of "
82+
"read-only named return value %qD"),
83+
G_ ("increment of "
84+
"read-only named return value %qD"),
85+
G_ ("decrement of "
86+
"read-only named return value %qD"),
87+
G_ ("read-only named return value %qD "
88+
"used as %<asm%>output")),
89+
arg);
90+
}
91+
else if (TREE_CODE (arg) == FUNCTION_DECL)
92+
error_at (loc,
93+
READONLY_MSG (G_ ("assignment of function %qD"),
94+
G_ ("increment of function %qD"),
95+
G_ ("decrement of function %qD"),
96+
G_ ("function %qD used as %<asm%> output")),
97+
arg);
98+
else
99+
error_at (loc,
100+
READONLY_MSG (G_ ("assignment of read-only location %qE"),
101+
G_ ("increment of read-only location %qE"),
102+
G_ ("decrement of read-only location %qE"),
103+
G_ (
104+
"read-only location %qE used as %<asm%> output")),
105+
arg);
106+
}
107+
108+
static void
109+
check_decl (tree *t)
110+
{
111+
if (TREE_CODE (*t) == MODIFY_EXPR)
112+
{
113+
tree lhs = TREE_OPERAND (*t, 0);
114+
if (TREE_READONLY (lhs) || TREE_CONSTANT (lhs))
115+
{
116+
readonly_error (EXPR_LOCATION (*t), lhs, lv_assign);
117+
TREE_OPERAND (*t, 0) = error_mark_node;
118+
}
119+
}
120+
}
121+
122+
static tree
123+
readonly_walk_fn (tree *t, int *, void *)
124+
{
125+
switch (TREE_CODE (*t))
126+
{
127+
case MODIFY_EXPR:
128+
check_decl (t);
129+
break;
130+
131+
default:
132+
break;
133+
}
134+
return NULL_TREE;
135+
}
136+
137+
void
138+
ReadonlyCheck::Lint (Compile::Context &ctx)
139+
{
140+
for (auto &fndecl : ctx.get_func_decls ())
141+
{
142+
for (tree p = DECL_ARGUMENTS (fndecl); p != NULL_TREE; p = DECL_CHAIN (p))
143+
{
144+
check_decl (&p);
145+
}
146+
147+
walk_tree_without_duplicates (&DECL_SAVED_TREE (fndecl),
148+
&readonly_walk_fn, &ctx);
149+
}
150+
151+
for (auto &var : ctx.get_var_decls ())
152+
{
153+
tree decl = var->get_decl ();
154+
check_decl (&decl);
155+
}
156+
157+
for (auto &const_decl : ctx.get_const_decls ())
158+
{
159+
check_decl (&const_decl);
160+
}
161+
}
162+
163+
} // namespace Analysis
164+
} // namespace Rust
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// Copyright (C) 2021-2023 Free Software Foundation, Inc.
2+
3+
// This file is part of GCC.
4+
5+
// GCC is free software; you can redistribute it and/or modify it under
6+
// the terms of the GNU General Public License as published by the Free
7+
// Software Foundation; either version 3, or (at your option) any later
8+
// version.
9+
10+
// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
11+
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
12+
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13+
// for more details.
14+
15+
// You should have received a copy of the GNU General Public License
16+
// along with GCC; see the file COPYING3. If not see
17+
// <http://www.gnu.org/licenses/>.
18+
19+
#ifndef RUST_READONLY_CHECK
20+
#define RUST_READONLY_CHECK
21+
22+
#include "rust-compile-context.h"
23+
24+
namespace Rust {
25+
namespace Analysis {
26+
27+
class ReadonlyCheck
28+
{
29+
public:
30+
static void Lint (Compile::Context &ctx);
31+
};
32+
33+
} // namespace Analysis
34+
} // namespace Rust
35+
36+
#endif // RUST_READONLY_CHECK

gcc/rust/resolve/rust-ast-resolve-expr.cc

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
#include "rust-ast-resolve-expr.h"
2020
#include "rust-ast-resolve-stmt.h"
2121
#include "rust-ast-resolve-struct-expr-field.h"
22-
#include "rust-ast-verify-assignee.h"
2322
#include "rust-ast-resolve-type.h"
2423
#include "rust-ast-resolve-pattern.h"
2524
#include "rust-ast-resolve-path.h"
@@ -101,9 +100,6 @@ ResolveExpr::visit (AST::AssignmentExpr &expr)
101100
{
102101
ResolveExpr::go (expr.get_left_expr ().get (), prefix, canonical_prefix);
103102
ResolveExpr::go (expr.get_right_expr ().get (), prefix, canonical_prefix);
104-
105-
// need to verify the assignee
106-
VerifyAsignee::go (expr.get_left_expr ().get ());
107103
}
108104

109105
/* The "break rust" Easter egg.
@@ -191,9 +187,6 @@ ResolveExpr::visit (AST::CompoundAssignmentExpr &expr)
191187
{
192188
ResolveExpr::go (expr.get_left_expr ().get (), prefix, canonical_prefix);
193189
ResolveExpr::go (expr.get_right_expr ().get (), prefix, canonical_prefix);
194-
195-
// need to verify the assignee
196-
VerifyAsignee::go (expr.get_left_expr ().get ());
197190
}
198191

199192
void

gcc/rust/resolve/rust-ast-verify-assignee.h

Lines changed: 0 additions & 84 deletions
This file was deleted.

gcc/rust/rust-session-manager.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,9 @@
3232
#include "rust-cfg-parser.h"
3333
#include "rust-lint-scan-deadcode.h"
3434
#include "rust-lint-unused-var.h"
35+
#include "rust-readonly-check.h"
3536
#include "rust-hir-dump.h"
3637
#include "rust-ast-dump.h"
37-
#include "rust-ast-collector.h"
3838
#include "rust-export-metadata.h"
3939
#include "rust-imports.h"
4040
#include "rust-extern-crate.h"
@@ -47,7 +47,6 @@
4747
#include "rust-unicode.h"
4848
#include "rust-attribute-values.h"
4949

50-
#include "diagnostic.h"
5150
#include "input.h"
5251
#include "selftest.h"
5352
#include "tm.h"
@@ -676,6 +675,7 @@ Session::compile_crate (const char *filename)
676675
// lints
677676
Analysis::ScanDeadcode::Scan (hir);
678677
Analysis::UnusedVariables::Lint (ctx);
678+
Analysis::ReadonlyCheck::Lint (ctx);
679679

680680
// metadata
681681
bool specified_emit_metadata

0 commit comments

Comments
 (0)