Branch data Line data Source code
1 : : // Copyright (C) 2021-2024 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 : 2 : readonly_error (location_t loc, tree arg, enum lvalue_use use)
29 : : {
30 : 2 : gcc_assert (use == lv_assign || use == lv_increment || use == lv_decrement
31 : : || use == lv_asm);
32 : 2 : 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 : 2 : if (TREE_CODE (arg) == COMPONENT_REF)
41 : : {
42 : 0 : if (TYPE_READONLY (TREE_TYPE (TREE_OPERAND (arg, 0))))
43 : 0 : 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 : 0 : TREE_OPERAND (arg, 1));
53 : : else
54 : 0 : 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 : 0 : TREE_OPERAND (arg, 1));
61 : : }
62 : : else if (VAR_P (arg))
63 : 0 : 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 : 0 : 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 : 0 : 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 : 0 : 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 : 4 : 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 : 2 : }
107 : :
108 : : static void
109 : 22518 : check_decl (tree *t)
110 : : {
111 : 22518 : if (TREE_CODE (*t) == MODIFY_EXPR)
112 : : {
113 : 15424 : tree lhs = TREE_OPERAND (*t, 0);
114 : 15424 : if (TREE_READONLY (lhs) || TREE_CONSTANT (lhs))
115 : : {
116 : 2 : readonly_error (EXPR_LOCATION (*t), lhs, lv_assign);
117 : 2 : TREE_OPERAND (*t, 0) = error_mark_node;
118 : : }
119 : : }
120 : 22518 : }
121 : :
122 : : static tree
123 : 217904 : readonly_walk_fn (tree *t, int *, void *)
124 : : {
125 : 217904 : switch (TREE_CODE (*t))
126 : : {
127 : 15424 : case MODIFY_EXPR:
128 : 15424 : check_decl (t);
129 : 15424 : break;
130 : :
131 : : default:
132 : : break;
133 : : }
134 : 217904 : return NULL_TREE;
135 : : }
136 : :
137 : : void
138 : 3290 : ReadonlyCheck::Lint (Compile::Context &ctx)
139 : : {
140 : 12793 : for (auto &fndecl : ctx.get_func_decls ())
141 : : {
142 : 16111 : for (tree p = DECL_ARGUMENTS (fndecl); p != NULL_TREE; p = DECL_CHAIN (p))
143 : : {
144 : 6608 : check_decl (&p);
145 : : }
146 : :
147 : 9503 : walk_tree_without_duplicates (&DECL_SAVED_TREE (fndecl),
148 : : &readonly_walk_fn, &ctx);
149 : : }
150 : :
151 : 3328 : for (auto &var : ctx.get_var_decls ())
152 : : {
153 : 38 : tree decl = var->get_decl ();
154 : 38 : check_decl (&decl);
155 : : }
156 : :
157 : 3738 : for (auto &const_decl : ctx.get_const_decls ())
158 : : {
159 : 448 : check_decl (&const_decl);
160 : : }
161 : 3290 : }
162 : :
163 : : } // namespace Analysis
164 : : } // namespace Rust
|