]>
Commit | Line | Data |
---|---|---|
03385ed3 | 1 | /* d-attribs.c -- D attributes handling. |
fbd26352 | 2 | Copyright (C) 2015-2019 Free Software Foundation, Inc. |
03385ed3 | 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 | /* Implementation of attribute handlers for user defined attributes and | |
19 | internal built-in functions. */ | |
20 | ||
21 | #include "config.h" | |
22 | #include "system.h" | |
23 | #include "coretypes.h" | |
24 | ||
25 | #include "dmd/declaration.h" | |
26 | #include "dmd/mtype.h" | |
27 | ||
28 | #include "tree.h" | |
29 | #include "diagnostic.h" | |
30 | #include "tm.h" | |
31 | #include "cgraph.h" | |
32 | #include "toplev.h" | |
33 | #include "target.h" | |
34 | #include "common/common-target.h" | |
35 | #include "stringpool.h" | |
36 | #include "attribs.h" | |
37 | #include "varasm.h" | |
38 | ||
39 | #include "d-tree.h" | |
40 | ||
41 | ||
42 | /* Internal attribute handlers for built-in functions. */ | |
43 | static tree handle_noreturn_attribute (tree *, tree, tree, int, bool *); | |
44 | static tree handle_leaf_attribute (tree *, tree, tree, int, bool *); | |
45 | static tree handle_const_attribute (tree *, tree, tree, int, bool *); | |
46 | static tree handle_malloc_attribute (tree *, tree, tree, int, bool *); | |
47 | static tree handle_pure_attribute (tree *, tree, tree, int, bool *); | |
48 | static tree handle_novops_attribute (tree *, tree, tree, int, bool *); | |
49 | static tree handle_nonnull_attribute (tree *, tree, tree, int, bool *); | |
50 | static tree handle_nothrow_attribute (tree *, tree, tree, int, bool *); | |
51 | static tree handle_type_generic_attribute (tree *, tree, tree, int, bool *); | |
52 | static tree handle_transaction_pure_attribute (tree *, tree, tree, int, bool *); | |
53 | static tree handle_returns_twice_attribute (tree *, tree, tree, int, bool *); | |
54 | static tree handle_fnspec_attribute (tree *, tree, tree, int, bool *); | |
55 | ||
56 | /* D attribute handlers for user defined attributes. */ | |
57 | static tree d_handle_noinline_attribute (tree *, tree, tree, int, bool *); | |
58 | static tree d_handle_forceinline_attribute (tree *, tree, tree, int, bool *); | |
59 | static tree d_handle_flatten_attribute (tree *, tree, tree, int, bool *); | |
60 | static tree d_handle_target_attribute (tree *, tree, tree, int, bool *); | |
61 | static tree d_handle_noclone_attribute (tree *, tree, tree, int, bool *); | |
62 | static tree d_handle_section_attribute (tree *, tree, tree, int, bool *); | |
63 | static tree d_handle_alias_attribute (tree *, tree, tree, int, bool *); | |
64 | static tree d_handle_weak_attribute (tree *, tree, tree, int, bool *) ; | |
65 | ||
66 | /* Helper to define attribute exclusions. */ | |
67 | #define ATTR_EXCL(name, function, type, variable) \ | |
68 | { name, function, type, variable } | |
69 | ||
70 | /* Define attributes that are mutually exclusive with one another. */ | |
71 | static const struct attribute_spec::exclusions attr_noreturn_exclusions[] = | |
72 | { | |
73 | ATTR_EXCL ("const", true, true, true), | |
74 | ATTR_EXCL ("malloc", true, true, true), | |
75 | ATTR_EXCL ("pure", true, true, true), | |
76 | ATTR_EXCL ("returns_twice", true, true, true), | |
77 | ATTR_EXCL (NULL, false, false, false), | |
78 | }; | |
79 | ||
80 | static const struct attribute_spec::exclusions attr_returns_twice_exclusions[] = | |
81 | { | |
82 | ATTR_EXCL ("noreturn", true, true, true), | |
83 | ATTR_EXCL (NULL, false, false, false), | |
84 | }; | |
85 | ||
86 | static const struct attribute_spec::exclusions attr_const_pure_exclusions[] = | |
87 | { | |
88 | ATTR_EXCL ("const", true, true, true), | |
89 | ATTR_EXCL ("noreturn", true, true, true), | |
90 | ATTR_EXCL ("pure", true, true, true), | |
91 | ATTR_EXCL (NULL, false, false, false) | |
92 | }; | |
93 | ||
94 | static const struct attribute_spec::exclusions attr_inline_exclusions[] = | |
95 | { | |
96 | ATTR_EXCL ("noinline", true, true, true), | |
97 | ATTR_EXCL (NULL, false, false, false), | |
98 | }; | |
99 | ||
100 | static const struct attribute_spec::exclusions attr_noinline_exclusions[] = | |
101 | { | |
102 | ATTR_EXCL ("forceinline", true, true, true), | |
103 | ATTR_EXCL (NULL, false, false, false), | |
104 | }; | |
105 | ||
106 | /* Helper to define an attribute. */ | |
107 | #define ATTR_SPEC(name, min_len, max_len, decl_req, type_req, fn_type_req, \ | |
108 | affects_type_identity, handler, exclude) \ | |
109 | { name, min_len, max_len, decl_req, type_req, fn_type_req, \ | |
110 | affects_type_identity, handler, exclude } | |
111 | ||
112 | /* Table of machine-independent attributes. | |
113 | For internal use (marking of built-ins) only. */ | |
114 | const attribute_spec d_langhook_common_attribute_table[] = | |
115 | { | |
116 | ATTR_SPEC ("noreturn", 0, 0, true, false, false, false, | |
117 | handle_noreturn_attribute, attr_noreturn_exclusions), | |
118 | ATTR_SPEC ("leaf", 0, 0, true, false, false, false, | |
119 | handle_leaf_attribute, NULL), | |
120 | ATTR_SPEC ("const", 0, 0, true, false, false, false, | |
121 | handle_const_attribute, attr_const_pure_exclusions), | |
122 | ATTR_SPEC ("malloc", 0, 0, true, false, false, false, | |
123 | handle_malloc_attribute, NULL), | |
124 | ATTR_SPEC ("returns_twice", 0, 0, true, false, false, false, | |
125 | handle_returns_twice_attribute, attr_returns_twice_exclusions), | |
126 | ATTR_SPEC ("pure", 0, 0, true, false, false, false, | |
127 | handle_pure_attribute, attr_const_pure_exclusions), | |
128 | ATTR_SPEC ("nonnull", 0, -1, false, true, true, false, | |
129 | handle_nonnull_attribute, NULL), | |
130 | ATTR_SPEC ("nothrow", 0, 0, true, false, false, false, | |
131 | handle_nothrow_attribute, NULL), | |
132 | ATTR_SPEC ("transaction_pure", 0, 0, false, true, true, false, | |
133 | handle_transaction_pure_attribute, NULL), | |
134 | ATTR_SPEC ("no vops", 0, 0, true, false, false, false, | |
135 | handle_novops_attribute, NULL), | |
136 | ATTR_SPEC ("type generic", 0, 0, false, true, true, false, | |
137 | handle_type_generic_attribute, NULL), | |
138 | ATTR_SPEC ("fn spec", 1, 1, false, true, true, false, | |
139 | handle_fnspec_attribute, NULL), | |
140 | ATTR_SPEC (NULL, 0, 0, false, false, false, false, NULL, NULL), | |
141 | }; | |
142 | ||
143 | /* Table of D language attributes exposed by `gcc.attribute' UDAs. */ | |
144 | const attribute_spec d_langhook_attribute_table[] = | |
145 | { | |
146 | ATTR_SPEC ("noinline", 0, 0, true, false, false, false, | |
147 | d_handle_noinline_attribute, attr_noinline_exclusions), | |
148 | ATTR_SPEC ("forceinline", 0, 0, true, false, false, false, | |
149 | d_handle_forceinline_attribute, attr_inline_exclusions), | |
150 | ATTR_SPEC ("flatten", 0, 0, true, false, false, false, | |
151 | d_handle_flatten_attribute, NULL), | |
152 | ATTR_SPEC ("target", 1, -1, true, false, false, false, | |
153 | d_handle_target_attribute, NULL), | |
154 | ATTR_SPEC ("noclone", 0, 0, true, false, false, false, | |
155 | d_handle_noclone_attribute, NULL), | |
156 | ATTR_SPEC ("section", 1, 1, true, false, false, false, | |
157 | d_handle_section_attribute, NULL), | |
158 | ATTR_SPEC ("alias", 1, 1, true, false, false, false, | |
159 | d_handle_alias_attribute, NULL), | |
160 | ATTR_SPEC ("weak", 0, 0, true, false, false, false, | |
161 | d_handle_weak_attribute, NULL), | |
162 | ATTR_SPEC (NULL, 0, 0, false, false, false, false, NULL, NULL), | |
163 | }; | |
164 | ||
165 | ||
166 | /* Insert the type attribute ATTRNAME with value VALUE into TYPE. | |
167 | Returns a new variant of the original type declaration. */ | |
168 | ||
169 | tree | |
170 | insert_type_attribute (tree type, const char *attrname, tree value) | |
171 | { | |
172 | tree ident = get_identifier (attrname); | |
173 | ||
174 | if (value) | |
175 | value = tree_cons (NULL_TREE, value, NULL_TREE); | |
176 | ||
177 | tree attribs = merge_attributes (TYPE_ATTRIBUTES (type), | |
178 | tree_cons (ident, value, NULL_TREE)); | |
179 | ||
180 | return build_type_attribute_variant (type, attribs); | |
181 | } | |
182 | ||
183 | /* Insert the decl attribute ATTRNAME with value VALUE into DECL. */ | |
184 | ||
185 | tree | |
186 | insert_decl_attribute (tree decl, const char *attrname, tree value) | |
187 | { | |
188 | tree ident = get_identifier (attrname); | |
189 | ||
190 | if (value) | |
191 | value = tree_cons (NULL_TREE, value, NULL_TREE); | |
192 | ||
193 | tree attribs = merge_attributes (DECL_ATTRIBUTES (decl), | |
194 | tree_cons (ident, value, NULL_TREE)); | |
195 | ||
196 | return build_decl_attribute_variant (decl, attribs); | |
197 | } | |
198 | ||
199 | /* Returns TRUE if NAME is an attribute recognized as being handled by | |
200 | the `gcc.attribute' module. */ | |
201 | ||
202 | static bool | |
203 | uda_attribute_p (const char *name) | |
204 | { | |
205 | tree ident = get_identifier (name); | |
206 | ||
207 | /* Search both our language, and target attribute tables. | |
208 | Common and format attributes are kept internal. */ | |
209 | for (const attribute_spec *p = d_langhook_attribute_table; p->name; p++) | |
210 | { | |
211 | if (get_identifier (p->name) == ident) | |
212 | return true; | |
213 | } | |
214 | ||
215 | for (const attribute_spec *p = targetm.attribute_table; p->name; p++) | |
216 | { | |
217 | if (get_identifier (p->name) == ident) | |
218 | return true; | |
219 | } | |
220 | ||
221 | return false; | |
222 | } | |
223 | ||
224 | /* [attribute/uda] | |
225 | ||
226 | User Defined Attributes (UDA) are compile time expressions that can be | |
227 | attached to a declaration. These attributes can then be queried, extracted, | |
228 | and manipulated at compile-time. There is no run-time component to them. | |
229 | ||
230 | Expand and merge all UDAs found in the EATTRS list that are of type | |
231 | `gcc.attribute.Attribute'. This symbol is internally recognized by the | |
232 | compiler and maps them to their equivalent GCC attribute. */ | |
233 | ||
234 | tree | |
235 | build_attributes (Expressions *eattrs) | |
236 | { | |
237 | if (!eattrs) | |
238 | return NULL_TREE; | |
239 | ||
240 | expandTuples (eattrs); | |
241 | ||
242 | tree attribs = NULL_TREE; | |
243 | ||
244 | for (size_t i = 0; i < eattrs->dim; i++) | |
245 | { | |
246 | Expression *attr = (*eattrs)[i]; | |
247 | Dsymbol *sym = attr->type->toDsymbol (0); | |
248 | ||
249 | if (!sym) | |
250 | continue; | |
251 | ||
252 | /* Attribute symbol must come from the `gcc.attribute' module. */ | |
253 | Dsymbol *mod = (Dsymbol*) sym->getModule (); | |
254 | if (!(strcmp (mod->toChars (), "attribute") == 0 | |
255 | && mod->parent != NULL | |
256 | && strcmp (mod->parent->toChars (), "gcc") == 0 | |
257 | && !mod->parent->parent)) | |
258 | continue; | |
259 | ||
260 | /* Get the result of the attribute if it hasn't already been folded. */ | |
261 | if (attr->op == TOKcall) | |
262 | attr = attr->ctfeInterpret (); | |
263 | ||
264 | /* Should now have a struct `Attribute("attrib", "value", ...)' | |
265 | initializer list. */ | |
266 | gcc_assert (attr->op == TOKstructliteral); | |
267 | Expressions *elems = ((StructLiteralExp*) attr)->elements; | |
268 | Expression *e0 = (*elems)[0]; | |
269 | ||
270 | if (e0->op != TOKstring) | |
271 | { | |
272 | error ("expected string attribute, not %qs", e0->toChars ()); | |
273 | return error_mark_node; | |
274 | } | |
275 | ||
276 | StringExp *se = (StringExp*) e0; | |
277 | gcc_assert (se->sz == 1); | |
278 | ||
279 | /* Empty string attribute, just ignore it. */ | |
280 | if (se->len == 0) | |
281 | continue; | |
282 | ||
283 | /* Check if the attribute is recognized and handled. | |
284 | Done here to report the diagnostic at the right location. */ | |
285 | const char *name = (const char *)(se->len ? se->string : ""); | |
286 | if (!uda_attribute_p (name)) | |
287 | { | |
288 | warning_at (make_location_t (e0->loc), OPT_Wattributes, | |
289 | "unknown attribute %qs", name); | |
290 | return error_mark_node; | |
291 | } | |
292 | ||
293 | /* Chain all attribute arguments together. */ | |
294 | tree args = NULL_TREE; | |
295 | ||
296 | for (size_t j = 1; j < elems->dim; j++) | |
297 | { | |
298 | Expression *e = (*elems)[j]; | |
299 | tree t; | |
300 | if (e->op == TOKstring && ((StringExp *) e)->sz == 1) | |
301 | { | |
302 | StringExp *s = (StringExp *) e; | |
303 | const char *string = (const char *)(s->len ? s->string : ""); | |
304 | t = build_string (s->len, string); | |
305 | } | |
306 | else | |
307 | t = build_expr (e); | |
308 | ||
309 | args = chainon (args, build_tree_list (0, t)); | |
310 | } | |
311 | ||
312 | tree list = build_tree_list (get_identifier (name), args); | |
313 | attribs = chainon (attribs, list); | |
314 | } | |
315 | ||
316 | return attribs; | |
317 | } | |
318 | ||
319 | /* Built-in attribute handlers. */ | |
320 | ||
321 | /* Handle a "noreturn" attribute; arguments as in | |
322 | struct attribute_spec.handler. */ | |
323 | ||
324 | static tree | |
325 | handle_noreturn_attribute (tree *node, tree ARG_UNUSED (name), | |
326 | tree ARG_UNUSED (args), int ARG_UNUSED (flags), | |
327 | bool * ARG_UNUSED (no_add_attrs)) | |
328 | { | |
329 | tree type = TREE_TYPE (*node); | |
330 | ||
331 | if (TREE_CODE (*node) == FUNCTION_DECL) | |
332 | TREE_THIS_VOLATILE (*node) = 1; | |
333 | else if (TREE_CODE (type) == POINTER_TYPE | |
334 | && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE) | |
335 | TREE_TYPE (*node) | |
336 | = build_pointer_type | |
337 | (build_type_variant (TREE_TYPE (type), | |
338 | TYPE_READONLY (TREE_TYPE (type)), 1)); | |
339 | else | |
340 | gcc_unreachable (); | |
341 | ||
342 | return NULL_TREE; | |
343 | } | |
344 | ||
345 | /* Handle a "leaf" attribute; arguments as in | |
346 | struct attribute_spec.handler. */ | |
347 | ||
348 | static tree | |
349 | handle_leaf_attribute (tree *node, tree name, | |
350 | tree ARG_UNUSED (args), | |
351 | int ARG_UNUSED (flags), bool *no_add_attrs) | |
352 | { | |
353 | if (TREE_CODE (*node) != FUNCTION_DECL) | |
354 | { | |
355 | warning (OPT_Wattributes, "%qE attribute ignored", name); | |
356 | *no_add_attrs = true; | |
357 | } | |
358 | if (!TREE_PUBLIC (*node)) | |
359 | { | |
360 | warning (OPT_Wattributes, "%qE attribute has no effect", name); | |
361 | *no_add_attrs = true; | |
362 | } | |
363 | ||
364 | return NULL_TREE; | |
365 | } | |
366 | ||
367 | /* Handle a "const" attribute; arguments as in | |
368 | struct attribute_spec.handler. */ | |
369 | ||
370 | static tree | |
371 | handle_const_attribute (tree *node, tree ARG_UNUSED (name), | |
372 | tree ARG_UNUSED (args), int ARG_UNUSED (flags), | |
373 | bool * ARG_UNUSED (no_add_attrs)) | |
374 | { | |
375 | tree type = TREE_TYPE (*node); | |
376 | ||
377 | if (TREE_CODE (*node) == FUNCTION_DECL) | |
378 | TREE_READONLY (*node) = 1; | |
379 | else if (TREE_CODE (type) == POINTER_TYPE | |
380 | && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE) | |
381 | TREE_TYPE (*node) | |
382 | = build_pointer_type | |
383 | (build_type_variant (TREE_TYPE (type), 1, | |
384 | TREE_THIS_VOLATILE (TREE_TYPE (type)))); | |
385 | else | |
386 | gcc_unreachable (); | |
387 | ||
388 | return NULL_TREE; | |
389 | } | |
390 | ||
391 | /* Handle a "malloc" attribute; arguments as in | |
392 | struct attribute_spec.handler. */ | |
393 | ||
394 | tree | |
395 | handle_malloc_attribute (tree *node, tree ARG_UNUSED (name), | |
396 | tree ARG_UNUSED (args), int ARG_UNUSED (flags), | |
397 | bool * ARG_UNUSED (no_add_attrs)) | |
398 | { | |
399 | gcc_assert (TREE_CODE (*node) == FUNCTION_DECL | |
400 | && POINTER_TYPE_P (TREE_TYPE (TREE_TYPE (*node)))); | |
401 | DECL_IS_MALLOC (*node) = 1; | |
402 | return NULL_TREE; | |
403 | } | |
404 | ||
405 | /* Handle a "pure" attribute; arguments as in | |
406 | struct attribute_spec.handler. */ | |
407 | ||
408 | static tree | |
409 | handle_pure_attribute (tree *node, tree ARG_UNUSED (name), | |
410 | tree ARG_UNUSED (args), int ARG_UNUSED (flags), | |
411 | bool * ARG_UNUSED (no_add_attrs)) | |
412 | { | |
413 | gcc_assert (TREE_CODE (*node) == FUNCTION_DECL); | |
414 | DECL_PURE_P (*node) = 1; | |
415 | return NULL_TREE; | |
416 | } | |
417 | ||
418 | /* Handle a "no vops" attribute; arguments as in | |
419 | struct attribute_spec.handler. */ | |
420 | ||
421 | static tree | |
422 | handle_novops_attribute (tree *node, tree ARG_UNUSED (name), | |
423 | tree ARG_UNUSED (args), int ARG_UNUSED (flags), | |
424 | bool * ARG_UNUSED (no_add_attrs)) | |
425 | { | |
426 | gcc_assert (TREE_CODE (*node) == FUNCTION_DECL); | |
427 | DECL_IS_NOVOPS (*node) = 1; | |
428 | return NULL_TREE; | |
429 | } | |
430 | ||
431 | /* Helper for nonnull attribute handling; fetch the operand number | |
432 | from the attribute argument list. */ | |
433 | ||
434 | static bool | |
435 | get_nonnull_operand (tree arg_num_expr, unsigned HOST_WIDE_INT *valp) | |
436 | { | |
437 | /* Verify the arg number is a constant. */ | |
438 | if (!tree_fits_uhwi_p (arg_num_expr)) | |
439 | return false; | |
440 | ||
441 | *valp = TREE_INT_CST_LOW (arg_num_expr); | |
442 | return true; | |
443 | } | |
444 | ||
445 | /* Handle the "nonnull" attribute. */ | |
446 | ||
447 | static tree | |
448 | handle_nonnull_attribute (tree *node, tree ARG_UNUSED (name), | |
449 | tree args, int ARG_UNUSED (flags), | |
450 | bool * ARG_UNUSED (no_add_attrs)) | |
451 | { | |
452 | tree type = *node; | |
453 | ||
454 | /* If no arguments are specified, all pointer arguments should be | |
455 | non-null. Verify a full prototype is given so that the arguments | |
456 | will have the correct types when we actually check them later. | |
457 | Avoid diagnosing type-generic built-ins since those have no | |
458 | prototype. */ | |
459 | if (!args) | |
460 | { | |
461 | gcc_assert (prototype_p (type) | |
462 | || !TYPE_ATTRIBUTES (type) | |
463 | || lookup_attribute ("type generic", TYPE_ATTRIBUTES (type))); | |
464 | ||
465 | return NULL_TREE; | |
466 | } | |
467 | ||
468 | /* Argument list specified. Verify that each argument number references | |
469 | a pointer argument. */ | |
470 | for (; args; args = TREE_CHAIN (args)) | |
471 | { | |
472 | tree argument; | |
473 | unsigned HOST_WIDE_INT arg_num = 0, ck_num; | |
474 | ||
475 | if (!get_nonnull_operand (TREE_VALUE (args), &arg_num)) | |
476 | gcc_unreachable (); | |
477 | ||
478 | argument = TYPE_ARG_TYPES (type); | |
479 | if (argument) | |
480 | { | |
481 | for (ck_num = 1; ; ck_num++) | |
482 | { | |
483 | if (!argument || ck_num == arg_num) | |
484 | break; | |
485 | argument = TREE_CHAIN (argument); | |
486 | } | |
487 | ||
488 | gcc_assert (argument | |
489 | && TREE_CODE (TREE_VALUE (argument)) == POINTER_TYPE); | |
490 | } | |
491 | } | |
492 | ||
493 | return NULL_TREE; | |
494 | } | |
495 | ||
496 | /* Handle a "nothrow" attribute; arguments as in | |
497 | struct attribute_spec.handler. */ | |
498 | ||
499 | static tree | |
500 | handle_nothrow_attribute (tree *node, tree ARG_UNUSED (name), | |
501 | tree ARG_UNUSED (args), int ARG_UNUSED (flags), | |
502 | bool * ARG_UNUSED (no_add_attrs)) | |
503 | { | |
504 | gcc_assert (TREE_CODE (*node) == FUNCTION_DECL); | |
505 | TREE_NOTHROW (*node) = 1; | |
506 | return NULL_TREE; | |
507 | } | |
508 | ||
509 | /* Handle a "type_generic" attribute. */ | |
510 | ||
511 | static tree | |
512 | handle_type_generic_attribute (tree *node, tree ARG_UNUSED (name), | |
513 | tree ARG_UNUSED (args), int ARG_UNUSED (flags), | |
514 | bool * ARG_UNUSED (no_add_attrs)) | |
515 | { | |
516 | /* Ensure we have a function type. */ | |
517 | gcc_assert (TREE_CODE (*node) == FUNCTION_TYPE); | |
518 | ||
519 | /* Ensure we have a variadic function. */ | |
520 | gcc_assert (!prototype_p (*node) || stdarg_p (*node)); | |
521 | ||
522 | return NULL_TREE; | |
523 | } | |
524 | ||
525 | /* Handle a "transaction_pure" attribute. */ | |
526 | ||
527 | static tree | |
528 | handle_transaction_pure_attribute (tree *node, tree ARG_UNUSED (name), | |
529 | tree ARG_UNUSED (args), | |
530 | int ARG_UNUSED (flags), | |
531 | bool * ARG_UNUSED (no_add_attrs)) | |
532 | { | |
533 | /* Ensure we have a function type. */ | |
534 | gcc_assert (TREE_CODE (*node) == FUNCTION_TYPE); | |
535 | ||
536 | return NULL_TREE; | |
537 | } | |
538 | ||
539 | /* Handle a "returns_twice" attribute. */ | |
540 | ||
541 | static tree | |
542 | handle_returns_twice_attribute (tree *node, tree ARG_UNUSED (name), | |
543 | tree ARG_UNUSED (args), | |
544 | int ARG_UNUSED (flags), | |
545 | bool * ARG_UNUSED (no_add_attrs)) | |
546 | { | |
547 | gcc_assert (TREE_CODE (*node) == FUNCTION_DECL); | |
548 | ||
549 | DECL_IS_RETURNS_TWICE (*node) = 1; | |
550 | ||
551 | return NULL_TREE; | |
552 | } | |
553 | ||
554 | /* Handle a "fn spec" attribute; arguments as in | |
555 | struct attribute_spec.handler. */ | |
556 | ||
557 | tree | |
558 | handle_fnspec_attribute (tree *node ATTRIBUTE_UNUSED, tree ARG_UNUSED (name), | |
559 | tree args, int ARG_UNUSED (flags), | |
560 | bool *no_add_attrs ATTRIBUTE_UNUSED) | |
561 | { | |
562 | gcc_assert (args | |
563 | && TREE_CODE (TREE_VALUE (args)) == STRING_CST | |
564 | && !TREE_CHAIN (args)); | |
565 | return NULL_TREE; | |
566 | } | |
567 | ||
568 | /* Language specific attribute handlers. */ | |
569 | ||
570 | /* Handle a "noinline" attribute. */ | |
571 | ||
572 | static tree | |
573 | d_handle_noinline_attribute (tree *node, tree name, | |
574 | tree ARG_UNUSED (args), | |
575 | int ARG_UNUSED (flags), bool *no_add_attrs) | |
576 | { | |
577 | Type *t = TYPE_LANG_FRONTEND (TREE_TYPE (*node)); | |
578 | ||
579 | if (t->ty == Tfunction) | |
580 | DECL_UNINLINABLE (*node) = 1; | |
581 | else | |
582 | { | |
583 | warning (OPT_Wattributes, "%qE attribute ignored", name); | |
584 | *no_add_attrs = true; | |
585 | } | |
586 | ||
587 | return NULL_TREE; | |
588 | } | |
589 | ||
590 | /* Handle a "forceinline" attribute. */ | |
591 | ||
592 | static tree | |
593 | d_handle_forceinline_attribute (tree *node, tree name, | |
594 | tree ARG_UNUSED (args), | |
595 | int ARG_UNUSED (flags), | |
596 | bool *no_add_attrs) | |
597 | { | |
598 | Type *t = TYPE_LANG_FRONTEND (TREE_TYPE (*node)); | |
599 | ||
600 | if (t->ty == Tfunction) | |
601 | { | |
602 | tree attributes = DECL_ATTRIBUTES (*node); | |
603 | ||
604 | /* Push attribute always_inline. */ | |
605 | if (! lookup_attribute ("always_inline", attributes)) | |
606 | DECL_ATTRIBUTES (*node) = tree_cons (get_identifier ("always_inline"), | |
607 | NULL_TREE, attributes); | |
608 | ||
609 | DECL_DECLARED_INLINE_P (*node) = 1; | |
610 | DECL_NO_INLINE_WARNING_P (*node) = 1; | |
611 | DECL_DISREGARD_INLINE_LIMITS (*node) = 1; | |
612 | } | |
613 | else | |
614 | { | |
615 | warning (OPT_Wattributes, "%qE attribute ignored", name); | |
616 | *no_add_attrs = true; | |
617 | } | |
618 | ||
619 | return NULL_TREE; | |
620 | } | |
621 | ||
622 | /* Handle a "flatten" attribute. */ | |
623 | ||
624 | static tree | |
625 | d_handle_flatten_attribute (tree *node, tree name, | |
626 | tree args ATTRIBUTE_UNUSED, | |
627 | int flags ATTRIBUTE_UNUSED, bool *no_add_attrs) | |
628 | { | |
629 | Type *t = TYPE_LANG_FRONTEND (TREE_TYPE (*node)); | |
630 | ||
631 | if (t->ty != Tfunction) | |
632 | { | |
633 | warning (OPT_Wattributes, "%qE attribute ignored", name); | |
634 | *no_add_attrs = true; | |
635 | } | |
636 | ||
637 | return NULL_TREE; | |
638 | } | |
639 | ||
640 | /* Handle a "target" attribute. */ | |
641 | ||
642 | static tree | |
643 | d_handle_target_attribute (tree *node, tree name, tree args, int flags, | |
644 | bool *no_add_attrs) | |
645 | { | |
646 | Type *t = TYPE_LANG_FRONTEND (TREE_TYPE (*node)); | |
647 | ||
648 | /* Ensure we have a function type. */ | |
649 | if (t->ty != Tfunction) | |
650 | { | |
651 | warning (OPT_Wattributes, "%qE attribute ignored", name); | |
652 | *no_add_attrs = true; | |
653 | } | |
654 | else if (! targetm.target_option.valid_attribute_p (*node, name, args, flags)) | |
655 | *no_add_attrs = true; | |
656 | ||
657 | return NULL_TREE; | |
658 | } | |
659 | ||
660 | /* Handle a "noclone" attribute. */ | |
661 | ||
662 | static tree | |
663 | d_handle_noclone_attribute (tree *node, tree name, | |
664 | tree ARG_UNUSED (args), | |
665 | int ARG_UNUSED (flags), | |
666 | bool *no_add_attrs) | |
667 | { | |
668 | Type *t = TYPE_LANG_FRONTEND (TREE_TYPE (*node)); | |
669 | ||
670 | if (t->ty == Tfunction) | |
671 | { | |
672 | tree attributes = DECL_ATTRIBUTES (*node); | |
673 | ||
674 | /* Push attribute noclone. */ | |
675 | if (! lookup_attribute ("noclone", attributes)) | |
676 | DECL_ATTRIBUTES (*node) = tree_cons (get_identifier ("noclone"), | |
677 | NULL_TREE, attributes); | |
678 | } | |
679 | else | |
680 | { | |
681 | warning (OPT_Wattributes, "%qE attribute ignored", name); | |
682 | *no_add_attrs = true; | |
683 | } | |
684 | ||
685 | return NULL_TREE; | |
686 | } | |
687 | ||
688 | /* Handle a "section" attribute; arguments as in | |
689 | struct attribute_spec.handler. */ | |
690 | ||
691 | static tree | |
692 | d_handle_section_attribute (tree *node, tree ARG_UNUSED (name), tree args, | |
693 | int ARG_UNUSED (flags), bool *no_add_attrs) | |
694 | { | |
695 | tree decl = *node; | |
696 | ||
697 | if (targetm_common.have_named_sections) | |
698 | { | |
699 | if (VAR_OR_FUNCTION_DECL_P (decl) | |
700 | && TREE_CODE (TREE_VALUE (args)) == STRING_CST) | |
701 | { | |
702 | if (VAR_P (decl) | |
703 | && current_function_decl != NULL_TREE | |
704 | && !TREE_STATIC (decl)) | |
705 | { | |
706 | error_at (DECL_SOURCE_LOCATION (decl), | |
707 | "section attribute cannot be specified for " | |
708 | "local variables"); | |
709 | *no_add_attrs = true; | |
710 | } | |
711 | ||
712 | /* The decl may have already been given a section attribute | |
713 | from a previous declaration. Ensure they match. */ | |
714 | else if (DECL_SECTION_NAME (decl) != NULL | |
715 | && strcmp (DECL_SECTION_NAME (decl), | |
716 | TREE_STRING_POINTER (TREE_VALUE (args))) != 0) | |
717 | { | |
718 | error ("section of %q+D conflicts with previous declaration", | |
719 | *node); | |
720 | *no_add_attrs = true; | |
721 | } | |
722 | else if (VAR_P (decl) | |
723 | && !targetm.have_tls && targetm.emutls.tmpl_section | |
724 | && DECL_THREAD_LOCAL_P (decl)) | |
725 | { | |
726 | error ("section of %q+D cannot be overridden", *node); | |
727 | *no_add_attrs = true; | |
728 | } | |
729 | else | |
730 | set_decl_section_name (decl, | |
731 | TREE_STRING_POINTER (TREE_VALUE (args))); | |
732 | } | |
733 | else | |
734 | { | |
735 | error ("section attribute not allowed for %q+D", *node); | |
736 | *no_add_attrs = true; | |
737 | } | |
738 | } | |
739 | else | |
740 | { | |
741 | error_at (DECL_SOURCE_LOCATION (*node), | |
742 | "section attributes are not supported for this target"); | |
743 | *no_add_attrs = true; | |
744 | } | |
745 | ||
746 | return NULL_TREE; | |
747 | } | |
748 | ||
749 | /* Handle an "alias" attribute; arguments as in | |
750 | struct attribute_spec.handler. */ | |
751 | ||
752 | static tree | |
753 | d_handle_alias_attribute (tree *node, tree ARG_UNUSED (name), | |
754 | tree args, int ARG_UNUSED (flags), | |
755 | bool *no_add_attrs ATTRIBUTE_UNUSED) | |
756 | { | |
757 | tree decl = *node; | |
758 | ||
759 | if (TREE_CODE (decl) != FUNCTION_DECL | |
760 | && TREE_CODE (decl) != VAR_DECL) | |
761 | { | |
762 | warning (OPT_Wattributes, "%qE attribute ignored", name); | |
763 | *no_add_attrs = true; | |
764 | return NULL_TREE; | |
765 | } | |
766 | else if ((TREE_CODE (decl) == FUNCTION_DECL && DECL_INITIAL (decl)) | |
767 | || (TREE_CODE (decl) != FUNCTION_DECL | |
768 | && TREE_PUBLIC (decl) && !DECL_EXTERNAL (decl)) | |
769 | /* A static variable declaration is always a tentative definition, | |
770 | but the alias is a non-tentative definition which overrides. */ | |
771 | || (TREE_CODE (decl) != FUNCTION_DECL | |
772 | && ! TREE_PUBLIC (decl) && DECL_INITIAL (decl))) | |
773 | { | |
774 | error ("%q+D defined both normally and as %qE attribute", decl, name); | |
775 | *no_add_attrs = true; | |
776 | return NULL_TREE; | |
777 | } | |
778 | else if (decl_function_context (decl)) | |
779 | { | |
780 | error ("%q+D alias functions must be global", name); | |
781 | *no_add_attrs = true; | |
782 | return NULL_TREE; | |
783 | } | |
784 | else | |
785 | { | |
786 | tree id; | |
787 | ||
788 | id = TREE_VALUE (args); | |
789 | if (TREE_CODE (id) != STRING_CST) | |
790 | { | |
791 | error ("attribute %qE argument not a string", name); | |
792 | *no_add_attrs = true; | |
793 | return NULL_TREE; | |
794 | } | |
795 | id = get_identifier (TREE_STRING_POINTER (id)); | |
796 | /* This counts as a use of the object pointed to. */ | |
797 | TREE_USED (id) = 1; | |
798 | ||
799 | if (TREE_CODE (decl) == FUNCTION_DECL) | |
800 | DECL_INITIAL (decl) = error_mark_node; | |
801 | else | |
802 | TREE_STATIC (decl) = 1; | |
803 | ||
804 | return NULL_TREE; | |
805 | } | |
806 | } | |
807 | ||
808 | /* Handle a "weak" attribute; arguments as in | |
809 | struct attribute_spec.handler. */ | |
810 | ||
811 | static tree | |
812 | d_handle_weak_attribute (tree *node, tree name, | |
813 | tree ARG_UNUSED (args), | |
814 | int ARG_UNUSED (flags), | |
815 | bool * ARG_UNUSED (no_add_attrs)) | |
816 | { | |
817 | if (TREE_CODE (*node) == FUNCTION_DECL | |
818 | && DECL_DECLARED_INLINE_P (*node)) | |
819 | { | |
820 | warning (OPT_Wattributes, "inline function %q+D declared weak", *node); | |
821 | *no_add_attrs = true; | |
822 | } | |
823 | else if (VAR_OR_FUNCTION_DECL_P (*node)) | |
824 | { | |
825 | struct symtab_node *n = symtab_node::get (*node); | |
826 | if (n && n->refuse_visibility_changes) | |
827 | error ("%q+D declared weak after being used", *node); | |
828 | declare_weak (*node); | |
829 | } | |
830 | else | |
831 | warning (OPT_Wattributes, "%qE attribute ignored", name); | |
832 | ||
833 | return NULL_TREE; | |
834 | } | |
835 |