Mercurial > hg > CbC > CbC_gcc
comparison gcc/d/d-attribs.cc @ 145:1830386684a0
gcc-9.2.0
author | anatofuz |
---|---|
date | Thu, 13 Feb 2020 11:34:05 +0900 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
131:84e7813d76e9 | 145:1830386684a0 |
---|---|
1 /* d-attribs.c -- D attributes handling. | |
2 Copyright (C) 2015-2020 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 /* 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 |