Branch data Line data Source code
1 : : /* rust-attribs.c -- Rust attributes handling.
2 : : Copyright (C) 2015-2024 Free Software Foundation, Inc.
3 : :
4 : : GCC is free software; you can redistribute it and/or modify
5 : : it under the terms of the GNU General Public License as published by
6 : : the Free Software Foundation; either version 3, or (at your option)
7 : : any later version.
8 : :
9 : : GCC is distributed in the hope that it will be useful,
10 : : but WITHOUT ANY WARRANTY; without even the implied warranty of
11 : : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 : : GNU General Public License for more details.
13 : :
14 : : You should have received a copy of the GNU General Public License
15 : : along with GCC; see the file COPYING3. If not see
16 : : <http://www.gnu.org/licenses/>. */
17 : :
18 : : #include "config.h"
19 : : #include "system.h"
20 : : #include "coretypes.h"
21 : :
22 : : #include "tree.h"
23 : : #include "diagnostic.h"
24 : : #include "tm.h"
25 : : #include "cgraph.h"
26 : : #include "toplev.h"
27 : : #include "target.h"
28 : : #include "common/common-target.h"
29 : : #include "stringpool.h"
30 : : #include "attribs.h"
31 : : #include "varasm.h"
32 : : #include "fold-const.h"
33 : : #include "opts.h"
34 : :
35 : : /* Heavily based on the D frontend Only a subset of the attributes found in the
36 : : * D frontend have been pulled, the goal being to have the builtin function
37 : : * correctly setup. It's possible we may need to add extra attributes in the
38 : : * future.
39 : : */
40 : :
41 : : extern const attribute_spec grs_langhook_common_attribute_table[];
42 : :
43 : : /* Internal attribute handlers for built-in functions. */
44 : : static tree
45 : : handle_noreturn_attribute (tree *, tree, tree, int, bool *);
46 : : static tree
47 : : handle_leaf_attribute (tree *, tree, tree, int, bool *);
48 : : static tree
49 : : handle_const_attribute (tree *, tree, tree, int, bool *);
50 : : static tree
51 : : handle_malloc_attribute (tree *, tree, tree, int, bool *);
52 : : static tree
53 : : handle_pure_attribute (tree *, tree, tree, int, bool *);
54 : : static tree
55 : : handle_novops_attribute (tree *, tree, tree, int, bool *);
56 : : static tree
57 : : handle_nonnull_attribute (tree *, tree, tree, int, bool *);
58 : : static tree
59 : : handle_nothrow_attribute (tree *, tree, tree, int, bool *);
60 : : static tree
61 : : handle_type_generic_attribute (tree *, tree, tree, int, bool *);
62 : : static tree
63 : : handle_transaction_pure_attribute (tree *, tree, tree, int, bool *);
64 : : static tree
65 : : handle_returns_twice_attribute (tree *, tree, tree, int, bool *);
66 : : static tree
67 : : handle_fnspec_attribute (tree *, tree, tree, int, bool *);
68 : : static tree
69 : : handle_omp_declare_simd_attribute (tree *, tree, tree, int, bool *);
70 : :
71 : : /* Helper to define attribute exclusions. */
72 : : #define ATTR_EXCL(name, function, type, variable) \
73 : : { \
74 : : name, function, type, variable \
75 : : }
76 : :
77 : : static const struct attribute_spec::exclusions attr_noreturn_exclusions[] = {
78 : : // ATTR_EXCL ("alloc_size", true, true, true),
79 : : ATTR_EXCL ("const", true, true, true),
80 : : // ATTR_EXCL ("malloc", true, true, true),
81 : : ATTR_EXCL ("pure", true, true, true),
82 : : ATTR_EXCL ("returns_twice", true, true, true),
83 : : ATTR_EXCL (NULL, false, false, false),
84 : : };
85 : :
86 : : static const struct attribute_spec::exclusions attr_returns_twice_exclusions[]
87 : : = {
88 : : ATTR_EXCL ("noreturn", true, true, true),
89 : : ATTR_EXCL (NULL, false, false, false),
90 : : };
91 : :
92 : : static const struct attribute_spec::exclusions attr_const_pure_exclusions[] = {
93 : : // ATTR_EXCL ("alloc_size", true, true, true),
94 : : ATTR_EXCL ("const", true, true, true),
95 : : ATTR_EXCL ("noreturn", true, true, true),
96 : : ATTR_EXCL ("pure", true, true, true), ATTR_EXCL (NULL, false, false, false)};
97 : :
98 : : /* Helper to define an attribute. */
99 : : #define ATTR_SPEC(name, min_len, max_len, decl_req, type_req, fn_type_req, \
100 : : affects_type_identity, handler, exclude) \
101 : : { \
102 : : name, min_len, max_len, decl_req, type_req, fn_type_req, \
103 : : affects_type_identity, handler, exclude \
104 : : }
105 : :
106 : : /* Table of machine-independent attributes.
107 : : For internal use (marking of built-ins) only. */
108 : : const attribute_spec grs_langhook_common_attribute_table[] = {
109 : : ATTR_SPEC ("noreturn", 0, 0, true, false, false, false,
110 : : handle_noreturn_attribute, attr_noreturn_exclusions),
111 : : ATTR_SPEC ("leaf", 0, 0, true, false, false, false, handle_leaf_attribute,
112 : : NULL),
113 : : ATTR_SPEC ("const", 0, 0, true, false, false, false, handle_const_attribute,
114 : : attr_const_pure_exclusions),
115 : : ATTR_SPEC ("malloc", 0, 0, true, false, false, false, handle_malloc_attribute,
116 : : NULL),
117 : : ATTR_SPEC ("returns_twice", 0, 0, true, false, false, false,
118 : : handle_returns_twice_attribute, attr_returns_twice_exclusions),
119 : : ATTR_SPEC ("pure", 0, 0, true, false, false, false, handle_pure_attribute,
120 : : attr_const_pure_exclusions),
121 : : ATTR_SPEC ("nonnull", 0, -1, false, true, true, false,
122 : : handle_nonnull_attribute, NULL),
123 : : ATTR_SPEC ("nothrow", 0, 0, true, false, false, false,
124 : : handle_nothrow_attribute, NULL),
125 : : ATTR_SPEC ("transaction_pure", 0, 0, false, true, true, false,
126 : : handle_transaction_pure_attribute, NULL),
127 : : ATTR_SPEC ("no vops", 0, 0, true, false, false, false,
128 : : handle_novops_attribute, NULL),
129 : : ATTR_SPEC ("type generic", 0, 0, false, true, true, false,
130 : : handle_type_generic_attribute, NULL),
131 : : ATTR_SPEC ("fn spec", 1, 1, false, true, true, false, handle_fnspec_attribute,
132 : : NULL),
133 : : ATTR_SPEC ("omp declare simd", 0, -1, true, false, false, false,
134 : : handle_omp_declare_simd_attribute, NULL),
135 : : ATTR_SPEC (NULL, 0, 0, false, false, false, false, NULL, NULL),
136 : : };
137 : :
138 : : /* Built-in attribute handlers.
139 : : These functions take the arguments:
140 : : (tree *node, tree name, tree args, int flags, bool *no_add_attrs) */
141 : :
142 : : /* Handle a "noreturn" attribute; arguments as in
143 : : struct attribute_spec.handler. */
144 : :
145 : : static tree
146 : 0 : handle_noreturn_attribute (tree *node, tree, tree, int, bool *)
147 : : {
148 : 0 : tree type = TREE_TYPE (*node);
149 : :
150 : 0 : if (TREE_CODE (*node) == FUNCTION_DECL)
151 : 0 : TREE_THIS_VOLATILE (*node) = 1;
152 : 0 : else if (TREE_CODE (type) == POINTER_TYPE
153 : 0 : && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE)
154 : 0 : TREE_TYPE (*node) = build_pointer_type (
155 : 0 : build_type_variant (TREE_TYPE (type), TYPE_READONLY (TREE_TYPE (type)),
156 : : 1));
157 : : else
158 : 0 : gcc_unreachable ();
159 : :
160 : 0 : return NULL_TREE;
161 : : }
162 : :
163 : : /* Handle a "leaf" attribute; arguments as in
164 : : struct attribute_spec.handler. */
165 : :
166 : : static tree
167 : 0 : handle_leaf_attribute (tree *node, tree name, tree, int, bool *no_add_attrs)
168 : : {
169 : 0 : if (TREE_CODE (*node) != FUNCTION_DECL)
170 : : {
171 : 0 : warning (OPT_Wattributes, "%qE attribute ignored", name);
172 : 0 : *no_add_attrs = true;
173 : : }
174 : 0 : if (!TREE_PUBLIC (*node))
175 : : {
176 : 0 : warning (OPT_Wattributes, "%qE attribute has no effect", name);
177 : 0 : *no_add_attrs = true;
178 : : }
179 : :
180 : 0 : return NULL_TREE;
181 : : }
182 : :
183 : : /* Handle a "const" attribute; arguments as in
184 : : struct attribute_spec.handler. */
185 : :
186 : : static tree
187 : 0 : handle_const_attribute (tree *node, tree, tree, int, bool *)
188 : : {
189 : 0 : tree type = TREE_TYPE (*node);
190 : :
191 : 0 : if (TREE_CODE (*node) == FUNCTION_DECL)
192 : 0 : TREE_READONLY (*node) = 1;
193 : 0 : else if (TREE_CODE (type) == POINTER_TYPE
194 : 0 : && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE)
195 : 0 : TREE_TYPE (*node) = build_pointer_type (
196 : 0 : build_type_variant (TREE_TYPE (type), 1,
197 : : TREE_THIS_VOLATILE (TREE_TYPE (type))));
198 : : else
199 : 0 : gcc_unreachable ();
200 : :
201 : 0 : return NULL_TREE;
202 : : }
203 : :
204 : : /* Handle a "malloc" attribute; arguments as in
205 : : struct attribute_spec.handler. */
206 : :
207 : : tree
208 : 0 : handle_malloc_attribute (tree *node, tree, tree, int, bool *)
209 : : {
210 : 0 : gcc_assert (TREE_CODE (*node) == FUNCTION_DECL
211 : : && POINTER_TYPE_P (TREE_TYPE (TREE_TYPE (*node))));
212 : 0 : DECL_IS_MALLOC (*node) = 1;
213 : 0 : return NULL_TREE;
214 : : }
215 : :
216 : : /* Handle a "pure" attribute; arguments as in
217 : : struct attribute_spec.handler. */
218 : :
219 : : static tree
220 : 0 : handle_pure_attribute (tree *node, tree, tree, int, bool *)
221 : : {
222 : 0 : gcc_assert (TREE_CODE (*node) == FUNCTION_DECL);
223 : 0 : DECL_PURE_P (*node) = 1;
224 : 0 : return NULL_TREE;
225 : : }
226 : :
227 : : /* Handle a "no vops" attribute; arguments as in
228 : : struct attribute_spec.handler. */
229 : :
230 : : static tree
231 : 0 : handle_novops_attribute (tree *node, tree, tree, int, bool *)
232 : : {
233 : 0 : gcc_assert (TREE_CODE (*node) == FUNCTION_DECL);
234 : 0 : DECL_IS_NOVOPS (*node) = 1;
235 : 0 : return NULL_TREE;
236 : : }
237 : :
238 : : /* Helper for nonnull attribute handling; fetch the operand number
239 : : from the attribute argument list. */
240 : :
241 : : static bool
242 : 0 : get_nonnull_operand (tree arg_num_expr, unsigned HOST_WIDE_INT *valp)
243 : : {
244 : : /* Verify the arg number is a constant. */
245 : 0 : if (!tree_fits_uhwi_p (arg_num_expr))
246 : : return false;
247 : :
248 : 0 : *valp = TREE_INT_CST_LOW (arg_num_expr);
249 : 0 : return true;
250 : : }
251 : :
252 : : /* Handle the "nonnull" attribute. */
253 : :
254 : : static tree
255 : 0 : handle_nonnull_attribute (tree *node, tree, tree args, int, bool *)
256 : : {
257 : 0 : tree type = *node;
258 : :
259 : : /* If no arguments are specified, all pointer arguments should be
260 : : non-null. Verify a full prototype is given so that the arguments
261 : : will have the correct types when we actually check them later.
262 : : Avoid diagnosing type-generic built-ins since those have no
263 : : prototype. */
264 : 0 : if (!args)
265 : : {
266 : 0 : gcc_assert (prototype_p (type) || !TYPE_ATTRIBUTES (type)
267 : : || lookup_attribute ("type generic", TYPE_ATTRIBUTES (type)));
268 : :
269 : 0 : return NULL_TREE;
270 : : }
271 : :
272 : : /* Argument list specified. Verify that each argument number references
273 : : a pointer argument. */
274 : 0 : for (; args; args = TREE_CHAIN (args))
275 : : {
276 : 0 : tree argument;
277 : 0 : unsigned HOST_WIDE_INT arg_num = 0, ck_num;
278 : :
279 : 0 : if (!get_nonnull_operand (TREE_VALUE (args), &arg_num))
280 : 0 : gcc_unreachable ();
281 : :
282 : 0 : argument = TYPE_ARG_TYPES (type);
283 : 0 : if (argument)
284 : : {
285 : 0 : for (ck_num = 1;; ck_num++)
286 : : {
287 : 0 : if (!argument || ck_num == arg_num)
288 : : break;
289 : 0 : argument = TREE_CHAIN (argument);
290 : : }
291 : :
292 : 0 : gcc_assert (argument
293 : : && TREE_CODE (TREE_VALUE (argument)) == POINTER_TYPE);
294 : : }
295 : : }
296 : :
297 : : return NULL_TREE;
298 : : }
299 : :
300 : : /* Handle a "nothrow" attribute; arguments as in
301 : : struct attribute_spec.handler. */
302 : :
303 : : static tree
304 : 0 : handle_nothrow_attribute (tree *node, tree, tree, int, bool *)
305 : : {
306 : 0 : gcc_assert (TREE_CODE (*node) == FUNCTION_DECL);
307 : 0 : TREE_NOTHROW (*node) = 1;
308 : 0 : return NULL_TREE;
309 : : }
310 : :
311 : : /* Handle a "type generic" attribute; arguments as in
312 : : struct attribute_spec.handler. */
313 : :
314 : : static tree
315 : 0 : handle_type_generic_attribute (tree *node, tree, tree, int, bool *)
316 : : {
317 : : /* Ensure we have a function type. */
318 : 0 : gcc_assert (TREE_CODE (*node) == FUNCTION_TYPE);
319 : :
320 : : /* Ensure we have a variadic function. */
321 : 0 : gcc_assert (!prototype_p (*node) || stdarg_p (*node));
322 : :
323 : 0 : return NULL_TREE;
324 : : }
325 : :
326 : : /* Handle a "transaction_pure" attribute; arguments as in
327 : : struct attribute_spec.handler. */
328 : :
329 : : static tree
330 : 0 : handle_transaction_pure_attribute (tree *node, tree, tree, int, bool *)
331 : : {
332 : : /* Ensure we have a function type. */
333 : 0 : gcc_assert (TREE_CODE (*node) == FUNCTION_TYPE);
334 : :
335 : 0 : return NULL_TREE;
336 : : }
337 : :
338 : : /* Handle a "returns_twice" attribute; arguments as in
339 : : struct attribute_spec.handler. */
340 : :
341 : : static tree
342 : 0 : handle_returns_twice_attribute (tree *node, tree, tree, int, bool *)
343 : : {
344 : 0 : gcc_assert (TREE_CODE (*node) == FUNCTION_DECL);
345 : :
346 : 0 : DECL_IS_RETURNS_TWICE (*node) = 1;
347 : :
348 : 0 : return NULL_TREE;
349 : : }
350 : :
351 : : /* Handle a "fn spec" attribute; arguments as in
352 : : struct attribute_spec.handler. */
353 : :
354 : : tree
355 : 0 : handle_fnspec_attribute (tree *, tree, tree args, int, bool *)
356 : : {
357 : 0 : gcc_assert (args && TREE_CODE (TREE_VALUE (args)) == STRING_CST
358 : : && !TREE_CHAIN (args));
359 : 0 : return NULL_TREE;
360 : : }
361 : :
362 : : /* Handle an "omp declare simd" attribute; arguments as in
363 : : struct attribute_spec.handler. */
364 : :
365 : : tree
366 : 0 : handle_omp_declare_simd_attribute (tree *node, tree, tree, int, bool *)
367 : : {
368 : 0 : gcc_assert (TREE_CODE (*node) == FUNCTION_DECL);
369 : 0 : return NULL_TREE;
370 : : }
|