1 | /* C-family attributes handling. |
2 | Copyright (C) 1992-2023 Free Software Foundation, Inc. |
3 | |
4 | This file is part of GCC. |
5 | |
6 | GCC is free software; you can redistribute it and/or modify it under |
7 | the terms of the GNU General Public License as published by the Free |
8 | Software Foundation; either version 3, or (at your option) any later |
9 | version. |
10 | |
11 | GCC is distributed in the hope that it will be useful, but WITHOUT ANY |
12 | WARRANTY; without even the implied warranty of MERCHANTABILITY or |
13 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
14 | for more details. |
15 | |
16 | You should have received a copy of the GNU General Public License |
17 | along with GCC; see the file COPYING3. If not see |
18 | <http://www.gnu.org/licenses/>. */ |
19 | |
20 | #define INCLUDE_STRING |
21 | #include "config.h" |
22 | #include "system.h" |
23 | #include "coretypes.h" |
24 | #include "target.h" |
25 | #include "function.h" |
26 | #include "tree.h" |
27 | #include "memmodel.h" |
28 | #include "c-common.h" |
29 | #include "gimple-expr.h" |
30 | #include "tm_p.h" |
31 | #include "stringpool.h" |
32 | #include "cgraph.h" |
33 | #include "diagnostic.h" |
34 | #include "intl.h" |
35 | #include "stor-layout.h" |
36 | #include "calls.h" |
37 | #include "attribs.h" |
38 | #include "varasm.h" |
39 | #include "trans-mem.h" |
40 | #include "c-objc.h" |
41 | #include "common/common-target.h" |
42 | #include "langhooks.h" |
43 | #include "tree-inline.h" |
44 | #include "toplev.h" |
45 | #include "tree-iterator.h" |
46 | #include "opts.h" |
47 | #include "gimplify.h" |
48 | #include "tree-pretty-print.h" |
49 | #include "gcc-rich-location.h" |
50 | |
51 | static tree handle_packed_attribute (tree *, tree, tree, int, bool *); |
52 | static tree handle_nocommon_attribute (tree *, tree, tree, int, bool *); |
53 | static tree handle_common_attribute (tree *, tree, tree, int, bool *); |
54 | static tree handle_hot_attribute (tree *, tree, tree, int, bool *); |
55 | static tree handle_cold_attribute (tree *, tree, tree, int, bool *); |
56 | static tree handle_no_sanitize_attribute (tree *, tree, tree, int, bool *); |
57 | static tree handle_no_sanitize_address_attribute (tree *, tree, tree, |
58 | int, bool *); |
59 | static tree handle_no_sanitize_thread_attribute (tree *, tree, tree, |
60 | int, bool *); |
61 | static tree handle_no_address_safety_analysis_attribute (tree *, tree, tree, |
62 | int, bool *); |
63 | static tree handle_no_sanitize_undefined_attribute (tree *, tree, tree, int, |
64 | bool *); |
65 | static tree handle_no_sanitize_coverage_attribute (tree *, tree, tree, int, |
66 | bool *); |
67 | static tree handle_asan_odr_indicator_attribute (tree *, tree, tree, int, |
68 | bool *); |
69 | static tree handle_stack_protect_attribute (tree *, tree, tree, int, bool *); |
70 | static tree handle_no_stack_protector_function_attribute (tree *, tree, |
71 | tree, int, bool *); |
72 | static tree handle_noinline_attribute (tree *, tree, tree, int, bool *); |
73 | static tree handle_noclone_attribute (tree *, tree, tree, int, bool *); |
74 | static tree handle_nocf_check_attribute (tree *, tree, tree, int, bool *); |
75 | static tree handle_symver_attribute (tree *, tree, tree, int, bool *); |
76 | static tree handle_noicf_attribute (tree *, tree, tree, int, bool *); |
77 | static tree handle_noipa_attribute (tree *, tree, tree, int, bool *); |
78 | static tree handle_leaf_attribute (tree *, tree, tree, int, bool *); |
79 | static tree handle_always_inline_attribute (tree *, tree, tree, int, |
80 | bool *); |
81 | static tree handle_gnu_inline_attribute (tree *, tree, tree, int, bool *); |
82 | static tree handle_artificial_attribute (tree *, tree, tree, int, bool *); |
83 | static tree handle_flatten_attribute (tree *, tree, tree, int, bool *); |
84 | static tree handle_error_attribute (tree *, tree, tree, int, bool *); |
85 | static tree handle_used_attribute (tree *, tree, tree, int, bool *); |
86 | static tree handle_uninitialized_attribute (tree *, tree, tree, int, bool *); |
87 | static tree handle_externally_visible_attribute (tree *, tree, tree, int, |
88 | bool *); |
89 | static tree handle_no_reorder_attribute (tree *, tree, tree, int, |
90 | bool *); |
91 | static tree handle_const_attribute (tree *, tree, tree, int, bool *); |
92 | static tree handle_transparent_union_attribute (tree *, tree, tree, |
93 | int, bool *); |
94 | static tree handle_scalar_storage_order_attribute (tree *, tree, tree, |
95 | int, bool *); |
96 | static tree handle_constructor_attribute (tree *, tree, tree, int, bool *); |
97 | static tree handle_destructor_attribute (tree *, tree, tree, int, bool *); |
98 | static tree handle_mode_attribute (tree *, tree, tree, int, bool *); |
99 | static tree handle_section_attribute (tree *, tree, tree, int, bool *); |
100 | static tree handle_special_var_sec_attribute (tree *, tree, tree, int, bool *); |
101 | static tree handle_aligned_attribute (tree *, tree, tree, int, bool *); |
102 | static tree handle_warn_if_not_aligned_attribute (tree *, tree, tree, |
103 | int, bool *); |
104 | static tree handle_strict_flex_array_attribute (tree *, tree, tree, |
105 | int, bool *); |
106 | static tree handle_weak_attribute (tree *, tree, tree, int, bool *) ; |
107 | static tree handle_noplt_attribute (tree *, tree, tree, int, bool *) ; |
108 | static tree handle_alias_ifunc_attribute (bool, tree *, tree, tree, bool *); |
109 | static tree handle_ifunc_attribute (tree *, tree, tree, int, bool *); |
110 | static tree handle_alias_attribute (tree *, tree, tree, int, bool *); |
111 | static tree handle_weakref_attribute (tree *, tree, tree, int, bool *) ; |
112 | static tree handle_visibility_attribute (tree *, tree, tree, int, |
113 | bool *); |
114 | static tree handle_tls_model_attribute (tree *, tree, tree, int, |
115 | bool *); |
116 | static tree handle_no_instrument_function_attribute (tree *, tree, |
117 | tree, int, bool *); |
118 | static tree handle_no_profile_instrument_function_attribute (tree *, tree, |
119 | tree, int, bool *); |
120 | static tree handle_malloc_attribute (tree *, tree, tree, int, bool *); |
121 | static tree handle_dealloc_attribute (tree *, tree, tree, int, bool *); |
122 | static tree handle_tainted_args_attribute (tree *, tree, tree, int, bool *); |
123 | static tree handle_returns_twice_attribute (tree *, tree, tree, int, bool *); |
124 | static tree handle_no_limit_stack_attribute (tree *, tree, tree, int, |
125 | bool *); |
126 | static tree handle_pure_attribute (tree *, tree, tree, int, bool *); |
127 | static tree handle_tm_attribute (tree *, tree, tree, int, bool *); |
128 | static tree handle_tm_wrap_attribute (tree *, tree, tree, int, bool *); |
129 | static tree handle_novops_attribute (tree *, tree, tree, int, bool *); |
130 | static tree handle_unavailable_attribute (tree *, tree, tree, int, |
131 | bool *); |
132 | static tree handle_vector_size_attribute (tree *, tree, tree, int, |
133 | bool *) ATTRIBUTE_NONNULL(3); |
134 | static tree handle_vector_mask_attribute (tree *, tree, tree, int, |
135 | bool *) ATTRIBUTE_NONNULL(3); |
136 | static tree handle_nonnull_attribute (tree *, tree, tree, int, bool *); |
137 | static tree handle_nonstring_attribute (tree *, tree, tree, int, bool *); |
138 | static tree handle_nothrow_attribute (tree *, tree, tree, int, bool *); |
139 | static tree handle_expected_throw_attribute (tree *, tree, tree, int, bool *); |
140 | static tree handle_cleanup_attribute (tree *, tree, tree, int, bool *); |
141 | static tree handle_warn_unused_result_attribute (tree *, tree, tree, int, |
142 | bool *); |
143 | static tree handle_access_attribute (tree *, tree, tree, int, bool *); |
144 | |
145 | static tree handle_sentinel_attribute (tree *, tree, tree, int, bool *); |
146 | static tree handle_type_generic_attribute (tree *, tree, tree, int, bool *); |
147 | static tree handle_alloc_size_attribute (tree *, tree, tree, int, bool *); |
148 | static tree handle_alloc_align_attribute (tree *, tree, tree, int, bool *); |
149 | static tree handle_assume_aligned_attribute (tree *, tree, tree, int, bool *); |
150 | static tree handle_assume_attribute (tree *, tree, tree, int, bool *); |
151 | static tree handle_target_attribute (tree *, tree, tree, int, bool *); |
152 | static tree handle_target_clones_attribute (tree *, tree, tree, int, bool *); |
153 | static tree handle_optimize_attribute (tree *, tree, tree, int, bool *); |
154 | static tree ignore_attribute (tree *, tree, tree, int, bool *); |
155 | static tree handle_no_split_stack_attribute (tree *, tree, tree, int, bool *); |
156 | static tree handle_zero_call_used_regs_attribute (tree *, tree, tree, int, |
157 | bool *); |
158 | static tree handle_argspec_attribute (tree *, tree, tree, int, bool *); |
159 | static tree handle_fnspec_attribute (tree *, tree, tree, int, bool *); |
160 | static tree handle_warn_unused_attribute (tree *, tree, tree, int, bool *); |
161 | static tree handle_returns_nonnull_attribute (tree *, tree, tree, int, bool *); |
162 | static tree handle_omp_declare_simd_attribute (tree *, tree, tree, int, |
163 | bool *); |
164 | static tree handle_omp_declare_variant_attribute (tree *, tree, tree, int, |
165 | bool *); |
166 | static tree handle_simd_attribute (tree *, tree, tree, int, bool *); |
167 | static tree handle_omp_declare_target_attribute (tree *, tree, tree, int, |
168 | bool *); |
169 | static tree handle_non_overlapping_attribute (tree *, tree, tree, int, bool *); |
170 | static tree handle_designated_init_attribute (tree *, tree, tree, int, bool *); |
171 | static tree handle_patchable_function_entry_attribute (tree *, tree, tree, |
172 | int, bool *); |
173 | static tree handle_copy_attribute (tree *, tree, tree, int, bool *); |
174 | static tree handle_nsobject_attribute (tree *, tree, tree, int, bool *); |
175 | static tree handle_objc_root_class_attribute (tree *, tree, tree, int, bool *); |
176 | static tree handle_objc_nullability_attribute (tree *, tree, tree, int, bool *); |
177 | static tree handle_signed_bool_precision_attribute (tree *, tree, tree, int, |
178 | bool *); |
179 | static tree handle_retain_attribute (tree *, tree, tree, int, bool *); |
180 | static tree handle_fd_arg_attribute (tree *, tree, tree, int, bool *); |
181 | static tree handle_null_terminated_string_arg_attribute (tree *, tree, tree, int, bool *); |
182 | |
183 | /* Helper to define attribute exclusions. */ |
184 | #define ATTR_EXCL(name, function, type, variable) \ |
185 | { name, function, type, variable } |
186 | |
187 | /* Define attributes that are mutually exclusive with one another. */ |
188 | static const struct attribute_spec::exclusions attr_aligned_exclusions[] = |
189 | { |
190 | /* Attribute name exclusion applies to: |
191 | function, type, variable */ |
192 | ATTR_EXCL ("aligned" , true, false, false), |
193 | ATTR_EXCL ("packed" , true, false, false), |
194 | ATTR_EXCL (NULL, false, false, false) |
195 | }; |
196 | |
197 | extern const struct attribute_spec::exclusions attr_cold_hot_exclusions[] = |
198 | { |
199 | ATTR_EXCL ("cold" , true, true, true), |
200 | ATTR_EXCL ("hot" , true, true, true), |
201 | ATTR_EXCL (NULL, false, false, false) |
202 | }; |
203 | |
204 | static const struct attribute_spec::exclusions attr_common_exclusions[] = |
205 | { |
206 | ATTR_EXCL ("common" , true, true, true), |
207 | ATTR_EXCL ("nocommon" , true, true, true), |
208 | ATTR_EXCL (NULL, false, false, false), |
209 | }; |
210 | |
211 | static const struct attribute_spec::exclusions attr_inline_exclusions[] = |
212 | { |
213 | ATTR_EXCL ("noinline" , true, true, true), |
214 | ATTR_EXCL (NULL, false, false, false), |
215 | }; |
216 | |
217 | static const struct attribute_spec::exclusions attr_noinline_exclusions[] = |
218 | { |
219 | ATTR_EXCL ("always_inline" , true, true, true), |
220 | ATTR_EXCL ("gnu_inline" , true, true, true), |
221 | ATTR_EXCL (NULL, false, false, false), |
222 | }; |
223 | |
224 | extern const struct attribute_spec::exclusions attr_noreturn_exclusions[] = |
225 | { |
226 | ATTR_EXCL ("alloc_align" , true, true, true), |
227 | ATTR_EXCL ("alloc_size" , true, true, true), |
228 | ATTR_EXCL ("const" , true, true, true), |
229 | ATTR_EXCL ("malloc" , true, true, true), |
230 | ATTR_EXCL ("pure" , true, true, true), |
231 | ATTR_EXCL ("returns_twice" , true, true, true), |
232 | ATTR_EXCL ("warn_unused_result" , true, true, true), |
233 | ATTR_EXCL (NULL, false, false, false), |
234 | }; |
235 | |
236 | static const struct attribute_spec::exclusions |
237 | attr_warn_unused_result_exclusions[] = |
238 | { |
239 | ATTR_EXCL ("noreturn" , true, true, true), |
240 | ATTR_EXCL ("warn_unused_result" , true, true, true), |
241 | ATTR_EXCL (NULL, false, false, false), |
242 | }; |
243 | |
244 | static const struct attribute_spec::exclusions attr_returns_twice_exclusions[] = |
245 | { |
246 | ATTR_EXCL ("noreturn" , true, true, true), |
247 | ATTR_EXCL (NULL, false, false, false), |
248 | }; |
249 | |
250 | /* Exclusions that apply to attribute alloc_align, alloc_size, and malloc. */ |
251 | static const struct attribute_spec::exclusions attr_alloc_exclusions[] = |
252 | { |
253 | ATTR_EXCL ("const" , true, true, true), |
254 | ATTR_EXCL ("noreturn" , true, true, true), |
255 | ATTR_EXCL ("pure" , true, true, true), |
256 | ATTR_EXCL (NULL, false, false, false), |
257 | }; |
258 | |
259 | static const struct attribute_spec::exclusions attr_const_pure_exclusions[] = |
260 | { |
261 | ATTR_EXCL ("const" , true, true, true), |
262 | ATTR_EXCL ("alloc_align" , true, true, true), |
263 | ATTR_EXCL ("alloc_size" , true, true, true), |
264 | ATTR_EXCL ("malloc" , true, true, true), |
265 | ATTR_EXCL ("noreturn" , true, true, true), |
266 | ATTR_EXCL ("pure" , true, true, true), |
267 | ATTR_EXCL (NULL, false, false, false) |
268 | }; |
269 | |
270 | /* Exclusions that apply to attributes that put declarations in specific |
271 | sections. */ |
272 | static const struct attribute_spec::exclusions attr_section_exclusions[] = |
273 | { |
274 | ATTR_EXCL ("noinit" , true, true, true), |
275 | ATTR_EXCL ("persistent" , true, true, true), |
276 | ATTR_EXCL ("section" , true, true, true), |
277 | ATTR_EXCL (NULL, false, false, false), |
278 | }; |
279 | |
280 | static const struct attribute_spec::exclusions attr_stack_protect_exclusions[] = |
281 | { |
282 | ATTR_EXCL ("stack_protect" , true, false, false), |
283 | ATTR_EXCL ("no_stack_protector" , true, false, false), |
284 | ATTR_EXCL (NULL, false, false, false), |
285 | }; |
286 | |
287 | |
288 | /* Table of machine-independent attributes common to all C-like languages. |
289 | |
290 | Current list of processed common attributes: nonnull. */ |
291 | const struct attribute_spec c_common_attribute_table[] = |
292 | { |
293 | /* { name, min_len, max_len, decl_req, type_req, fn_type_req, |
294 | affects_type_identity, handler, exclude } */ |
295 | { .name: "signed_bool_precision" , .min_length: 1, .max_length: 1, .decl_required: false, .type_required: true, .function_type_required: false, .affects_type_identity: true, |
296 | .handler: handle_signed_bool_precision_attribute, NULL }, |
297 | { .name: "packed" , .min_length: 0, .max_length: 0, .decl_required: false, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
298 | .handler: handle_packed_attribute, |
299 | .exclude: attr_aligned_exclusions }, |
300 | { .name: "nocommon" , .min_length: 0, .max_length: 0, .decl_required: true, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
301 | .handler: handle_nocommon_attribute, |
302 | .exclude: attr_common_exclusions }, |
303 | { .name: "common" , .min_length: 0, .max_length: 0, .decl_required: true, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
304 | .handler: handle_common_attribute, |
305 | .exclude: attr_common_exclusions }, |
306 | /* FIXME: logically, noreturn attributes should be listed as |
307 | "false, true, true" and apply to function types. But implementing this |
308 | would require all the places in the compiler that use TREE_THIS_VOLATILE |
309 | on a decl to identify non-returning functions to be located and fixed |
310 | to check the function type instead. */ |
311 | { .name: "noreturn" , .min_length: 0, .max_length: 0, .decl_required: true, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
312 | .handler: handle_noreturn_attribute, |
313 | .exclude: attr_noreturn_exclusions }, |
314 | { .name: "volatile" , .min_length: 0, .max_length: 0, .decl_required: true, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
315 | .handler: handle_noreturn_attribute, NULL }, |
316 | { .name: "stack_protect" , .min_length: 0, .max_length: 0, .decl_required: true, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
317 | .handler: handle_stack_protect_attribute, |
318 | .exclude: attr_stack_protect_exclusions }, |
319 | { .name: "no_stack_protector" , .min_length: 0, .max_length: 0, .decl_required: true, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
320 | .handler: handle_no_stack_protector_function_attribute, |
321 | .exclude: attr_stack_protect_exclusions }, |
322 | { .name: "noinline" , .min_length: 0, .max_length: 0, .decl_required: true, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
323 | .handler: handle_noinline_attribute, |
324 | .exclude: attr_noinline_exclusions }, |
325 | { .name: "noclone" , .min_length: 0, .max_length: 0, .decl_required: true, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
326 | .handler: handle_noclone_attribute, NULL }, |
327 | { .name: "no_icf" , .min_length: 0, .max_length: 0, .decl_required: true, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
328 | .handler: handle_noicf_attribute, NULL }, |
329 | { .name: "noipa" , .min_length: 0, .max_length: 0, .decl_required: true, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
330 | .handler: handle_noipa_attribute, NULL }, |
331 | { .name: "leaf" , .min_length: 0, .max_length: 0, .decl_required: true, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
332 | .handler: handle_leaf_attribute, NULL }, |
333 | { .name: "always_inline" , .min_length: 0, .max_length: 0, .decl_required: true, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
334 | .handler: handle_always_inline_attribute, |
335 | .exclude: attr_inline_exclusions }, |
336 | { .name: "gnu_inline" , .min_length: 0, .max_length: 0, .decl_required: true, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
337 | .handler: handle_gnu_inline_attribute, |
338 | .exclude: attr_inline_exclusions }, |
339 | { .name: "artificial" , .min_length: 0, .max_length: 0, .decl_required: true, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
340 | .handler: handle_artificial_attribute, NULL }, |
341 | { .name: "flatten" , .min_length: 0, .max_length: 0, .decl_required: true, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
342 | .handler: handle_flatten_attribute, NULL }, |
343 | { .name: "used" , .min_length: 0, .max_length: 0, .decl_required: true, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
344 | .handler: handle_used_attribute, NULL }, |
345 | { .name: "unused" , .min_length: 0, .max_length: 0, .decl_required: false, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
346 | .handler: handle_unused_attribute, NULL }, |
347 | { .name: "uninitialized" , .min_length: 0, .max_length: 0, .decl_required: true, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
348 | .handler: handle_uninitialized_attribute, NULL }, |
349 | { .name: "retain" , .min_length: 0, .max_length: 0, .decl_required: true, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
350 | .handler: handle_retain_attribute, NULL }, |
351 | { .name: "externally_visible" , .min_length: 0, .max_length: 0, .decl_required: true, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
352 | .handler: handle_externally_visible_attribute, NULL }, |
353 | { .name: "no_reorder" , .min_length: 0, .max_length: 0, .decl_required: true, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
354 | .handler: handle_no_reorder_attribute, NULL }, |
355 | /* The same comments as for noreturn attributes apply to const ones. */ |
356 | { .name: "const" , .min_length: 0, .max_length: 0, .decl_required: true, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
357 | .handler: handle_const_attribute, |
358 | .exclude: attr_const_pure_exclusions }, |
359 | { .name: "scalar_storage_order" , .min_length: 1, .max_length: 1, .decl_required: false, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
360 | .handler: handle_scalar_storage_order_attribute, NULL }, |
361 | { .name: "transparent_union" , .min_length: 0, .max_length: 0, .decl_required: false, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
362 | .handler: handle_transparent_union_attribute, NULL }, |
363 | { .name: "constructor" , .min_length: 0, .max_length: 1, .decl_required: true, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
364 | .handler: handle_constructor_attribute, NULL }, |
365 | { .name: "destructor" , .min_length: 0, .max_length: 1, .decl_required: true, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
366 | .handler: handle_destructor_attribute, NULL }, |
367 | { .name: "mode" , .min_length: 1, .max_length: 1, .decl_required: false, .type_required: true, .function_type_required: false, .affects_type_identity: false, |
368 | .handler: handle_mode_attribute, NULL }, |
369 | { .name: "section" , .min_length: 1, .max_length: 1, .decl_required: true, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
370 | .handler: handle_section_attribute, .exclude: attr_section_exclusions }, |
371 | { .name: "aligned" , .min_length: 0, .max_length: 1, .decl_required: false, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
372 | .handler: handle_aligned_attribute, |
373 | .exclude: attr_aligned_exclusions }, |
374 | { .name: "warn_if_not_aligned" , .min_length: 0, .max_length: 1, .decl_required: false, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
375 | .handler: handle_warn_if_not_aligned_attribute, NULL }, |
376 | { .name: "strict_flex_array" , .min_length: 1, .max_length: 1, .decl_required: true, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
377 | .handler: handle_strict_flex_array_attribute, NULL }, |
378 | { .name: "weak" , .min_length: 0, .max_length: 0, .decl_required: true, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
379 | .handler: handle_weak_attribute, NULL }, |
380 | { .name: "noplt" , .min_length: 0, .max_length: 0, .decl_required: true, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
381 | .handler: handle_noplt_attribute, NULL }, |
382 | { .name: "ifunc" , .min_length: 1, .max_length: 1, .decl_required: true, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
383 | .handler: handle_ifunc_attribute, NULL }, |
384 | { .name: "alias" , .min_length: 1, .max_length: 1, .decl_required: true, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
385 | .handler: handle_alias_attribute, NULL }, |
386 | { .name: "weakref" , .min_length: 0, .max_length: 1, .decl_required: true, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
387 | .handler: handle_weakref_attribute, NULL }, |
388 | { .name: "no_instrument_function" , .min_length: 0, .max_length: 0, .decl_required: true, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
389 | .handler: handle_no_instrument_function_attribute, |
390 | NULL }, |
391 | { .name: "no_profile_instrument_function" , .min_length: 0, .max_length: 0, .decl_required: true, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
392 | .handler: handle_no_profile_instrument_function_attribute, |
393 | NULL }, |
394 | { .name: "malloc" , .min_length: 0, .max_length: 2, .decl_required: true, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
395 | .handler: handle_malloc_attribute, .exclude: attr_alloc_exclusions }, |
396 | { .name: "returns_twice" , .min_length: 0, .max_length: 0, .decl_required: true, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
397 | .handler: handle_returns_twice_attribute, |
398 | .exclude: attr_returns_twice_exclusions }, |
399 | { .name: "no_stack_limit" , .min_length: 0, .max_length: 0, .decl_required: true, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
400 | .handler: handle_no_limit_stack_attribute, NULL }, |
401 | { .name: "pure" , .min_length: 0, .max_length: 0, .decl_required: true, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
402 | .handler: handle_pure_attribute, |
403 | .exclude: attr_const_pure_exclusions }, |
404 | { .name: "transaction_callable" , .min_length: 0, .max_length: 0, .decl_required: false, .type_required: true, .function_type_required: false, .affects_type_identity: false, |
405 | .handler: handle_tm_attribute, NULL }, |
406 | { .name: "transaction_unsafe" , .min_length: 0, .max_length: 0, .decl_required: false, .type_required: true, .function_type_required: false, .affects_type_identity: true, |
407 | .handler: handle_tm_attribute, NULL }, |
408 | { .name: "transaction_safe" , .min_length: 0, .max_length: 0, .decl_required: false, .type_required: true, .function_type_required: false, .affects_type_identity: true, |
409 | .handler: handle_tm_attribute, NULL }, |
410 | { .name: "transaction_safe_dynamic" , .min_length: 0, .max_length: 0, .decl_required: true, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
411 | .handler: handle_tm_attribute, NULL }, |
412 | { .name: "transaction_may_cancel_outer" , .min_length: 0, .max_length: 0, .decl_required: false, .type_required: true, .function_type_required: false, .affects_type_identity: false, |
413 | .handler: handle_tm_attribute, NULL }, |
414 | /* ??? These two attributes didn't make the transition from the |
415 | Intel language document to the multi-vendor language document. */ |
416 | { .name: "transaction_pure" , .min_length: 0, .max_length: 0, .decl_required: false, .type_required: true, .function_type_required: false, .affects_type_identity: false, |
417 | .handler: handle_tm_attribute, NULL }, |
418 | { .name: "transaction_wrap" , .min_length: 1, .max_length: 1, .decl_required: true, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
419 | .handler: handle_tm_wrap_attribute, NULL }, |
420 | /* For internal use (marking of builtins) only. The name contains space |
421 | to prevent its usage in source code. */ |
422 | { .name: "no vops" , .min_length: 0, .max_length: 0, .decl_required: true, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
423 | .handler: handle_novops_attribute, NULL }, |
424 | { .name: "deprecated" , .min_length: 0, .max_length: 1, .decl_required: false, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
425 | .handler: handle_deprecated_attribute, NULL }, |
426 | { .name: "unavailable" , .min_length: 0, .max_length: 1, .decl_required: false, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
427 | .handler: handle_unavailable_attribute, NULL }, |
428 | { .name: "vector_size" , .min_length: 1, .max_length: 1, .decl_required: false, .type_required: true, .function_type_required: false, .affects_type_identity: true, |
429 | .handler: handle_vector_size_attribute, NULL }, |
430 | { .name: "vector_mask" , .min_length: 0, .max_length: 0, .decl_required: false, .type_required: true, .function_type_required: false, .affects_type_identity: true, |
431 | .handler: handle_vector_mask_attribute, NULL }, |
432 | { .name: "visibility" , .min_length: 1, .max_length: 1, .decl_required: false, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
433 | .handler: handle_visibility_attribute, NULL }, |
434 | { .name: "tls_model" , .min_length: 1, .max_length: 1, .decl_required: true, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
435 | .handler: handle_tls_model_attribute, NULL }, |
436 | { .name: "nonnull" , .min_length: 0, .max_length: -1, .decl_required: false, .type_required: true, .function_type_required: true, .affects_type_identity: false, |
437 | .handler: handle_nonnull_attribute, NULL }, |
438 | { .name: "nonstring" , .min_length: 0, .max_length: 0, .decl_required: true, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
439 | .handler: handle_nonstring_attribute, NULL }, |
440 | { .name: "nothrow" , .min_length: 0, .max_length: 0, .decl_required: true, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
441 | .handler: handle_nothrow_attribute, NULL }, |
442 | { .name: "expected_throw" , .min_length: 0, .max_length: 0, .decl_required: true, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
443 | .handler: handle_expected_throw_attribute, NULL }, |
444 | { .name: "may_alias" , .min_length: 0, .max_length: 0, .decl_required: false, .type_required: true, .function_type_required: false, .affects_type_identity: false, NULL, NULL }, |
445 | { .name: "cleanup" , .min_length: 1, .max_length: 1, .decl_required: true, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
446 | .handler: handle_cleanup_attribute, NULL }, |
447 | { .name: "warn_unused_result" , .min_length: 0, .max_length: 0, .decl_required: false, .type_required: true, .function_type_required: true, .affects_type_identity: false, |
448 | .handler: handle_warn_unused_result_attribute, |
449 | .exclude: attr_warn_unused_result_exclusions }, |
450 | { .name: "sentinel" , .min_length: 0, .max_length: 1, .decl_required: false, .type_required: true, .function_type_required: true, .affects_type_identity: false, |
451 | .handler: handle_sentinel_attribute, NULL }, |
452 | /* For internal use (marking of builtins) only. The name contains space |
453 | to prevent its usage in source code. */ |
454 | { .name: "type generic" , .min_length: 0, .max_length: 0, .decl_required: false, .type_required: true, .function_type_required: true, .affects_type_identity: false, |
455 | .handler: handle_type_generic_attribute, NULL }, |
456 | { .name: "alloc_size" , .min_length: 1, .max_length: 2, .decl_required: false, .type_required: true, .function_type_required: true, .affects_type_identity: false, |
457 | .handler: handle_alloc_size_attribute, |
458 | .exclude: attr_alloc_exclusions }, |
459 | { .name: "cold" , .min_length: 0, .max_length: 0, .decl_required: false, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
460 | .handler: handle_cold_attribute, |
461 | .exclude: attr_cold_hot_exclusions }, |
462 | { .name: "hot" , .min_length: 0, .max_length: 0, .decl_required: false, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
463 | .handler: handle_hot_attribute, |
464 | .exclude: attr_cold_hot_exclusions }, |
465 | { .name: "no_address_safety_analysis" , |
466 | .min_length: 0, .max_length: 0, .decl_required: true, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
467 | .handler: handle_no_address_safety_analysis_attribute, |
468 | NULL }, |
469 | { .name: "no_sanitize" , .min_length: 1, .max_length: -1, .decl_required: true, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
470 | .handler: handle_no_sanitize_attribute, NULL }, |
471 | { .name: "no_sanitize_address" , .min_length: 0, .max_length: 0, .decl_required: true, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
472 | .handler: handle_no_sanitize_address_attribute, NULL }, |
473 | { .name: "no_sanitize_thread" , .min_length: 0, .max_length: 0, .decl_required: true, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
474 | .handler: handle_no_sanitize_thread_attribute, NULL }, |
475 | { .name: "no_sanitize_undefined" , .min_length: 0, .max_length: 0, .decl_required: true, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
476 | .handler: handle_no_sanitize_undefined_attribute, NULL }, |
477 | { .name: "no_sanitize_coverage" , .min_length: 0, .max_length: 0, .decl_required: true, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
478 | .handler: handle_no_sanitize_coverage_attribute, NULL }, |
479 | { .name: "asan odr indicator" , .min_length: 0, .max_length: 0, .decl_required: true, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
480 | .handler: handle_asan_odr_indicator_attribute, NULL }, |
481 | { .name: "warning" , .min_length: 1, .max_length: 1, .decl_required: true, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
482 | .handler: handle_error_attribute, NULL }, |
483 | { .name: "error" , .min_length: 1, .max_length: 1, .decl_required: true, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
484 | .handler: handle_error_attribute, NULL }, |
485 | { .name: "target" , .min_length: 1, .max_length: -1, .decl_required: true, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
486 | .handler: handle_target_attribute, NULL }, |
487 | { .name: "target_clones" , .min_length: 1, .max_length: -1, .decl_required: true, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
488 | .handler: handle_target_clones_attribute, NULL }, |
489 | { .name: "optimize" , .min_length: 1, .max_length: -1, .decl_required: true, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
490 | .handler: handle_optimize_attribute, NULL }, |
491 | /* For internal use only. The leading '*' both prevents its usage in |
492 | source code and signals that it may be overridden by machine tables. */ |
493 | { .name: "*tm regparm" , .min_length: 0, .max_length: 0, .decl_required: false, .type_required: true, .function_type_required: true, .affects_type_identity: false, |
494 | .handler: ignore_attribute, NULL }, |
495 | { .name: "no_split_stack" , .min_length: 0, .max_length: 0, .decl_required: true, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
496 | .handler: handle_no_split_stack_attribute, NULL }, |
497 | { .name: "zero_call_used_regs" , .min_length: 1, .max_length: 1, .decl_required: true, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
498 | .handler: handle_zero_call_used_regs_attribute, NULL }, |
499 | /* For internal use only (marking of function arguments). |
500 | The name contains a space to prevent its usage in source code. */ |
501 | { .name: "arg spec" , .min_length: 1, .max_length: -1, .decl_required: true, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
502 | .handler: handle_argspec_attribute, NULL }, |
503 | /* For internal use (marking of builtins and runtime functions) only. |
504 | The name contains space to prevent its usage in source code. */ |
505 | { .name: "fn spec" , .min_length: 1, .max_length: 1, .decl_required: false, .type_required: true, .function_type_required: true, .affects_type_identity: false, |
506 | .handler: handle_fnspec_attribute, NULL }, |
507 | { .name: "warn_unused" , .min_length: 0, .max_length: 0, .decl_required: false, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
508 | .handler: handle_warn_unused_attribute, NULL }, |
509 | { .name: "returns_nonnull" , .min_length: 0, .max_length: 0, .decl_required: false, .type_required: true, .function_type_required: true, .affects_type_identity: false, |
510 | .handler: handle_returns_nonnull_attribute, NULL }, |
511 | { .name: "omp declare simd" , .min_length: 0, .max_length: -1, .decl_required: true, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
512 | .handler: handle_omp_declare_simd_attribute, NULL }, |
513 | { .name: "omp declare variant base" , .min_length: 0, .max_length: -1, .decl_required: true, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
514 | .handler: handle_omp_declare_variant_attribute, NULL }, |
515 | { .name: "omp declare variant variant" , .min_length: 0, .max_length: -1, .decl_required: true, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
516 | .handler: handle_omp_declare_variant_attribute, NULL }, |
517 | { .name: "simd" , .min_length: 0, .max_length: 1, .decl_required: true, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
518 | .handler: handle_simd_attribute, NULL }, |
519 | { .name: "omp declare target" , .min_length: 0, .max_length: -1, .decl_required: true, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
520 | .handler: handle_omp_declare_target_attribute, NULL }, |
521 | { .name: "omp declare target link" , .min_length: 0, .max_length: 0, .decl_required: true, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
522 | .handler: handle_omp_declare_target_attribute, NULL }, |
523 | { .name: "omp declare target implicit" , .min_length: 0, .max_length: 0, .decl_required: true, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
524 | .handler: handle_omp_declare_target_attribute, NULL }, |
525 | { .name: "omp declare target indirect" , .min_length: 0, .max_length: 0, .decl_required: true, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
526 | .handler: handle_omp_declare_target_attribute, NULL }, |
527 | { .name: "omp declare target host" , .min_length: 0, .max_length: 0, .decl_required: true, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
528 | .handler: handle_omp_declare_target_attribute, NULL }, |
529 | { .name: "omp declare target nohost" , .min_length: 0, .max_length: 0, .decl_required: true, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
530 | .handler: handle_omp_declare_target_attribute, NULL }, |
531 | { .name: "omp declare target block" , .min_length: 0, .max_length: 0, .decl_required: true, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
532 | .handler: handle_omp_declare_target_attribute, NULL }, |
533 | { .name: "non overlapping" , .min_length: 0, .max_length: 0, .decl_required: true, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
534 | .handler: handle_non_overlapping_attribute, NULL }, |
535 | { .name: "alloc_align" , .min_length: 1, .max_length: 1, .decl_required: false, .type_required: true, .function_type_required: true, .affects_type_identity: false, |
536 | .handler: handle_alloc_align_attribute, |
537 | .exclude: attr_alloc_exclusions }, |
538 | { .name: "assume_aligned" , .min_length: 1, .max_length: 2, .decl_required: false, .type_required: true, .function_type_required: true, .affects_type_identity: false, |
539 | .handler: handle_assume_aligned_attribute, NULL }, |
540 | { .name: "designated_init" , .min_length: 0, .max_length: 0, .decl_required: false, .type_required: true, .function_type_required: false, .affects_type_identity: false, |
541 | .handler: handle_designated_init_attribute, NULL }, |
542 | { .name: "fallthrough" , .min_length: 0, .max_length: 0, .decl_required: false, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
543 | .handler: handle_fallthrough_attribute, NULL }, |
544 | { .name: "assume" , .min_length: 1, .max_length: 1, .decl_required: false, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
545 | .handler: handle_assume_attribute, NULL }, |
546 | { .name: "patchable_function_entry" , .min_length: 1, .max_length: 2, .decl_required: true, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
547 | .handler: handle_patchable_function_entry_attribute, |
548 | NULL }, |
549 | { .name: "nocf_check" , .min_length: 0, .max_length: 0, .decl_required: false, .type_required: true, .function_type_required: true, .affects_type_identity: true, |
550 | .handler: handle_nocf_check_attribute, NULL }, |
551 | { .name: "symver" , .min_length: 1, .max_length: -1, .decl_required: true, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
552 | .handler: handle_symver_attribute, NULL}, |
553 | { .name: "copy" , .min_length: 1, .max_length: 1, .decl_required: false, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
554 | .handler: handle_copy_attribute, NULL }, |
555 | { .name: "noinit" , .min_length: 0, .max_length: 0, .decl_required: true, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
556 | .handler: handle_special_var_sec_attribute, .exclude: attr_section_exclusions }, |
557 | { .name: "persistent" , .min_length: 0, .max_length: 0, .decl_required: true, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
558 | .handler: handle_special_var_sec_attribute, .exclude: attr_section_exclusions }, |
559 | { .name: "access" , .min_length: 1, .max_length: 3, .decl_required: false, .type_required: true, .function_type_required: true, .affects_type_identity: false, |
560 | .handler: handle_access_attribute, NULL }, |
561 | /* Attributes used by Objective-C. */ |
562 | { .name: "NSObject" , .min_length: 0, .max_length: 0, .decl_required: true, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
563 | .handler: handle_nsobject_attribute, NULL }, |
564 | { .name: "objc_root_class" , .min_length: 0, .max_length: 0, .decl_required: true, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
565 | .handler: handle_objc_root_class_attribute, NULL }, |
566 | { .name: "objc_nullability" , .min_length: 1, .max_length: 1, .decl_required: true, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
567 | .handler: handle_objc_nullability_attribute, NULL }, |
568 | { .name: "*dealloc" , .min_length: 1, .max_length: 2, .decl_required: true, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
569 | .handler: handle_dealloc_attribute, NULL }, |
570 | { .name: "tainted_args" , .min_length: 0, .max_length: 0, .decl_required: true, .type_required: false, .function_type_required: false, .affects_type_identity: false, |
571 | .handler: handle_tainted_args_attribute, NULL }, |
572 | { .name: "fd_arg" , .min_length: 1, .max_length: 1, .decl_required: false, .type_required: true, .function_type_required: true, .affects_type_identity: false, |
573 | .handler: handle_fd_arg_attribute, NULL}, |
574 | { .name: "fd_arg_read" , .min_length: 1, .max_length: 1, .decl_required: false, .type_required: true, .function_type_required: true, .affects_type_identity: false, |
575 | .handler: handle_fd_arg_attribute, NULL}, |
576 | { .name: "fd_arg_write" , .min_length: 1, .max_length: 1, .decl_required: false, .type_required: true, .function_type_required: true, .affects_type_identity: false, |
577 | .handler: handle_fd_arg_attribute, NULL}, |
578 | { .name: "null_terminated_string_arg" , .min_length: 1, .max_length: 1, .decl_required: false, .type_required: true, .function_type_required: true, .affects_type_identity: false, |
579 | .handler: handle_null_terminated_string_arg_attribute, NULL}, |
580 | { NULL, .min_length: 0, .max_length: 0, .decl_required: false, .type_required: false, .function_type_required: false, .affects_type_identity: false, NULL, NULL } |
581 | }; |
582 | |
583 | /* Give the specifications for the format attributes, used by C and all |
584 | descendants. |
585 | |
586 | Current list of processed format attributes: format, format_arg. */ |
587 | const struct attribute_spec c_common_format_attribute_table[] = |
588 | { |
589 | /* { name, min_len, max_len, decl_req, type_req, fn_type_req, |
590 | affects_type_identity, handler, exclude } */ |
591 | { .name: "format" , .min_length: 3, .max_length: 3, .decl_required: false, .type_required: true, .function_type_required: true, .affects_type_identity: false, |
592 | .handler: handle_format_attribute, NULL }, |
593 | { .name: "format_arg" , .min_length: 1, .max_length: 1, .decl_required: false, .type_required: true, .function_type_required: true, .affects_type_identity: false, |
594 | .handler: handle_format_arg_attribute, NULL }, |
595 | { NULL, .min_length: 0, .max_length: 0, .decl_required: false, .type_required: false, .function_type_required: false, .affects_type_identity: false, NULL, NULL } |
596 | }; |
597 | |
598 | /* Returns TRUE iff the attribute indicated by ATTR_ID takes a plain |
599 | identifier as an argument, so the front end shouldn't look it up. */ |
600 | |
601 | bool |
602 | attribute_takes_identifier_p (const_tree attr_id) |
603 | { |
604 | const struct attribute_spec *spec = lookup_attribute_spec (attr_id); |
605 | if (spec == NULL) |
606 | /* Unknown attribute that we'll end up ignoring, return true so we |
607 | don't complain about an identifier argument. */ |
608 | return true; |
609 | else if (!strcmp (s1: "mode" , s2: spec->name) |
610 | || !strcmp (s1: "format" , s2: spec->name) |
611 | || !strcmp (s1: "cleanup" , s2: spec->name) |
612 | || !strcmp (s1: "access" , s2: spec->name)) |
613 | return true; |
614 | else |
615 | return targetm.attribute_takes_identifier_p (attr_id); |
616 | } |
617 | |
618 | /* Verify that argument value POS at position ARGNO to attribute NAME |
619 | applied to function FN (which is either a function declaration or function |
620 | type) refers to a function parameter at position POS and the expected type |
621 | CODE. Treat CODE == INTEGER_TYPE as matching all C integral types except |
622 | bool. If successful, return POS after default conversions (and possibly |
623 | adjusted by ADJUST_POS). Otherwise, issue appropriate warnings and return |
624 | null. A non-zero 1-based ARGNO should be passed in by callers only for |
625 | attributes with more than one argument. |
626 | |
627 | N.B. This function modifies POS. */ |
628 | |
629 | tree |
630 | positional_argument (const_tree fn, const_tree atname, tree &pos, |
631 | tree_code code, int argno /* = 0 */, |
632 | int flags /* = posargflags () */) |
633 | { |
634 | const_tree fndecl = TYPE_P (fn) ? NULL_TREE : fn; |
635 | const_tree fntype = TYPE_P (fn) ? fn : TREE_TYPE (fn); |
636 | if (pos && TREE_CODE (pos) != IDENTIFIER_NODE |
637 | && TREE_CODE (pos) != FUNCTION_DECL) |
638 | pos = default_conversion (pos); |
639 | |
640 | tree postype = TREE_TYPE (pos); |
641 | if (pos == error_mark_node || !postype) |
642 | { |
643 | /* Only mention the positional argument number when it's non-zero. */ |
644 | if (argno < 1) |
645 | warning (OPT_Wattributes, |
646 | "%qE attribute argument is invalid" , atname); |
647 | else |
648 | warning (OPT_Wattributes, |
649 | "%qE attribute argument %i is invalid" , atname, argno); |
650 | |
651 | return NULL_TREE; |
652 | } |
653 | |
654 | if (!INTEGRAL_TYPE_P (postype)) |
655 | { |
656 | /* Handle this case specially to avoid mentioning the value |
657 | of pointer constants in diagnostics. Only mention |
658 | the positional argument number when it's non-zero. */ |
659 | if (argno < 1) |
660 | warning (OPT_Wattributes, |
661 | "%qE attribute argument has type %qT" , |
662 | atname, postype); |
663 | else |
664 | warning (OPT_Wattributes, |
665 | "%qE attribute argument %i has type %qT" , |
666 | atname, argno, postype); |
667 | |
668 | return NULL_TREE; |
669 | } |
670 | |
671 | if (TREE_CODE (pos) != INTEGER_CST) |
672 | { |
673 | /* Only mention the argument number when it's non-zero. */ |
674 | if (argno < 1) |
675 | warning (OPT_Wattributes, |
676 | "%qE attribute argument value %qE is not an integer " |
677 | "constant" , |
678 | atname, pos); |
679 | else |
680 | warning (OPT_Wattributes, |
681 | "%qE attribute argument %i value %qE is not an integer " |
682 | "constant" , |
683 | atname, argno, pos); |
684 | |
685 | return NULL_TREE; |
686 | } |
687 | |
688 | /* Argument positions are 1-based. */ |
689 | if (integer_zerop (pos)) |
690 | { |
691 | if (flags & POSARG_ZERO) |
692 | /* Zero is explicitly allowed. */ |
693 | return pos; |
694 | |
695 | if (argno < 1) |
696 | warning (OPT_Wattributes, |
697 | "%qE attribute argument value %qE does not refer to " |
698 | "a function parameter" , |
699 | atname, pos); |
700 | else |
701 | warning (OPT_Wattributes, |
702 | "%qE attribute argument %i value %qE does not refer to " |
703 | "a function parameter" , |
704 | atname, argno, pos); |
705 | |
706 | return NULL_TREE; |
707 | } |
708 | |
709 | if (!prototype_p (fntype)) |
710 | return pos; |
711 | |
712 | /* ADJUST_POS is non-zero in C++ when the function type has invisible |
713 | parameters generated by the compiler, such as the in-charge or VTT |
714 | parameters. */ |
715 | const int adjust_pos = maybe_adjust_arg_pos_for_attribute (fndecl); |
716 | |
717 | /* Verify that the argument position does not exceed the number |
718 | of formal arguments to the function. When POSARG_ELLIPSIS |
719 | is set, ARGNO may be beyond the last argument of a vararg |
720 | function. */ |
721 | unsigned nargs = type_num_arguments (fntype); |
722 | if (!nargs |
723 | || !tree_fits_uhwi_p (pos) |
724 | || ((flags & POSARG_ELLIPSIS) == 0 |
725 | && !IN_RANGE (tree_to_uhwi (pos) + adjust_pos, 1, nargs))) |
726 | { |
727 | |
728 | if (argno < 1) |
729 | warning (OPT_Wattributes, |
730 | "%qE attribute argument value %qE exceeds the number " |
731 | "of function parameters %u" , |
732 | atname, pos, nargs); |
733 | else |
734 | warning (OPT_Wattributes, |
735 | "%qE attribute argument %i value %qE exceeds the number " |
736 | "of function parameters %u" , |
737 | atname, argno, pos, nargs); |
738 | return NULL_TREE; |
739 | } |
740 | |
741 | /* Verify that the type of the referenced formal argument matches |
742 | the expected type. Invisible parameters may have been added by |
743 | the compiler, so adjust the position accordingly. */ |
744 | unsigned HOST_WIDE_INT ipos = tree_to_uhwi (pos) + adjust_pos; |
745 | |
746 | /* Zero was handled above. */ |
747 | gcc_assert (ipos != 0); |
748 | |
749 | if (tree argtype = type_argument_type (fntype, ipos)) |
750 | { |
751 | if (argtype == error_mark_node) |
752 | return NULL_TREE; |
753 | |
754 | if (flags & POSARG_ELLIPSIS) |
755 | { |
756 | if (argno < 1) |
757 | error ("%qE attribute argument value %qE does not refer to " |
758 | "a variable argument list" , |
759 | atname, pos); |
760 | else |
761 | error ("%qE attribute argument %i value %qE does not refer to " |
762 | "a variable argument list" , |
763 | atname, argno, pos); |
764 | return NULL_TREE; |
765 | } |
766 | |
767 | /* Where the expected code is STRING_CST accept any pointer |
768 | expected by attribute format (this includes possibly qualified |
769 | char pointers and, for targets like Darwin, also pointers to |
770 | struct CFString). */ |
771 | bool type_match; |
772 | if (code == STRING_CST) |
773 | type_match = valid_format_string_type_p (argtype); |
774 | else if (code == INTEGER_TYPE) |
775 | /* For integers, accept enums, wide characters and other types |
776 | that match INTEGRAL_TYPE_P except for bool. */ |
777 | type_match = (INTEGRAL_TYPE_P (argtype) |
778 | && TREE_CODE (argtype) != BOOLEAN_TYPE); |
779 | else |
780 | type_match = TREE_CODE (argtype) == code; |
781 | |
782 | if (!type_match) |
783 | { |
784 | if (code == STRING_CST) |
785 | { |
786 | /* Reject invalid format strings with an error. */ |
787 | if (argno < 1) |
788 | error ("%qE attribute argument value %qE refers to " |
789 | "parameter type %qT" , |
790 | atname, pos, argtype); |
791 | else |
792 | error ("%qE attribute argument %i value %qE refers to " |
793 | "parameter type %qT" , |
794 | atname, argno, pos, argtype); |
795 | |
796 | return NULL_TREE; |
797 | } |
798 | |
799 | if (argno < 1) |
800 | warning (OPT_Wattributes, |
801 | "%qE attribute argument value %qE refers to " |
802 | "parameter type %qT" , |
803 | atname, pos, argtype); |
804 | else |
805 | warning (OPT_Wattributes, |
806 | "%qE attribute argument %i value %qE refers to " |
807 | "parameter type %qT" , |
808 | atname, argno, pos, argtype); |
809 | return NULL_TREE; |
810 | } |
811 | } |
812 | else if (!(flags & POSARG_ELLIPSIS)) |
813 | { |
814 | if (argno < 1) |
815 | warning (OPT_Wattributes, |
816 | "%qE attribute argument value %qE refers to " |
817 | "a variadic function parameter of unknown type" , |
818 | atname, pos); |
819 | else |
820 | warning (OPT_Wattributes, |
821 | "%qE attribute argument %i value %qE refers to " |
822 | "a variadic function parameter of unknown type" , |
823 | atname, argno, pos); |
824 | return NULL_TREE; |
825 | } |
826 | |
827 | return build_int_cst (TREE_TYPE (pos), ipos); |
828 | } |
829 | |
830 | /* Return the first of DECL or TYPE attributes installed in NODE if it's |
831 | a DECL, or TYPE attributes if it's a TYPE, or null otherwise. */ |
832 | |
833 | static tree |
834 | decl_or_type_attrs (tree node) |
835 | { |
836 | if (DECL_P (node)) |
837 | { |
838 | if (tree attrs = DECL_ATTRIBUTES (node)) |
839 | return attrs; |
840 | |
841 | tree type = TREE_TYPE (node); |
842 | if (type == error_mark_node) |
843 | return NULL_TREE; |
844 | return TYPE_ATTRIBUTES (type); |
845 | } |
846 | |
847 | if (TYPE_P (node)) |
848 | return TYPE_ATTRIBUTES (node); |
849 | |
850 | return NULL_TREE; |
851 | } |
852 | |
853 | /* Given a pair of NODEs for arbitrary DECLs or TYPEs, validate one or |
854 | two integral or string attribute arguments NEWARGS to be applied to |
855 | NODE[0] for the absence of conflicts with the same attribute arguments |
856 | already applied to NODE[1]. Issue a warning for conflicts and return |
857 | false. Otherwise, when no conflicts are found, return true. */ |
858 | |
859 | static bool |
860 | validate_attr_args (tree node[2], tree name, tree newargs[2]) |
861 | { |
862 | /* First validate the arguments against those already applied to |
863 | the same declaration (or type). */ |
864 | tree self[2] = { node[0], node[0] }; |
865 | if (node[0] != node[1] && !validate_attr_args (node: self, name, newargs)) |
866 | return false; |
867 | |
868 | if (!node[1]) |
869 | return true; |
870 | |
871 | /* Extract the same attribute from the previous declaration or type. */ |
872 | tree prevattr = decl_or_type_attrs (node: node[1]); |
873 | const char* const namestr = IDENTIFIER_POINTER (name); |
874 | prevattr = lookup_attribute (attr_name: namestr, list: prevattr); |
875 | if (!prevattr) |
876 | return true; |
877 | |
878 | /* Extract one or both attribute arguments. */ |
879 | tree prevargs[2]; |
880 | prevargs[0] = TREE_VALUE (TREE_VALUE (prevattr)); |
881 | prevargs[1] = TREE_CHAIN (TREE_VALUE (prevattr)); |
882 | if (prevargs[1]) |
883 | prevargs[1] = TREE_VALUE (prevargs[1]); |
884 | |
885 | /* Both arguments must be equal or, for the second pair, neither must |
886 | be provided to succeed. */ |
887 | bool arg1eq, arg2eq; |
888 | if (TREE_CODE (newargs[0]) == INTEGER_CST) |
889 | { |
890 | arg1eq = tree_int_cst_equal (newargs[0], prevargs[0]); |
891 | if (newargs[1] && prevargs[1]) |
892 | arg2eq = tree_int_cst_equal (newargs[1], prevargs[1]); |
893 | else |
894 | arg2eq = newargs[1] == prevargs[1]; |
895 | } |
896 | else if (TREE_CODE (newargs[0]) == STRING_CST) |
897 | { |
898 | const char *s0 = TREE_STRING_POINTER (newargs[0]); |
899 | const char *s1 = TREE_STRING_POINTER (prevargs[0]); |
900 | arg1eq = strcmp (s1: s0, s2: s1) == 0; |
901 | if (newargs[1] && prevargs[1]) |
902 | { |
903 | s0 = TREE_STRING_POINTER (newargs[1]); |
904 | s1 = TREE_STRING_POINTER (prevargs[1]); |
905 | arg2eq = strcmp (s1: s0, s2: s1) == 0; |
906 | } |
907 | else |
908 | arg2eq = newargs[1] == prevargs[1]; |
909 | } |
910 | else |
911 | gcc_unreachable (); |
912 | |
913 | if (arg1eq && arg2eq) |
914 | return true; |
915 | |
916 | /* If the two locations are different print a note pointing to |
917 | the previous one. */ |
918 | const location_t curloc = input_location; |
919 | const location_t prevloc = |
920 | DECL_P (node[1]) ? DECL_SOURCE_LOCATION (node[1]) : curloc; |
921 | |
922 | /* Format the attribute specification for convenience. */ |
923 | char newspec[80], prevspec[80]; |
924 | if (newargs[1]) |
925 | snprintf (s: newspec, maxlen: sizeof newspec, format: "%s (%s, %s)" , namestr, |
926 | print_generic_expr_to_str (newargs[0]), |
927 | print_generic_expr_to_str (newargs[1])); |
928 | else |
929 | snprintf (s: newspec, maxlen: sizeof newspec, format: "%s (%s)" , namestr, |
930 | print_generic_expr_to_str (newargs[0])); |
931 | |
932 | if (prevargs[1]) |
933 | snprintf (s: prevspec, maxlen: sizeof prevspec, format: "%s (%s, %s)" , namestr, |
934 | print_generic_expr_to_str (prevargs[0]), |
935 | print_generic_expr_to_str (prevargs[1])); |
936 | else |
937 | snprintf (s: prevspec, maxlen: sizeof prevspec, format: "%s (%s)" , namestr, |
938 | print_generic_expr_to_str (prevargs[0])); |
939 | |
940 | if (warning_at (curloc, OPT_Wattributes, |
941 | "ignoring attribute %qs because it conflicts " |
942 | "with previous %qs" , |
943 | newspec, prevspec) |
944 | && curloc != prevloc) |
945 | inform (prevloc, "previous declaration here" ); |
946 | |
947 | return false; |
948 | } |
949 | |
950 | /* Convenience wrapper for validate_attr_args to validate a single |
951 | attribute argument. Used by handlers for attributes that take |
952 | just a single argument. */ |
953 | |
954 | static bool |
955 | validate_attr_arg (tree node[2], tree name, tree newarg) |
956 | { |
957 | tree argarray[2] = { newarg, NULL_TREE }; |
958 | return validate_attr_args (node, name, newargs: argarray); |
959 | } |
960 | |
961 | /* Attribute handlers common to C front ends. */ |
962 | |
963 | /* Handle a "signed_bool_precision" attribute; arguments as in |
964 | struct attribute_spec.handler. */ |
965 | |
966 | static tree |
967 | handle_signed_bool_precision_attribute (tree *node, tree name, tree args, |
968 | int, bool *no_add_attrs) |
969 | { |
970 | *no_add_attrs = true; |
971 | if (!flag_gimple) |
972 | { |
973 | warning (OPT_Wattributes, "%qE attribute ignored" , name); |
974 | return NULL_TREE; |
975 | } |
976 | |
977 | if (!TYPE_P (*node) || TREE_CODE (*node) != BOOLEAN_TYPE) |
978 | { |
979 | warning (OPT_Wattributes, "%qE attribute only supported on " |
980 | "boolean types" , name); |
981 | return NULL_TREE; |
982 | } |
983 | |
984 | unsigned HOST_WIDE_INT prec = HOST_WIDE_INT_M1U; |
985 | if (tree_fits_uhwi_p (TREE_VALUE (args))) |
986 | prec = tree_to_uhwi (TREE_VALUE (args)); |
987 | if (prec > MAX_FIXED_MODE_SIZE) |
988 | { |
989 | warning (OPT_Wattributes, "%qE attribute with unsupported boolean " |
990 | "precision" , name); |
991 | return NULL_TREE; |
992 | } |
993 | |
994 | tree new_type = build_nonstandard_boolean_type (prec); |
995 | *node = lang_hooks.types.reconstruct_complex_type (*node, new_type); |
996 | |
997 | return NULL_TREE; |
998 | } |
999 | |
1000 | /* Handle a "packed" attribute; arguments as in |
1001 | struct attribute_spec.handler. */ |
1002 | |
1003 | static tree |
1004 | handle_packed_attribute (tree *node, tree name, tree ARG_UNUSED (args), |
1005 | int flags, bool *no_add_attrs) |
1006 | { |
1007 | if (TYPE_P (*node)) |
1008 | { |
1009 | if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE)) |
1010 | { |
1011 | warning (OPT_Wattributes, |
1012 | "%qE attribute ignored for type %qT" , name, *node); |
1013 | *no_add_attrs = true; |
1014 | } |
1015 | else |
1016 | TYPE_PACKED (*node) = 1; |
1017 | } |
1018 | else if (TREE_CODE (*node) == FIELD_DECL) |
1019 | { |
1020 | if (TYPE_ALIGN (TREE_TYPE (*node)) <= BITS_PER_UNIT |
1021 | /* Still pack bitfields. */ |
1022 | && ! DECL_C_BIT_FIELD (*node)) |
1023 | warning (OPT_Wattributes, |
1024 | "%qE attribute ignored for field of type %qT" , |
1025 | name, TREE_TYPE (*node)); |
1026 | else |
1027 | DECL_PACKED (*node) = 1; |
1028 | } |
1029 | /* We can't set DECL_PACKED for a VAR_DECL, because the bit is |
1030 | used for DECL_REGISTER. It wouldn't mean anything anyway. |
1031 | We can't set DECL_PACKED on the type of a TYPE_DECL, because |
1032 | that changes what the typedef is typing. */ |
1033 | else |
1034 | { |
1035 | warning (OPT_Wattributes, "%qE attribute ignored" , name); |
1036 | *no_add_attrs = true; |
1037 | } |
1038 | |
1039 | return NULL_TREE; |
1040 | } |
1041 | |
1042 | /* Handle a "nocommon" attribute; arguments as in |
1043 | struct attribute_spec.handler. */ |
1044 | |
1045 | static tree |
1046 | handle_nocommon_attribute (tree *node, tree name, |
1047 | tree ARG_UNUSED (args), |
1048 | int ARG_UNUSED (flags), bool *no_add_attrs) |
1049 | { |
1050 | if (VAR_P (*node)) |
1051 | DECL_COMMON (*node) = 0; |
1052 | else |
1053 | { |
1054 | warning (OPT_Wattributes, "%qE attribute ignored" , name); |
1055 | *no_add_attrs = true; |
1056 | } |
1057 | |
1058 | return NULL_TREE; |
1059 | } |
1060 | |
1061 | /* Handle a "common" attribute; arguments as in |
1062 | struct attribute_spec.handler. */ |
1063 | |
1064 | static tree |
1065 | handle_common_attribute (tree *node, tree name, tree ARG_UNUSED (args), |
1066 | int ARG_UNUSED (flags), bool *no_add_attrs) |
1067 | { |
1068 | if (VAR_P (*node)) |
1069 | DECL_COMMON (*node) = 1; |
1070 | else |
1071 | { |
1072 | warning (OPT_Wattributes, "%qE attribute ignored" , name); |
1073 | *no_add_attrs = true; |
1074 | } |
1075 | |
1076 | return NULL_TREE; |
1077 | } |
1078 | |
1079 | /* Handle a "noreturn" attribute; arguments as in |
1080 | struct attribute_spec.handler. */ |
1081 | |
1082 | tree |
1083 | handle_noreturn_attribute (tree *node, tree name, tree ARG_UNUSED (args), |
1084 | int ARG_UNUSED (flags), bool *no_add_attrs) |
1085 | { |
1086 | tree type = TREE_TYPE (*node); |
1087 | |
1088 | /* See FIXME comment in c_common_attribute_table. */ |
1089 | if (TREE_CODE (*node) == FUNCTION_DECL |
1090 | || objc_method_decl (TREE_CODE (*node))) |
1091 | TREE_THIS_VOLATILE (*node) = 1; |
1092 | else if (TREE_CODE (type) == POINTER_TYPE |
1093 | && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE) |
1094 | TREE_TYPE (*node) |
1095 | = (build_qualified_type |
1096 | (build_pointer_type |
1097 | (build_type_variant (TREE_TYPE (type), |
1098 | TYPE_READONLY (TREE_TYPE (type)), 1)), |
1099 | TYPE_QUALS (type))); |
1100 | else |
1101 | { |
1102 | warning (OPT_Wattributes, "%qE attribute ignored" , name); |
1103 | *no_add_attrs = true; |
1104 | } |
1105 | |
1106 | return NULL_TREE; |
1107 | } |
1108 | |
1109 | /* Handle a "hot" and attribute; arguments as in |
1110 | struct attribute_spec.handler. */ |
1111 | |
1112 | static tree |
1113 | handle_hot_attribute (tree *node, tree name, tree ARG_UNUSED (args), |
1114 | int ARG_UNUSED (flags), bool *no_add_attrs) |
1115 | { |
1116 | if (TREE_CODE (*node) == FUNCTION_DECL |
1117 | || TREE_CODE (*node) == LABEL_DECL) |
1118 | { |
1119 | /* Attribute hot processing is done later with lookup_attribute. */ |
1120 | } |
1121 | else if ((TREE_CODE (*node) == RECORD_TYPE |
1122 | || TREE_CODE (*node) == UNION_TYPE) |
1123 | && c_dialect_cxx () |
1124 | && (flags & (int) ATTR_FLAG_TYPE_IN_PLACE)) |
1125 | { |
1126 | /* Check conflict here as decl_attributes will otherwise only catch |
1127 | it late at the function when the attribute is used on a class. */ |
1128 | tree cold_attr = lookup_attribute (attr_name: "cold" , TYPE_ATTRIBUTES (*node)); |
1129 | if (cold_attr) |
1130 | { |
1131 | warning (OPT_Wattributes, "ignoring attribute %qE because it " |
1132 | "conflicts with attribute %qs" , name, "cold" ); |
1133 | *no_add_attrs = true; |
1134 | } |
1135 | } |
1136 | else if (flags & ((int) ATTR_FLAG_FUNCTION_NEXT |
1137 | | (int) ATTR_FLAG_DECL_NEXT)) |
1138 | { |
1139 | /* Avoid applying the attribute to a function return type when |
1140 | used as: void __attribute ((hot)) foo (void). It will be |
1141 | passed to the function. */ |
1142 | *no_add_attrs = true; |
1143 | } |
1144 | else |
1145 | { |
1146 | warning (OPT_Wattributes, "%qE attribute ignored" , name); |
1147 | *no_add_attrs = true; |
1148 | } |
1149 | |
1150 | return NULL_TREE; |
1151 | } |
1152 | |
1153 | /* Handle a "cold" and attribute; arguments as in |
1154 | struct attribute_spec.handler. */ |
1155 | |
1156 | static tree |
1157 | handle_cold_attribute (tree *node, tree name, tree ARG_UNUSED (args), |
1158 | int ARG_UNUSED (flags), bool *no_add_attrs) |
1159 | { |
1160 | if (TREE_CODE (*node) == FUNCTION_DECL |
1161 | || TREE_CODE (*node) == LABEL_DECL) |
1162 | { |
1163 | /* Attribute cold processing is done later with lookup_attribute. */ |
1164 | } |
1165 | else if ((TREE_CODE (*node) == RECORD_TYPE |
1166 | || TREE_CODE (*node) == UNION_TYPE) |
1167 | && c_dialect_cxx () |
1168 | && (flags & (int) ATTR_FLAG_TYPE_IN_PLACE)) |
1169 | { |
1170 | /* Check conflict here as decl_attributes will otherwise only catch |
1171 | it late at the function when the attribute is used on a class. */ |
1172 | tree hot_attr = lookup_attribute (attr_name: "hot" , TYPE_ATTRIBUTES (*node)); |
1173 | if (hot_attr) |
1174 | { |
1175 | warning (OPT_Wattributes, "ignoring attribute %qE because it " |
1176 | "conflicts with attribute %qs" , name, "hot" ); |
1177 | *no_add_attrs = true; |
1178 | } |
1179 | } |
1180 | else if (flags & ((int) ATTR_FLAG_FUNCTION_NEXT |
1181 | | (int) ATTR_FLAG_DECL_NEXT)) |
1182 | { |
1183 | /* Avoid applying the attribute to a function return type when |
1184 | used as: void __attribute ((cold)) foo (void). It will be |
1185 | passed to the function. */ |
1186 | *no_add_attrs = true; |
1187 | } |
1188 | else |
1189 | { |
1190 | warning (OPT_Wattributes, "%qE attribute ignored" , name); |
1191 | *no_add_attrs = true; |
1192 | } |
1193 | |
1194 | return NULL_TREE; |
1195 | } |
1196 | |
1197 | /* Add FLAGS for a function NODE to no_sanitize_flags in DECL_ATTRIBUTES. */ |
1198 | |
1199 | void |
1200 | add_no_sanitize_value (tree node, unsigned int flags) |
1201 | { |
1202 | tree attr = lookup_attribute (attr_name: "no_sanitize" , DECL_ATTRIBUTES (node)); |
1203 | if (attr) |
1204 | { |
1205 | unsigned int old_value = tree_to_uhwi (TREE_VALUE (attr)); |
1206 | flags |= old_value; |
1207 | |
1208 | if (flags == old_value) |
1209 | return; |
1210 | |
1211 | TREE_VALUE (attr) = build_int_cst (unsigned_type_node, flags); |
1212 | } |
1213 | else |
1214 | DECL_ATTRIBUTES (node) |
1215 | = tree_cons (get_identifier ("no_sanitize" ), |
1216 | build_int_cst (unsigned_type_node, flags), |
1217 | DECL_ATTRIBUTES (node)); |
1218 | } |
1219 | |
1220 | /* Handle a "no_sanitize" attribute; arguments as in |
1221 | struct attribute_spec.handler. */ |
1222 | |
1223 | static tree |
1224 | handle_no_sanitize_attribute (tree *node, tree name, tree args, int, |
1225 | bool *no_add_attrs) |
1226 | { |
1227 | unsigned int flags = 0; |
1228 | *no_add_attrs = true; |
1229 | if (TREE_CODE (*node) != FUNCTION_DECL) |
1230 | { |
1231 | warning (OPT_Wattributes, "%qE attribute ignored" , name); |
1232 | return NULL_TREE; |
1233 | } |
1234 | |
1235 | for (; args; args = TREE_CHAIN (args)) |
1236 | { |
1237 | tree id = TREE_VALUE (args); |
1238 | if (TREE_CODE (id) != STRING_CST) |
1239 | { |
1240 | error ("%qE argument not a string" , name); |
1241 | return NULL_TREE; |
1242 | } |
1243 | |
1244 | char *string = ASTRDUP (TREE_STRING_POINTER (id)); |
1245 | flags |= parse_no_sanitize_attribute (value: string); |
1246 | } |
1247 | |
1248 | add_no_sanitize_value (node: *node, flags); |
1249 | |
1250 | return NULL_TREE; |
1251 | } |
1252 | |
1253 | /* Handle a "no_sanitize_address" attribute; arguments as in |
1254 | struct attribute_spec.handler. */ |
1255 | |
1256 | static tree |
1257 | handle_no_sanitize_address_attribute (tree *node, tree name, tree, int, |
1258 | bool *no_add_attrs) |
1259 | { |
1260 | *no_add_attrs = true; |
1261 | if (TREE_CODE (*node) != FUNCTION_DECL) |
1262 | warning (OPT_Wattributes, "%qE attribute ignored" , name); |
1263 | else |
1264 | add_no_sanitize_value (node: *node, flags: SANITIZE_ADDRESS); |
1265 | |
1266 | return NULL_TREE; |
1267 | } |
1268 | |
1269 | /* Handle a "no_sanitize_thread" attribute; arguments as in |
1270 | struct attribute_spec.handler. */ |
1271 | |
1272 | static tree |
1273 | handle_no_sanitize_thread_attribute (tree *node, tree name, tree, int, |
1274 | bool *no_add_attrs) |
1275 | { |
1276 | *no_add_attrs = true; |
1277 | if (TREE_CODE (*node) != FUNCTION_DECL) |
1278 | warning (OPT_Wattributes, "%qE attribute ignored" , name); |
1279 | else |
1280 | add_no_sanitize_value (node: *node, flags: SANITIZE_THREAD); |
1281 | |
1282 | return NULL_TREE; |
1283 | } |
1284 | |
1285 | |
1286 | /* Handle a "no_address_safety_analysis" attribute; arguments as in |
1287 | struct attribute_spec.handler. */ |
1288 | |
1289 | static tree |
1290 | handle_no_address_safety_analysis_attribute (tree *node, tree name, tree, int, |
1291 | bool *no_add_attrs) |
1292 | { |
1293 | *no_add_attrs = true; |
1294 | if (TREE_CODE (*node) != FUNCTION_DECL) |
1295 | warning (OPT_Wattributes, "%qE attribute ignored" , name); |
1296 | else |
1297 | add_no_sanitize_value (node: *node, flags: SANITIZE_ADDRESS); |
1298 | |
1299 | return NULL_TREE; |
1300 | } |
1301 | |
1302 | /* Handle a "no_sanitize_undefined" attribute; arguments as in |
1303 | struct attribute_spec.handler. */ |
1304 | |
1305 | static tree |
1306 | handle_no_sanitize_undefined_attribute (tree *node, tree name, tree, int, |
1307 | bool *no_add_attrs) |
1308 | { |
1309 | *no_add_attrs = true; |
1310 | if (TREE_CODE (*node) != FUNCTION_DECL) |
1311 | warning (OPT_Wattributes, "%qE attribute ignored" , name); |
1312 | else |
1313 | add_no_sanitize_value (node: *node, |
1314 | flags: SANITIZE_UNDEFINED | SANITIZE_UNDEFINED_NONDEFAULT); |
1315 | |
1316 | return NULL_TREE; |
1317 | } |
1318 | |
1319 | /* Handle a "no_sanitize_coverage" attribute; arguments as in |
1320 | struct attribute_spec.handler. */ |
1321 | |
1322 | static tree |
1323 | handle_no_sanitize_coverage_attribute (tree *node, tree name, tree, int, |
1324 | bool *no_add_attrs) |
1325 | { |
1326 | if (TREE_CODE (*node) != FUNCTION_DECL) |
1327 | { |
1328 | warning (OPT_Wattributes, "%qE attribute ignored" , name); |
1329 | *no_add_attrs = true; |
1330 | } |
1331 | |
1332 | return NULL_TREE; |
1333 | } |
1334 | |
1335 | /* Handle an "asan odr indicator" attribute; arguments as in |
1336 | struct attribute_spec.handler. */ |
1337 | |
1338 | static tree |
1339 | handle_asan_odr_indicator_attribute (tree *, tree, tree, int, bool *) |
1340 | { |
1341 | return NULL_TREE; |
1342 | } |
1343 | |
1344 | /* Handle a "stack_protect" attribute; arguments as in |
1345 | struct attribute_spec.handler. */ |
1346 | |
1347 | static tree |
1348 | handle_stack_protect_attribute (tree *node, tree name, tree, int, |
1349 | bool *no_add_attrs) |
1350 | { |
1351 | if (TREE_CODE (*node) != FUNCTION_DECL) |
1352 | { |
1353 | warning (OPT_Wattributes, "%qE attribute ignored" , name); |
1354 | *no_add_attrs = true; |
1355 | } |
1356 | |
1357 | return NULL_TREE; |
1358 | } |
1359 | |
1360 | /* Handle a "no_stack_protector" attribute; arguments as in |
1361 | struct attribute_spec.handler. */ |
1362 | |
1363 | static tree |
1364 | handle_no_stack_protector_function_attribute (tree *node, tree name, tree, |
1365 | int, bool *no_add_attrs) |
1366 | { |
1367 | if (TREE_CODE (*node) != FUNCTION_DECL) |
1368 | { |
1369 | warning (OPT_Wattributes, "%qE attribute ignored" , name); |
1370 | *no_add_attrs = true; |
1371 | } |
1372 | |
1373 | return NULL_TREE; |
1374 | } |
1375 | |
1376 | /* Handle a "noipa" attribute; arguments as in |
1377 | struct attribute_spec.handler. */ |
1378 | |
1379 | static tree |
1380 | handle_noipa_attribute (tree *node, tree name, tree, int, bool *no_add_attrs) |
1381 | { |
1382 | if (TREE_CODE (*node) != FUNCTION_DECL) |
1383 | { |
1384 | warning (OPT_Wattributes, "%qE attribute ignored" , name); |
1385 | *no_add_attrs = true; |
1386 | } |
1387 | |
1388 | return NULL_TREE; |
1389 | } |
1390 | |
1391 | /* Handle a "noinline" attribute; arguments as in |
1392 | struct attribute_spec.handler. */ |
1393 | |
1394 | static tree |
1395 | handle_noinline_attribute (tree *node, tree name, |
1396 | tree ARG_UNUSED (args), |
1397 | int ARG_UNUSED (flags), bool *no_add_attrs) |
1398 | { |
1399 | if (TREE_CODE (*node) == FUNCTION_DECL) |
1400 | { |
1401 | if (lookup_attribute (attr_name: "always_inline" , DECL_ATTRIBUTES (*node))) |
1402 | { |
1403 | warning (OPT_Wattributes, "%qE attribute ignored due to conflict " |
1404 | "with attribute %qs" , name, "always_inline" ); |
1405 | *no_add_attrs = true; |
1406 | } |
1407 | else |
1408 | DECL_UNINLINABLE (*node) = 1; |
1409 | } |
1410 | else |
1411 | { |
1412 | warning (OPT_Wattributes, "%qE attribute ignored" , name); |
1413 | *no_add_attrs = true; |
1414 | } |
1415 | |
1416 | return NULL_TREE; |
1417 | } |
1418 | |
1419 | /* Handle a "noclone" attribute; arguments as in |
1420 | struct attribute_spec.handler. */ |
1421 | |
1422 | static tree |
1423 | handle_noclone_attribute (tree *node, tree name, |
1424 | tree ARG_UNUSED (args), |
1425 | int ARG_UNUSED (flags), bool *no_add_attrs) |
1426 | { |
1427 | if (TREE_CODE (*node) != FUNCTION_DECL) |
1428 | { |
1429 | warning (OPT_Wattributes, "%qE attribute ignored" , name); |
1430 | *no_add_attrs = true; |
1431 | } |
1432 | |
1433 | return NULL_TREE; |
1434 | } |
1435 | |
1436 | /* Handle a "nocf_check" attribute; arguments as in |
1437 | struct attribute_spec.handler. */ |
1438 | |
1439 | static tree |
1440 | handle_nocf_check_attribute (tree *node, tree name, |
1441 | tree ARG_UNUSED (args), |
1442 | int ARG_UNUSED (flags), bool *no_add_attrs) |
1443 | { |
1444 | if (TREE_CODE (*node) != FUNCTION_TYPE |
1445 | && TREE_CODE (*node) != METHOD_TYPE) |
1446 | { |
1447 | warning (OPT_Wattributes, "%qE attribute ignored" , name); |
1448 | *no_add_attrs = true; |
1449 | } |
1450 | else if (!(flag_cf_protection & CF_BRANCH)) |
1451 | { |
1452 | warning (OPT_Wattributes, "%qE attribute ignored. Use " |
1453 | "%<-fcf-protection%> option to enable it" , |
1454 | name); |
1455 | *no_add_attrs = true; |
1456 | } |
1457 | |
1458 | return NULL_TREE; |
1459 | } |
1460 | |
1461 | /* Handle a "no_icf" attribute; arguments as in |
1462 | struct attribute_spec.handler. */ |
1463 | |
1464 | static tree |
1465 | handle_noicf_attribute (tree *node, tree name, |
1466 | tree ARG_UNUSED (args), |
1467 | int ARG_UNUSED (flags), bool *no_add_attrs) |
1468 | { |
1469 | if (TREE_CODE (*node) != FUNCTION_DECL) |
1470 | { |
1471 | warning (OPT_Wattributes, "%qE attribute ignored" , name); |
1472 | *no_add_attrs = true; |
1473 | } |
1474 | |
1475 | return NULL_TREE; |
1476 | } |
1477 | |
1478 | |
1479 | /* Handle a "always_inline" attribute; arguments as in |
1480 | struct attribute_spec.handler. */ |
1481 | |
1482 | static tree |
1483 | handle_always_inline_attribute (tree *node, tree name, |
1484 | tree ARG_UNUSED (args), |
1485 | int ARG_UNUSED (flags), |
1486 | bool *no_add_attrs) |
1487 | { |
1488 | if (TREE_CODE (*node) == FUNCTION_DECL) |
1489 | { |
1490 | if (lookup_attribute (attr_name: "noinline" , DECL_ATTRIBUTES (*node))) |
1491 | { |
1492 | warning (OPT_Wattributes, "%qE attribute ignored due to conflict " |
1493 | "with %qs attribute" , name, "noinline" ); |
1494 | *no_add_attrs = true; |
1495 | } |
1496 | else if (lookup_attribute (attr_name: "target_clones" , DECL_ATTRIBUTES (*node))) |
1497 | { |
1498 | warning (OPT_Wattributes, "%qE attribute ignored due to conflict " |
1499 | "with %qs attribute" , name, "target_clones" ); |
1500 | *no_add_attrs = true; |
1501 | } |
1502 | else |
1503 | /* Set the attribute and mark it for disregarding inline |
1504 | limits. */ |
1505 | DECL_DISREGARD_INLINE_LIMITS (*node) = 1; |
1506 | } |
1507 | else |
1508 | { |
1509 | warning (OPT_Wattributes, "%qE attribute ignored" , name); |
1510 | *no_add_attrs = true; |
1511 | } |
1512 | |
1513 | return NULL_TREE; |
1514 | } |
1515 | |
1516 | /* Handle a "gnu_inline" attribute; arguments as in |
1517 | struct attribute_spec.handler. */ |
1518 | |
1519 | static tree |
1520 | handle_gnu_inline_attribute (tree *node, tree name, |
1521 | tree ARG_UNUSED (args), |
1522 | int ARG_UNUSED (flags), |
1523 | bool *no_add_attrs) |
1524 | { |
1525 | if (TREE_CODE (*node) == FUNCTION_DECL && DECL_DECLARED_INLINE_P (*node)) |
1526 | { |
1527 | /* Do nothing else, just set the attribute. We'll get at |
1528 | it later with lookup_attribute. */ |
1529 | } |
1530 | else |
1531 | { |
1532 | warning (OPT_Wattributes, "%qE attribute ignored" , name); |
1533 | *no_add_attrs = true; |
1534 | } |
1535 | |
1536 | return NULL_TREE; |
1537 | } |
1538 | |
1539 | /* Handle a "leaf" attribute; arguments as in |
1540 | struct attribute_spec.handler. */ |
1541 | |
1542 | static tree |
1543 | handle_leaf_attribute (tree *node, tree name, |
1544 | tree ARG_UNUSED (args), |
1545 | int ARG_UNUSED (flags), bool *no_add_attrs) |
1546 | { |
1547 | if (TREE_CODE (*node) != FUNCTION_DECL) |
1548 | { |
1549 | warning (OPT_Wattributes, "%qE attribute ignored" , name); |
1550 | *no_add_attrs = true; |
1551 | } |
1552 | if (!TREE_PUBLIC (*node)) |
1553 | { |
1554 | warning (OPT_Wattributes, "%qE attribute has no effect on unit local " |
1555 | "functions" , name); |
1556 | *no_add_attrs = true; |
1557 | } |
1558 | |
1559 | return NULL_TREE; |
1560 | } |
1561 | |
1562 | /* Handle an "artificial" attribute; arguments as in |
1563 | struct attribute_spec.handler. */ |
1564 | |
1565 | static tree |
1566 | handle_artificial_attribute (tree *node, tree name, |
1567 | tree ARG_UNUSED (args), |
1568 | int ARG_UNUSED (flags), |
1569 | bool *no_add_attrs) |
1570 | { |
1571 | if (TREE_CODE (*node) == FUNCTION_DECL && DECL_DECLARED_INLINE_P (*node)) |
1572 | { |
1573 | /* Do nothing else, just set the attribute. We'll get at |
1574 | it later with lookup_attribute. */ |
1575 | } |
1576 | else |
1577 | { |
1578 | warning (OPT_Wattributes, "%qE attribute ignored" , name); |
1579 | *no_add_attrs = true; |
1580 | } |
1581 | |
1582 | return NULL_TREE; |
1583 | } |
1584 | |
1585 | /* Handle a "flatten" attribute; arguments as in |
1586 | struct attribute_spec.handler. */ |
1587 | |
1588 | static tree |
1589 | handle_flatten_attribute (tree *node, tree name, |
1590 | tree args ATTRIBUTE_UNUSED, |
1591 | int flags ATTRIBUTE_UNUSED, bool *no_add_attrs) |
1592 | { |
1593 | if (TREE_CODE (*node) == FUNCTION_DECL) |
1594 | /* Do nothing else, just set the attribute. We'll get at |
1595 | it later with lookup_attribute. */ |
1596 | ; |
1597 | else |
1598 | { |
1599 | warning (OPT_Wattributes, "%qE attribute ignored" , name); |
1600 | *no_add_attrs = true; |
1601 | } |
1602 | |
1603 | return NULL_TREE; |
1604 | } |
1605 | |
1606 | /* Handle a "warning" or "error" attribute; arguments as in |
1607 | struct attribute_spec.handler. */ |
1608 | |
1609 | static tree |
1610 | handle_error_attribute (tree *node, tree name, tree args, |
1611 | int ARG_UNUSED (flags), bool *no_add_attrs) |
1612 | { |
1613 | if (TREE_CODE (*node) == FUNCTION_DECL |
1614 | && TREE_CODE (TREE_VALUE (args)) == STRING_CST) |
1615 | /* Do nothing else, just set the attribute. We'll get at |
1616 | it later with lookup_attribute. */ |
1617 | ; |
1618 | else |
1619 | { |
1620 | warning (OPT_Wattributes, "%qE attribute ignored" , name); |
1621 | *no_add_attrs = true; |
1622 | } |
1623 | |
1624 | return NULL_TREE; |
1625 | } |
1626 | |
1627 | /* Handle a "used" attribute; arguments as in |
1628 | struct attribute_spec.handler. */ |
1629 | |
1630 | static tree |
1631 | handle_used_attribute (tree *pnode, tree name, tree ARG_UNUSED (args), |
1632 | int ARG_UNUSED (flags), bool *no_add_attrs) |
1633 | { |
1634 | tree node = *pnode; |
1635 | |
1636 | if (TREE_CODE (node) == FUNCTION_DECL |
1637 | || (VAR_P (node) && TREE_STATIC (node)) |
1638 | || (TREE_CODE (node) == TYPE_DECL)) |
1639 | { |
1640 | TREE_USED (node) = 1; |
1641 | DECL_PRESERVE_P (node) = 1; |
1642 | if (VAR_P (node)) |
1643 | DECL_READ_P (node) = 1; |
1644 | } |
1645 | else |
1646 | { |
1647 | warning (OPT_Wattributes, "%qE attribute ignored" , name); |
1648 | *no_add_attrs = true; |
1649 | } |
1650 | |
1651 | return NULL_TREE; |
1652 | } |
1653 | |
1654 | /* Handle a "unused" attribute; arguments as in |
1655 | struct attribute_spec.handler. */ |
1656 | |
1657 | tree |
1658 | handle_unused_attribute (tree *node, tree name, tree ARG_UNUSED (args), |
1659 | int flags, bool *no_add_attrs) |
1660 | { |
1661 | if (DECL_P (*node)) |
1662 | { |
1663 | tree decl = *node; |
1664 | |
1665 | if (TREE_CODE (decl) == PARM_DECL |
1666 | || VAR_OR_FUNCTION_DECL_P (decl) |
1667 | || TREE_CODE (decl) == LABEL_DECL |
1668 | || TREE_CODE (decl) == CONST_DECL |
1669 | || TREE_CODE (decl) == FIELD_DECL |
1670 | || TREE_CODE (decl) == TYPE_DECL) |
1671 | { |
1672 | TREE_USED (decl) = 1; |
1673 | if (VAR_P (decl) || TREE_CODE (decl) == PARM_DECL) |
1674 | DECL_READ_P (decl) = 1; |
1675 | } |
1676 | else |
1677 | { |
1678 | warning (OPT_Wattributes, "%qE attribute ignored" , name); |
1679 | *no_add_attrs = true; |
1680 | } |
1681 | } |
1682 | else |
1683 | { |
1684 | if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE)) |
1685 | *node = build_variant_type_copy (*node); |
1686 | TREE_USED (*node) = 1; |
1687 | } |
1688 | |
1689 | return NULL_TREE; |
1690 | } |
1691 | |
1692 | /* Handle a "retain" attribute; arguments as in |
1693 | struct attribute_spec.handler. */ |
1694 | |
1695 | static tree |
1696 | handle_retain_attribute (tree *pnode, tree name, tree ARG_UNUSED (args), |
1697 | int ARG_UNUSED (flags), bool *no_add_attrs) |
1698 | { |
1699 | tree node = *pnode; |
1700 | |
1701 | if (SUPPORTS_SHF_GNU_RETAIN |
1702 | && (TREE_CODE (node) == FUNCTION_DECL |
1703 | || (VAR_P (node) && TREE_STATIC (node)))) |
1704 | ; |
1705 | else |
1706 | { |
1707 | warning (OPT_Wattributes, "%qE attribute ignored" , name); |
1708 | *no_add_attrs = true; |
1709 | } |
1710 | |
1711 | return NULL_TREE; |
1712 | } |
1713 | |
1714 | /* Handle an "uninitialized" attribute; arguments as in |
1715 | struct attribute_spec.handler. */ |
1716 | |
1717 | static tree |
1718 | handle_uninitialized_attribute (tree *node, tree name, tree ARG_UNUSED (args), |
1719 | int ARG_UNUSED (flags), bool *no_add_attrs) |
1720 | { |
1721 | tree decl = *node; |
1722 | if (!VAR_P (decl)) |
1723 | { |
1724 | warning (OPT_Wattributes, "%qE attribute ignored because %qD " |
1725 | "is not a variable" , name, decl); |
1726 | *no_add_attrs = true; |
1727 | } |
1728 | else if (TREE_STATIC (decl) || DECL_EXTERNAL (decl)) |
1729 | { |
1730 | warning (OPT_Wattributes, "%qE attribute ignored because %qD " |
1731 | "is not a local variable" , name, decl); |
1732 | *no_add_attrs = true; |
1733 | } |
1734 | |
1735 | return NULL_TREE; |
1736 | } |
1737 | |
1738 | /* Handle a "externally_visible" attribute; arguments as in |
1739 | struct attribute_spec.handler. */ |
1740 | |
1741 | static tree |
1742 | handle_externally_visible_attribute (tree *pnode, tree name, |
1743 | tree ARG_UNUSED (args), |
1744 | int ARG_UNUSED (flags), |
1745 | bool *no_add_attrs) |
1746 | { |
1747 | tree node = *pnode; |
1748 | |
1749 | if (VAR_OR_FUNCTION_DECL_P (node)) |
1750 | { |
1751 | if ((!TREE_STATIC (node) && TREE_CODE (node) != FUNCTION_DECL |
1752 | && !DECL_EXTERNAL (node)) || !TREE_PUBLIC (node)) |
1753 | { |
1754 | warning (OPT_Wattributes, |
1755 | "%qE attribute have effect only on public objects" , name); |
1756 | *no_add_attrs = true; |
1757 | } |
1758 | } |
1759 | else |
1760 | { |
1761 | warning (OPT_Wattributes, "%qE attribute ignored" , name); |
1762 | *no_add_attrs = true; |
1763 | } |
1764 | |
1765 | return NULL_TREE; |
1766 | } |
1767 | |
1768 | /* Handle the "no_reorder" attribute. Arguments as in |
1769 | struct attribute_spec.handler. */ |
1770 | |
1771 | static tree |
1772 | handle_no_reorder_attribute (tree *pnode, |
1773 | tree name, |
1774 | tree, |
1775 | int, |
1776 | bool *no_add_attrs) |
1777 | { |
1778 | tree node = *pnode; |
1779 | |
1780 | if (!VAR_OR_FUNCTION_DECL_P (node) |
1781 | && !(TREE_STATIC (node) || DECL_EXTERNAL (node))) |
1782 | { |
1783 | warning (OPT_Wattributes, |
1784 | "%qE attribute only affects top level objects" , |
1785 | name); |
1786 | *no_add_attrs = true; |
1787 | } |
1788 | |
1789 | return NULL_TREE; |
1790 | } |
1791 | |
1792 | /* Handle a "const" attribute; arguments as in |
1793 | struct attribute_spec.handler. */ |
1794 | |
1795 | static tree |
1796 | handle_const_attribute (tree *node, tree name, tree ARG_UNUSED (args), |
1797 | int flags, bool *no_add_attrs) |
1798 | { |
1799 | tree type = TREE_TYPE (*node); |
1800 | |
1801 | /* See FIXME comment on noreturn in c_common_attribute_table. */ |
1802 | if (TREE_CODE (*node) == FUNCTION_DECL) |
1803 | TREE_READONLY (*node) = 1; |
1804 | else if (TREE_CODE (type) == POINTER_TYPE |
1805 | && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE) |
1806 | TREE_TYPE (*node) |
1807 | = (build_qualified_type |
1808 | (build_pointer_type |
1809 | (build_type_variant (TREE_TYPE (type), 1, |
1810 | TREE_THIS_VOLATILE (TREE_TYPE (type)))), |
1811 | TYPE_QUALS (type))); |
1812 | else |
1813 | { |
1814 | warning (OPT_Wattributes, "%qE attribute ignored" , name); |
1815 | *no_add_attrs = true; |
1816 | } |
1817 | |
1818 | /* void __builtin_unreachable(void) is const. Accept other such |
1819 | built-ins but warn on user-defined functions that return void. */ |
1820 | if (!(flags & ATTR_FLAG_BUILT_IN) |
1821 | && TREE_CODE (*node) == FUNCTION_DECL |
1822 | && VOID_TYPE_P (TREE_TYPE (type))) |
1823 | warning (OPT_Wattributes, "%qE attribute on function " |
1824 | "returning %<void%>" , name); |
1825 | |
1826 | return NULL_TREE; |
1827 | } |
1828 | |
1829 | /* Handle a "scalar_storage_order" attribute; arguments as in |
1830 | struct attribute_spec.handler. */ |
1831 | |
1832 | static tree |
1833 | handle_scalar_storage_order_attribute (tree *node, tree name, tree args, |
1834 | int flags, bool *no_add_attrs) |
1835 | { |
1836 | tree id = TREE_VALUE (args); |
1837 | tree type; |
1838 | |
1839 | if (TREE_CODE (*node) == TYPE_DECL |
1840 | && ! (flags & ATTR_FLAG_CXX11)) |
1841 | node = &TREE_TYPE (*node); |
1842 | type = *node; |
1843 | |
1844 | if (BYTES_BIG_ENDIAN != WORDS_BIG_ENDIAN) |
1845 | { |
1846 | error ("%qE attribute is not supported because endianness is not uniform" , |
1847 | name); |
1848 | return NULL_TREE; |
1849 | } |
1850 | |
1851 | if (RECORD_OR_UNION_TYPE_P (type) && !c_dialect_cxx ()) |
1852 | { |
1853 | bool reverse = false; |
1854 | |
1855 | if (TREE_CODE (id) == STRING_CST |
1856 | && strcmp (TREE_STRING_POINTER (id), s2: "big-endian" ) == 0) |
1857 | reverse = !BYTES_BIG_ENDIAN; |
1858 | else if (TREE_CODE (id) == STRING_CST |
1859 | && strcmp (TREE_STRING_POINTER (id), s2: "little-endian" ) == 0) |
1860 | reverse = BYTES_BIG_ENDIAN; |
1861 | else |
1862 | { |
1863 | error ("attribute %qE argument must be one of %qs or %qs" , |
1864 | name, "big-endian" , "little-endian" ); |
1865 | return NULL_TREE; |
1866 | } |
1867 | |
1868 | if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE)) |
1869 | { |
1870 | if (reverse) |
1871 | /* A type variant isn't good enough, since we don't want a cast |
1872 | to such a type to be removed as a no-op. */ |
1873 | *node = type = build_duplicate_type (type); |
1874 | } |
1875 | |
1876 | TYPE_REVERSE_STORAGE_ORDER (type) = reverse; |
1877 | return NULL_TREE; |
1878 | } |
1879 | |
1880 | warning (OPT_Wattributes, "%qE attribute ignored" , name); |
1881 | *no_add_attrs = true; |
1882 | return NULL_TREE; |
1883 | } |
1884 | |
1885 | /* Handle a "transparent_union" attribute; arguments as in |
1886 | struct attribute_spec.handler. */ |
1887 | |
1888 | static tree |
1889 | handle_transparent_union_attribute (tree *node, tree name, |
1890 | tree ARG_UNUSED (args), int flags, |
1891 | bool *no_add_attrs) |
1892 | { |
1893 | tree type; |
1894 | |
1895 | *no_add_attrs = true; |
1896 | |
1897 | if (TREE_CODE (*node) == TYPE_DECL |
1898 | && ! (flags & ATTR_FLAG_CXX11)) |
1899 | node = &TREE_TYPE (*node); |
1900 | type = *node; |
1901 | |
1902 | if (TREE_CODE (type) == UNION_TYPE) |
1903 | { |
1904 | /* Make sure that the first field will work for a transparent union. |
1905 | If the type isn't complete yet, leave the check to the code in |
1906 | finish_struct. */ |
1907 | if (TYPE_SIZE (type)) |
1908 | { |
1909 | tree first = first_field (type); |
1910 | if (first == NULL_TREE |
1911 | || DECL_ARTIFICIAL (first) |
1912 | || TYPE_MODE (type) != DECL_MODE (first)) |
1913 | goto ignored; |
1914 | } |
1915 | |
1916 | if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE)) |
1917 | { |
1918 | /* If the type isn't complete yet, setting the flag |
1919 | on a variant wouldn't ever be checked. */ |
1920 | if (!TYPE_SIZE (type)) |
1921 | goto ignored; |
1922 | |
1923 | /* build_duplicate_type doesn't work for C++. */ |
1924 | if (c_dialect_cxx ()) |
1925 | goto ignored; |
1926 | |
1927 | /* A type variant isn't good enough, since we don't want a cast |
1928 | to such a type to be removed as a no-op. */ |
1929 | *node = type = build_duplicate_type (type); |
1930 | } |
1931 | |
1932 | for (tree t = TYPE_MAIN_VARIANT (type); t; t = TYPE_NEXT_VARIANT (t)) |
1933 | TYPE_TRANSPARENT_AGGR (t) = 1; |
1934 | return NULL_TREE; |
1935 | } |
1936 | |
1937 | ignored: |
1938 | warning (OPT_Wattributes, "%qE attribute ignored" , name); |
1939 | return NULL_TREE; |
1940 | } |
1941 | |
1942 | /* Subroutine of handle_{con,de}structor_attribute. Evaluate ARGS to |
1943 | get the requested priority for a constructor or destructor, |
1944 | possibly issuing diagnostics for invalid or reserved |
1945 | priorities. */ |
1946 | |
1947 | static priority_type |
1948 | get_priority (tree args, bool is_destructor) |
1949 | { |
1950 | HOST_WIDE_INT pri; |
1951 | tree arg; |
1952 | |
1953 | if (!args) |
1954 | return DEFAULT_INIT_PRIORITY; |
1955 | |
1956 | if (!SUPPORTS_INIT_PRIORITY) |
1957 | { |
1958 | if (is_destructor) |
1959 | error ("destructor priorities are not supported" ); |
1960 | else |
1961 | error ("constructor priorities are not supported" ); |
1962 | return DEFAULT_INIT_PRIORITY; |
1963 | } |
1964 | |
1965 | arg = TREE_VALUE (args); |
1966 | if (TREE_CODE (arg) == IDENTIFIER_NODE || TREE_CODE (arg) == FUNCTION_DECL) |
1967 | goto invalid; |
1968 | if (arg == error_mark_node) |
1969 | return DEFAULT_INIT_PRIORITY; |
1970 | arg = default_conversion (arg); |
1971 | if (!tree_fits_shwi_p (arg) |
1972 | || !INTEGRAL_TYPE_P (TREE_TYPE (arg))) |
1973 | goto invalid; |
1974 | |
1975 | pri = tree_to_shwi (arg); |
1976 | if (pri < 0 || pri > MAX_INIT_PRIORITY) |
1977 | goto invalid; |
1978 | |
1979 | if (pri <= MAX_RESERVED_INIT_PRIORITY) |
1980 | { |
1981 | if (is_destructor) |
1982 | warning (OPT_Wprio_ctor_dtor, |
1983 | "destructor priorities from 0 to %d are reserved " |
1984 | "for the implementation" , |
1985 | MAX_RESERVED_INIT_PRIORITY); |
1986 | else |
1987 | warning (OPT_Wprio_ctor_dtor, |
1988 | "constructor priorities from 0 to %d are reserved " |
1989 | "for the implementation" , |
1990 | MAX_RESERVED_INIT_PRIORITY); |
1991 | } |
1992 | return pri; |
1993 | |
1994 | invalid: |
1995 | if (is_destructor) |
1996 | error ("destructor priorities must be integers from 0 to %d inclusive" , |
1997 | MAX_INIT_PRIORITY); |
1998 | else |
1999 | error ("constructor priorities must be integers from 0 to %d inclusive" , |
2000 | MAX_INIT_PRIORITY); |
2001 | return DEFAULT_INIT_PRIORITY; |
2002 | } |
2003 | |
2004 | /* Handle a "constructor" attribute; arguments as in |
2005 | struct attribute_spec.handler. */ |
2006 | |
2007 | static tree |
2008 | handle_constructor_attribute (tree *node, tree name, tree args, |
2009 | int ARG_UNUSED (flags), |
2010 | bool *no_add_attrs) |
2011 | { |
2012 | tree decl = *node; |
2013 | tree type = TREE_TYPE (decl); |
2014 | |
2015 | if (TREE_CODE (decl) == FUNCTION_DECL |
2016 | && TREE_CODE (type) == FUNCTION_TYPE |
2017 | && decl_function_context (decl) == 0) |
2018 | { |
2019 | priority_type priority; |
2020 | DECL_STATIC_CONSTRUCTOR (decl) = 1; |
2021 | priority = get_priority (args, /*is_destructor=*/false); |
2022 | SET_DECL_INIT_PRIORITY (decl, priority); |
2023 | TREE_USED (decl) = 1; |
2024 | } |
2025 | else |
2026 | { |
2027 | warning (OPT_Wattributes, "%qE attribute ignored" , name); |
2028 | *no_add_attrs = true; |
2029 | } |
2030 | |
2031 | return NULL_TREE; |
2032 | } |
2033 | |
2034 | /* Handle a "destructor" attribute; arguments as in |
2035 | struct attribute_spec.handler. */ |
2036 | |
2037 | static tree |
2038 | handle_destructor_attribute (tree *node, tree name, tree args, |
2039 | int ARG_UNUSED (flags), |
2040 | bool *no_add_attrs) |
2041 | { |
2042 | tree decl = *node; |
2043 | tree type = TREE_TYPE (decl); |
2044 | |
2045 | if (TREE_CODE (decl) == FUNCTION_DECL |
2046 | && TREE_CODE (type) == FUNCTION_TYPE |
2047 | && decl_function_context (decl) == 0) |
2048 | { |
2049 | priority_type priority; |
2050 | DECL_STATIC_DESTRUCTOR (decl) = 1; |
2051 | priority = get_priority (args, /*is_destructor=*/true); |
2052 | SET_DECL_FINI_PRIORITY (decl, priority); |
2053 | TREE_USED (decl) = 1; |
2054 | } |
2055 | else |
2056 | { |
2057 | warning (OPT_Wattributes, "%qE attribute ignored" , name); |
2058 | *no_add_attrs = true; |
2059 | } |
2060 | |
2061 | return NULL_TREE; |
2062 | } |
2063 | |
2064 | /* Nonzero if the mode is a valid vector mode for this architecture. |
2065 | This returns nonzero even if there is no hardware support for the |
2066 | vector mode, but we can emulate with narrower modes. */ |
2067 | |
2068 | static bool |
2069 | vector_mode_valid_p (machine_mode mode) |
2070 | { |
2071 | enum mode_class mclass = GET_MODE_CLASS (mode); |
2072 | |
2073 | /* Doh! What's going on? */ |
2074 | if (mclass != MODE_VECTOR_INT |
2075 | && mclass != MODE_VECTOR_FLOAT |
2076 | && mclass != MODE_VECTOR_FRACT |
2077 | && mclass != MODE_VECTOR_UFRACT |
2078 | && mclass != MODE_VECTOR_ACCUM |
2079 | && mclass != MODE_VECTOR_UACCUM) |
2080 | return false; |
2081 | |
2082 | /* Hardware support. Woo hoo! */ |
2083 | if (targetm.vector_mode_supported_p (mode)) |
2084 | return true; |
2085 | |
2086 | /* We should probably return 1 if requesting V4DI and we have no DI, |
2087 | but we have V2DI, but this is probably very unlikely. */ |
2088 | |
2089 | /* If we have support for the inner mode, we can safely emulate it. |
2090 | We may not have V2DI, but me can emulate with a pair of DIs. */ |
2091 | return targetm.scalar_mode_supported_p (GET_MODE_INNER (mode)); |
2092 | } |
2093 | |
2094 | |
2095 | /* Handle a "mode" attribute; arguments as in |
2096 | struct attribute_spec.handler. */ |
2097 | |
2098 | static tree |
2099 | handle_mode_attribute (tree *node, tree name, tree args, |
2100 | int ARG_UNUSED (flags), bool *no_add_attrs) |
2101 | { |
2102 | tree type = *node; |
2103 | tree ident = TREE_VALUE (args); |
2104 | |
2105 | *no_add_attrs = true; |
2106 | |
2107 | if (TREE_CODE (ident) != IDENTIFIER_NODE) |
2108 | warning (OPT_Wattributes, "%qE attribute ignored" , name); |
2109 | else |
2110 | { |
2111 | int j; |
2112 | const char *p = IDENTIFIER_POINTER (ident); |
2113 | int len = strlen (s: p); |
2114 | machine_mode mode = VOIDmode; |
2115 | tree typefm; |
2116 | bool valid_mode; |
2117 | |
2118 | if (len > 4 && p[0] == '_' && p[1] == '_' |
2119 | && p[len - 1] == '_' && p[len - 2] == '_') |
2120 | { |
2121 | char *newp = (char *) alloca (len - 1); |
2122 | |
2123 | strcpy (dest: newp, src: &p[2]); |
2124 | newp[len - 4] = '\0'; |
2125 | p = newp; |
2126 | } |
2127 | |
2128 | /* Change this type to have a type with the specified mode. |
2129 | First check for the special modes. */ |
2130 | if (!strcmp (s1: p, s2: "byte" )) |
2131 | mode = byte_mode; |
2132 | else if (!strcmp (s1: p, s2: "word" )) |
2133 | mode = word_mode; |
2134 | else if (!strcmp (s1: p, s2: "pointer" )) |
2135 | mode = ptr_mode; |
2136 | else if (!strcmp (s1: p, s2: "libgcc_cmp_return" )) |
2137 | mode = targetm.libgcc_cmp_return_mode (); |
2138 | else if (!strcmp (s1: p, s2: "libgcc_shift_count" )) |
2139 | mode = targetm.libgcc_shift_count_mode (); |
2140 | else if (!strcmp (s1: p, s2: "unwind_word" )) |
2141 | mode = targetm.unwind_word_mode (); |
2142 | else |
2143 | for (j = 0; j < NUM_MACHINE_MODES; j++) |
2144 | if (!strcmp (s1: p, GET_MODE_NAME (j))) |
2145 | { |
2146 | mode = (machine_mode) j; |
2147 | break; |
2148 | } |
2149 | |
2150 | if (mode == VOIDmode) |
2151 | { |
2152 | error ("unknown machine mode %qE" , ident); |
2153 | return NULL_TREE; |
2154 | } |
2155 | |
2156 | /* Allow the target a chance to translate MODE into something supported. |
2157 | See PR86324. */ |
2158 | mode = targetm.translate_mode_attribute (mode); |
2159 | |
2160 | valid_mode = false; |
2161 | switch (GET_MODE_CLASS (mode)) |
2162 | { |
2163 | case MODE_INT: |
2164 | case MODE_PARTIAL_INT: |
2165 | case MODE_FLOAT: |
2166 | case MODE_DECIMAL_FLOAT: |
2167 | case MODE_FRACT: |
2168 | case MODE_UFRACT: |
2169 | case MODE_ACCUM: |
2170 | case MODE_UACCUM: |
2171 | valid_mode |
2172 | = targetm.scalar_mode_supported_p (as_a <scalar_mode> (m: mode)); |
2173 | break; |
2174 | |
2175 | case MODE_COMPLEX_INT: |
2176 | case MODE_COMPLEX_FLOAT: |
2177 | valid_mode = targetm.scalar_mode_supported_p (GET_MODE_INNER (mode)); |
2178 | break; |
2179 | |
2180 | case MODE_VECTOR_INT: |
2181 | case MODE_VECTOR_FLOAT: |
2182 | case MODE_VECTOR_FRACT: |
2183 | case MODE_VECTOR_UFRACT: |
2184 | case MODE_VECTOR_ACCUM: |
2185 | case MODE_VECTOR_UACCUM: |
2186 | warning (OPT_Wattributes, "specifying vector types with " |
2187 | "%<__attribute__ ((mode))%> is deprecated" ); |
2188 | inform (input_location, |
2189 | "use %<__attribute__ ((vector_size))%> instead" ); |
2190 | valid_mode = vector_mode_valid_p (mode); |
2191 | break; |
2192 | |
2193 | default: |
2194 | break; |
2195 | } |
2196 | if (!valid_mode) |
2197 | { |
2198 | error ("unable to emulate %qs" , p); |
2199 | return NULL_TREE; |
2200 | } |
2201 | |
2202 | if (POINTER_TYPE_P (type)) |
2203 | { |
2204 | scalar_int_mode addr_mode; |
2205 | addr_space_t as = TYPE_ADDR_SPACE (TREE_TYPE (type)); |
2206 | tree (*fn)(tree, machine_mode, bool); |
2207 | |
2208 | if (!is_a <scalar_int_mode> (m: mode, result: &addr_mode) |
2209 | || !targetm.addr_space.valid_pointer_mode (addr_mode, as)) |
2210 | { |
2211 | error ("invalid pointer mode %qs" , p); |
2212 | return NULL_TREE; |
2213 | } |
2214 | |
2215 | if (TREE_CODE (type) == POINTER_TYPE) |
2216 | fn = build_pointer_type_for_mode; |
2217 | else |
2218 | fn = build_reference_type_for_mode; |
2219 | typefm = fn (TREE_TYPE (type), addr_mode, false); |
2220 | } |
2221 | else |
2222 | { |
2223 | /* For fixed-point modes, we need to test if the signness of type |
2224 | and the machine mode are consistent. */ |
2225 | if (ALL_FIXED_POINT_MODE_P (mode) |
2226 | && TYPE_UNSIGNED (type) != UNSIGNED_FIXED_POINT_MODE_P (mode)) |
2227 | { |
2228 | error ("signedness of type and machine mode %qs don%'t match" , p); |
2229 | return NULL_TREE; |
2230 | } |
2231 | /* For fixed-point modes, we need to pass saturating info. */ |
2232 | typefm = lang_hooks.types.type_for_mode (mode, |
2233 | ALL_FIXED_POINT_MODE_P (mode) ? TYPE_SATURATING (type) |
2234 | : TYPE_UNSIGNED (type)); |
2235 | } |
2236 | |
2237 | if (typefm == NULL_TREE) |
2238 | { |
2239 | error ("no data type for mode %qs" , p); |
2240 | return NULL_TREE; |
2241 | } |
2242 | else if (TREE_CODE (type) == ENUMERAL_TYPE) |
2243 | { |
2244 | /* For enumeral types, copy the precision from the integer |
2245 | type returned above. If not an INTEGER_TYPE, we can't use |
2246 | this mode for this type. */ |
2247 | if (TREE_CODE (typefm) != INTEGER_TYPE) |
2248 | { |
2249 | error ("cannot use mode %qs for enumerated types" , p); |
2250 | return NULL_TREE; |
2251 | } |
2252 | |
2253 | if (flags & ATTR_FLAG_TYPE_IN_PLACE) |
2254 | { |
2255 | TYPE_PRECISION (type) = TYPE_PRECISION (typefm); |
2256 | typefm = type; |
2257 | } |
2258 | else |
2259 | { |
2260 | /* We cannot build a type variant, as there's code that assumes |
2261 | that TYPE_MAIN_VARIANT has the same mode. This includes the |
2262 | debug generators. Instead, create a subrange type. This |
2263 | results in all of the enumeral values being emitted only once |
2264 | in the original, and the subtype gets them by reference. */ |
2265 | if (TYPE_UNSIGNED (type)) |
2266 | typefm = make_unsigned_type (TYPE_PRECISION (typefm)); |
2267 | else |
2268 | typefm = make_signed_type (TYPE_PRECISION (typefm)); |
2269 | TREE_TYPE (typefm) = type; |
2270 | } |
2271 | *no_add_attrs = false; |
2272 | } |
2273 | else if (VECTOR_MODE_P (mode) |
2274 | ? TREE_CODE (type) != TREE_CODE (TREE_TYPE (typefm)) |
2275 | : TREE_CODE (type) != TREE_CODE (typefm)) |
2276 | { |
2277 | error ("mode %qs applied to inappropriate type" , p); |
2278 | return NULL_TREE; |
2279 | } |
2280 | |
2281 | /* Copy any quals and attributes to the new type. */ |
2282 | *node = build_type_attribute_qual_variant (typefm, TYPE_ATTRIBUTES (type), |
2283 | TYPE_QUALS (type)); |
2284 | if (TYPE_USER_ALIGN (type)) |
2285 | *node = build_aligned_type (*node, TYPE_ALIGN (type)); |
2286 | } |
2287 | |
2288 | return NULL_TREE; |
2289 | } |
2290 | |
2291 | /* Handle a "section" attribute; arguments as in |
2292 | struct attribute_spec.handler. */ |
2293 | |
2294 | static tree |
2295 | handle_section_attribute (tree *node, tree name, tree args, |
2296 | int flags, bool *no_add_attrs) |
2297 | { |
2298 | tree decl = *node; |
2299 | tree res = NULL_TREE; |
2300 | tree argval = TREE_VALUE (args); |
2301 | const char* new_section_name; |
2302 | |
2303 | if (!targetm_common.have_named_sections) |
2304 | { |
2305 | error_at (DECL_SOURCE_LOCATION (*node), |
2306 | "section attributes are not supported for this target" ); |
2307 | goto fail; |
2308 | } |
2309 | |
2310 | if (!VAR_OR_FUNCTION_DECL_P (decl)) |
2311 | { |
2312 | error ("section attribute not allowed for %q+D" , *node); |
2313 | goto fail; |
2314 | } |
2315 | |
2316 | if (TREE_CODE (argval) != STRING_CST) |
2317 | { |
2318 | error ("section attribute argument not a string constant" ); |
2319 | goto fail; |
2320 | } |
2321 | |
2322 | if (VAR_P (decl) |
2323 | && current_function_decl != NULL_TREE |
2324 | && !TREE_STATIC (decl)) |
2325 | { |
2326 | error_at (DECL_SOURCE_LOCATION (decl), |
2327 | "section attribute cannot be specified for local variables" ); |
2328 | goto fail; |
2329 | } |
2330 | |
2331 | new_section_name = TREE_STRING_POINTER (argval); |
2332 | |
2333 | /* The decl may have already been given a section attribute |
2334 | from a previous declaration. Ensure they match. */ |
2335 | if (const char* const old_section_name = DECL_SECTION_NAME (decl)) |
2336 | if (strcmp (s1: old_section_name, s2: new_section_name) != 0) |
2337 | { |
2338 | error ("section of %q+D conflicts with previous declaration" , |
2339 | *node); |
2340 | goto fail; |
2341 | } |
2342 | |
2343 | if (VAR_P (decl) |
2344 | && !targetm.have_tls && targetm.emutls.tmpl_section |
2345 | && DECL_THREAD_LOCAL_P (decl)) |
2346 | { |
2347 | error ("section of %q+D cannot be overridden" , *node); |
2348 | goto fail; |
2349 | } |
2350 | |
2351 | if (!validate_attr_arg (node, name, newarg: argval)) |
2352 | goto fail; |
2353 | |
2354 | res = targetm.handle_generic_attribute (node, name, args, flags, |
2355 | no_add_attrs); |
2356 | |
2357 | /* If the back end confirms the attribute can be added then continue onto |
2358 | final processing. */ |
2359 | if (!(*no_add_attrs)) |
2360 | { |
2361 | set_decl_section_name (decl, new_section_name); |
2362 | return res; |
2363 | } |
2364 | |
2365 | fail: |
2366 | *no_add_attrs = true; |
2367 | return res; |
2368 | } |
2369 | |
2370 | /* Common codes shared by handle_warn_if_not_aligned_attribute and |
2371 | handle_aligned_attribute. */ |
2372 | |
2373 | static tree |
2374 | common_handle_aligned_attribute (tree *node, tree name, tree args, int flags, |
2375 | bool *no_add_attrs, |
2376 | bool warn_if_not_aligned_p) |
2377 | { |
2378 | tree decl = NULL_TREE; |
2379 | tree *type = NULL; |
2380 | bool is_type = false; |
2381 | tree align_expr; |
2382 | |
2383 | /* The last (already pushed) declaration with all validated attributes |
2384 | merged in or the current about-to-be-pushed one if one hasn't been |
2385 | yet. */ |
2386 | tree last_decl = node[1] ? node[1] : *node; |
2387 | |
2388 | if (args) |
2389 | { |
2390 | align_expr = TREE_VALUE (args); |
2391 | if (align_expr && TREE_CODE (align_expr) != IDENTIFIER_NODE |
2392 | && TREE_CODE (align_expr) != FUNCTION_DECL) |
2393 | align_expr = default_conversion (align_expr); |
2394 | } |
2395 | else |
2396 | align_expr = size_int (ATTRIBUTE_ALIGNED_VALUE / BITS_PER_UNIT); |
2397 | |
2398 | if (DECL_P (*node)) |
2399 | { |
2400 | decl = *node; |
2401 | type = &TREE_TYPE (decl); |
2402 | is_type = TREE_CODE (*node) == TYPE_DECL; |
2403 | } |
2404 | else if (TYPE_P (*node)) |
2405 | type = node, is_type = true; |
2406 | |
2407 | /* True to consider invalid alignments greater than MAX_OFILE_ALIGNMENT. */ |
2408 | bool objfile = (TREE_CODE (*node) == FUNCTION_DECL |
2409 | || (VAR_P (*node) && TREE_STATIC (*node))); |
2410 | /* Log2 of specified alignment. */ |
2411 | int pow2align = check_user_alignment (align_expr, objfile, |
2412 | /* warn_zero = */ true); |
2413 | if (pow2align == -1) |
2414 | { |
2415 | *no_add_attrs = true; |
2416 | return NULL_TREE; |
2417 | } |
2418 | |
2419 | /* The alignment in bits corresponding to the specified alignment. */ |
2420 | unsigned bitalign = (1U << pow2align) * BITS_PER_UNIT; |
2421 | |
2422 | /* The alignment of the current declaration and that of the last |
2423 | pushed declaration, determined on demand below. */ |
2424 | unsigned curalign = 0; |
2425 | unsigned lastalign = 0; |
2426 | |
2427 | /* True when SET_DECL_ALIGN() should be called for the decl when |
2428 | *NO_ADD_ATTRS is false. */ |
2429 | bool set_align = true; |
2430 | if (is_type) |
2431 | { |
2432 | if ((flags & (int) ATTR_FLAG_TYPE_IN_PLACE)) |
2433 | /* OK, modify the type in place. */; |
2434 | /* If we have a TYPE_DECL, then copy the type, so that we |
2435 | don't accidentally modify a builtin type. See pushdecl. */ |
2436 | else if (decl && TREE_TYPE (decl) != error_mark_node |
2437 | && DECL_ORIGINAL_TYPE (decl) == NULL_TREE) |
2438 | { |
2439 | tree tt = TREE_TYPE (decl); |
2440 | *type = build_variant_type_copy (*type); |
2441 | DECL_ORIGINAL_TYPE (decl) = tt; |
2442 | TYPE_NAME (*type) = decl; |
2443 | TREE_USED (*type) = TREE_USED (decl); |
2444 | TREE_TYPE (decl) = *type; |
2445 | } |
2446 | else |
2447 | *type = build_variant_type_copy (*type); |
2448 | |
2449 | if (warn_if_not_aligned_p) |
2450 | { |
2451 | SET_TYPE_WARN_IF_NOT_ALIGN (*type, bitalign); |
2452 | warn_if_not_aligned_p = false; |
2453 | } |
2454 | else |
2455 | { |
2456 | SET_TYPE_ALIGN (*type, bitalign); |
2457 | TYPE_USER_ALIGN (*type) = 1; |
2458 | } |
2459 | } |
2460 | else if (! VAR_OR_FUNCTION_DECL_P (decl) |
2461 | && TREE_CODE (decl) != FIELD_DECL) |
2462 | { |
2463 | error ("alignment may not be specified for %q+D" , decl); |
2464 | *no_add_attrs = true; |
2465 | } |
2466 | else if (TREE_CODE (decl) == FUNCTION_DECL |
2467 | && (((curalign = DECL_ALIGN (decl)) > bitalign) |
2468 | | ((lastalign = DECL_ALIGN (last_decl)) > bitalign))) |
2469 | { |
2470 | /* Either a prior attribute on the same declaration or one |
2471 | on a prior declaration of the same function specifies |
2472 | stricter alignment than this attribute. */ |
2473 | bool note = (lastalign > curalign |
2474 | || (lastalign == curalign |
2475 | && (DECL_USER_ALIGN (last_decl) |
2476 | > DECL_USER_ALIGN (decl)))); |
2477 | if (note) |
2478 | curalign = lastalign; |
2479 | |
2480 | curalign /= BITS_PER_UNIT; |
2481 | unsigned newalign = bitalign / BITS_PER_UNIT; |
2482 | |
2483 | auto_diagnostic_group d; |
2484 | if ((DECL_USER_ALIGN (decl) |
2485 | || DECL_USER_ALIGN (last_decl))) |
2486 | { |
2487 | if (warning (OPT_Wattributes, |
2488 | "ignoring attribute %<%E (%u)%> because it conflicts " |
2489 | "with attribute %<%E (%u)%>" , |
2490 | name, newalign, name, curalign) |
2491 | && note) |
2492 | inform (DECL_SOURCE_LOCATION (last_decl), |
2493 | "previous declaration here" ); |
2494 | /* Only reject attempts to relax/override an alignment |
2495 | explicitly specified previously and accept declarations |
2496 | that appear to relax the implicit function alignment for |
2497 | the target. Both increasing and increasing the alignment |
2498 | set by -falign-functions setting is permitted. */ |
2499 | *no_add_attrs = true; |
2500 | } |
2501 | else if (!warn_if_not_aligned_p) |
2502 | { |
2503 | /* Do not fail for attribute warn_if_not_aligned. Otherwise, |
2504 | silently avoid applying the alignment to the declaration |
2505 | because it's implicitly satisfied by the target. Apply |
2506 | the attribute nevertheless so it can be retrieved by |
2507 | __builtin_has_attribute. */ |
2508 | set_align = false; |
2509 | } |
2510 | } |
2511 | else if (DECL_USER_ALIGN (decl) |
2512 | && DECL_ALIGN (decl) > bitalign) |
2513 | /* C++-11 [dcl.align/4]: |
2514 | |
2515 | When multiple alignment-specifiers are specified for an |
2516 | entity, the alignment requirement shall be set to the |
2517 | strictest specified alignment. |
2518 | |
2519 | This formally comes from the c++11 specification but we are |
2520 | doing it for the GNU attribute syntax as well. */ |
2521 | *no_add_attrs = true; |
2522 | else if (warn_if_not_aligned_p |
2523 | && TREE_CODE (decl) == FIELD_DECL |
2524 | && !DECL_C_BIT_FIELD (decl)) |
2525 | { |
2526 | SET_DECL_WARN_IF_NOT_ALIGN (decl, bitalign); |
2527 | warn_if_not_aligned_p = false; |
2528 | set_align = false; |
2529 | } |
2530 | |
2531 | if (warn_if_not_aligned_p) |
2532 | { |
2533 | error ("%<warn_if_not_aligned%> may not be specified for %q+D" , |
2534 | decl); |
2535 | *no_add_attrs = true; |
2536 | } |
2537 | else if (!is_type && !*no_add_attrs && set_align) |
2538 | { |
2539 | SET_DECL_ALIGN (decl, bitalign); |
2540 | DECL_USER_ALIGN (decl) = 1; |
2541 | } |
2542 | |
2543 | return NULL_TREE; |
2544 | } |
2545 | |
2546 | /* Handle a "aligned" attribute; arguments as in |
2547 | struct attribute_spec.handler. */ |
2548 | |
2549 | static tree |
2550 | handle_aligned_attribute (tree *node, tree name, tree args, |
2551 | int flags, bool *no_add_attrs) |
2552 | { |
2553 | return common_handle_aligned_attribute (node, name, args, flags, |
2554 | no_add_attrs, warn_if_not_aligned_p: false); |
2555 | } |
2556 | |
2557 | /* Handle a "warn_if_not_aligned" attribute; arguments as in |
2558 | struct attribute_spec.handler. */ |
2559 | |
2560 | static tree |
2561 | handle_warn_if_not_aligned_attribute (tree *node, tree name, |
2562 | tree args, int flags, |
2563 | bool *no_add_attrs) |
2564 | { |
2565 | return common_handle_aligned_attribute (node, name, args, flags, |
2566 | no_add_attrs, warn_if_not_aligned_p: true); |
2567 | } |
2568 | |
2569 | /* Handle a "strict_flex_array" attribute; arguments as in |
2570 | struct attribute_spec.handler. */ |
2571 | |
2572 | static tree |
2573 | handle_strict_flex_array_attribute (tree *node, tree name, |
2574 | tree args, int ARG_UNUSED (flags), |
2575 | bool *no_add_attrs) |
2576 | { |
2577 | tree decl = *node; |
2578 | tree argval = TREE_VALUE (args); |
2579 | |
2580 | /* This attribute only applies to field decls of a structure. */ |
2581 | if (TREE_CODE (decl) != FIELD_DECL) |
2582 | { |
2583 | error_at (DECL_SOURCE_LOCATION (decl), |
2584 | "%qE attribute may not be specified for %q+D" , name, decl); |
2585 | *no_add_attrs = true; |
2586 | } |
2587 | /* This attribute only applies to field with array type. */ |
2588 | else if (TREE_CODE (TREE_TYPE (decl)) != ARRAY_TYPE) |
2589 | { |
2590 | error_at (DECL_SOURCE_LOCATION (decl), |
2591 | "%qE attribute may not be specified for a non-array field" , |
2592 | name); |
2593 | *no_add_attrs = true; |
2594 | } |
2595 | else if (TREE_CODE (argval) != INTEGER_CST) |
2596 | { |
2597 | error_at (DECL_SOURCE_LOCATION (decl), |
2598 | "%qE attribute argument not an integer" , name); |
2599 | *no_add_attrs = true; |
2600 | } |
2601 | else if (!tree_fits_uhwi_p (argval) || tree_to_uhwi (argval) > 3) |
2602 | { |
2603 | error_at (DECL_SOURCE_LOCATION (decl), |
2604 | "%qE attribute argument %qE is not an integer constant" |
2605 | " between 0 and 3" , name, argval); |
2606 | *no_add_attrs = true; |
2607 | } |
2608 | |
2609 | return NULL_TREE; |
2610 | } |
2611 | |
2612 | /* Handle a "weak" attribute; arguments as in |
2613 | struct attribute_spec.handler. */ |
2614 | |
2615 | static tree |
2616 | handle_weak_attribute (tree *node, tree name, |
2617 | tree ARG_UNUSED (args), |
2618 | int ARG_UNUSED (flags), |
2619 | bool * ARG_UNUSED (no_add_attrs)) |
2620 | { |
2621 | if (TREE_CODE (*node) == FUNCTION_DECL |
2622 | && DECL_DECLARED_INLINE_P (*node)) |
2623 | { |
2624 | warning (OPT_Wattributes, "inline function %q+D declared weak" , *node); |
2625 | *no_add_attrs = true; |
2626 | } |
2627 | else if (lookup_attribute (attr_name: "ifunc" , DECL_ATTRIBUTES (*node))) |
2628 | { |
2629 | error ("indirect function %q+D cannot be declared weak" , *node); |
2630 | *no_add_attrs = true; |
2631 | return NULL_TREE; |
2632 | } |
2633 | else if (VAR_OR_FUNCTION_DECL_P (*node)) |
2634 | declare_weak (*node); |
2635 | else |
2636 | warning (OPT_Wattributes, "%qE attribute ignored" , name); |
2637 | |
2638 | return NULL_TREE; |
2639 | } |
2640 | |
2641 | /* Handle a "noinit" or "persistent" attribute; arguments as in |
2642 | struct attribute_spec.handler. |
2643 | This generic handler is used for "special variable sections" that allow the |
2644 | section name to be set using a dedicated attribute. Additional validation |
2645 | is performed for the specific properties of the section corresponding to the |
2646 | attribute. |
2647 | The ".noinit" section *is not* loaded by the program loader, and is not |
2648 | initialized by the runtime startup code. |
2649 | The ".persistent" section *is* loaded by the program loader, but is not |
2650 | initialized by the runtime startup code. */ |
2651 | static tree |
2652 | handle_special_var_sec_attribute (tree *node, tree name, tree args, |
2653 | int flags, bool *no_add_attrs) |
2654 | { |
2655 | tree decl = *node; |
2656 | tree res = NULL_TREE; |
2657 | |
2658 | /* First perform generic validation common to "noinit" and "persistent" |
2659 | attributes. */ |
2660 | if (!targetm_common.have_named_sections) |
2661 | { |
2662 | error_at (DECL_SOURCE_LOCATION (decl), |
2663 | "section attributes are not supported for this target" ); |
2664 | goto fail; |
2665 | } |
2666 | |
2667 | if (!VAR_P (decl)) |
2668 | { |
2669 | warning_at (DECL_SOURCE_LOCATION (decl), OPT_Wattributes, |
2670 | "ignoring %qE attribute not set on a variable" , |
2671 | name); |
2672 | goto fail; |
2673 | } |
2674 | |
2675 | if (VAR_P (decl) |
2676 | && current_function_decl != NULL_TREE |
2677 | && !TREE_STATIC (decl)) |
2678 | { |
2679 | error_at (DECL_SOURCE_LOCATION (decl), |
2680 | "%qE attribute cannot be specified for local variables" , |
2681 | name); |
2682 | goto fail; |
2683 | } |
2684 | |
2685 | if (VAR_P (decl) |
2686 | && !targetm.have_tls && targetm.emutls.tmpl_section |
2687 | && DECL_THREAD_LOCAL_P (decl)) |
2688 | { |
2689 | error ("section of %q+D cannot be overridden" , decl); |
2690 | goto fail; |
2691 | } |
2692 | |
2693 | if (!targetm.have_switchable_bss_sections) |
2694 | { |
2695 | error ("%qE attribute is specific to ELF targets" , name); |
2696 | goto fail; |
2697 | } |
2698 | |
2699 | if (TREE_READONLY (decl)) |
2700 | { |
2701 | warning_at (DECL_SOURCE_LOCATION (decl), OPT_Wattributes, |
2702 | "ignoring %qE attribute set on const variable" , |
2703 | name); |
2704 | goto fail; |
2705 | } |
2706 | |
2707 | /* Now validate noinit/persistent individually. */ |
2708 | if (strcmp (IDENTIFIER_POINTER (name), s2: "noinit" ) == 0) |
2709 | { |
2710 | if (DECL_INITIAL (decl)) |
2711 | { |
2712 | warning_at (DECL_SOURCE_LOCATION (decl), OPT_Wattributes, |
2713 | "ignoring %qE attribute set on initialized variable" , |
2714 | name); |
2715 | goto fail; |
2716 | } |
2717 | /* If this var is thought to be common, then change this. "noinit" |
2718 | variables must be placed in an explicit ".noinit" section. */ |
2719 | DECL_COMMON (decl) = 0; |
2720 | } |
2721 | else if (strcmp (IDENTIFIER_POINTER (name), s2: "persistent" ) == 0) |
2722 | { |
2723 | if (DECL_COMMON (decl) || DECL_INITIAL (decl) == NULL_TREE) |
2724 | { |
2725 | warning_at (DECL_SOURCE_LOCATION (decl), OPT_Wattributes, |
2726 | "ignoring %qE attribute set on uninitialized variable" , |
2727 | name); |
2728 | goto fail; |
2729 | } |
2730 | } |
2731 | else |
2732 | gcc_unreachable (); |
2733 | |
2734 | res = targetm.handle_generic_attribute (node, name, args, flags, |
2735 | no_add_attrs); |
2736 | |
2737 | /* If the back end confirms the attribute can be added then continue onto |
2738 | final processing. */ |
2739 | if (!(*no_add_attrs)) |
2740 | return res; |
2741 | |
2742 | fail: |
2743 | *no_add_attrs = true; |
2744 | return res; |
2745 | } |
2746 | |
2747 | /* Handle a "noplt" attribute; arguments as in |
2748 | struct attribute_spec.handler. */ |
2749 | |
2750 | static tree |
2751 | handle_noplt_attribute (tree *node, tree name, |
2752 | tree ARG_UNUSED (args), |
2753 | int ARG_UNUSED (flags), |
2754 | bool * ARG_UNUSED (no_add_attrs)) |
2755 | { |
2756 | if (TREE_CODE (*node) != FUNCTION_DECL) |
2757 | { |
2758 | warning (OPT_Wattributes, |
2759 | "%qE attribute is only applicable on functions" , name); |
2760 | *no_add_attrs = true; |
2761 | return NULL_TREE; |
2762 | } |
2763 | return NULL_TREE; |
2764 | } |
2765 | |
2766 | /* Handle a "symver" attribute. */ |
2767 | |
2768 | static tree |
2769 | handle_symver_attribute (tree *node, tree ARG_UNUSED (name), tree args, |
2770 | int ARG_UNUSED (flags), bool *no_add_attrs) |
2771 | { |
2772 | tree symver; |
2773 | const char *symver_str; |
2774 | |
2775 | if (TREE_CODE (*node) != FUNCTION_DECL && TREE_CODE (*node) != VAR_DECL) |
2776 | { |
2777 | warning (OPT_Wattributes, |
2778 | "%<symver%> attribute only applies to functions and variables" ); |
2779 | *no_add_attrs = true; |
2780 | return NULL_TREE; |
2781 | } |
2782 | |
2783 | if (!decl_in_symtab_p (decl: *node)) |
2784 | { |
2785 | warning (OPT_Wattributes, |
2786 | "%<symver%> attribute is only applicable to symbols" ); |
2787 | *no_add_attrs = true; |
2788 | return NULL_TREE; |
2789 | } |
2790 | |
2791 | for (; args; args = TREE_CHAIN (args)) |
2792 | { |
2793 | symver = TREE_VALUE (args); |
2794 | if (TREE_CODE (symver) != STRING_CST) |
2795 | { |
2796 | error ("%<symver%> attribute argument not a string constant" ); |
2797 | *no_add_attrs = true; |
2798 | return NULL_TREE; |
2799 | } |
2800 | |
2801 | symver_str = TREE_STRING_POINTER (symver); |
2802 | |
2803 | int ats = 0; |
2804 | for (int n = 0; (int)n < TREE_STRING_LENGTH (symver); n++) |
2805 | if (symver_str[n] == '@') |
2806 | ats++; |
2807 | |
2808 | if (ats != 1 && ats != 2) |
2809 | { |
2810 | error ("symver attribute argument must have format %<name@nodename%>" ); |
2811 | error ("%<symver%> attribute argument %qs must contain one or two " |
2812 | "%<@%>" , symver_str); |
2813 | *no_add_attrs = true; |
2814 | return NULL_TREE; |
2815 | } |
2816 | } |
2817 | |
2818 | return NULL_TREE; |
2819 | } |
2820 | |
2821 | |
2822 | /* Handle an "alias" or "ifunc" attribute; arguments as in |
2823 | struct attribute_spec.handler, except that IS_ALIAS tells us |
2824 | whether this is an alias as opposed to ifunc attribute. */ |
2825 | |
2826 | static tree |
2827 | handle_alias_ifunc_attribute (bool is_alias, tree *node, tree name, tree args, |
2828 | bool *no_add_attrs) |
2829 | { |
2830 | tree decl = *node; |
2831 | |
2832 | if (TREE_CODE (decl) != FUNCTION_DECL |
2833 | && (!is_alias || !VAR_P (decl))) |
2834 | { |
2835 | warning (OPT_Wattributes, "%qE attribute ignored" , name); |
2836 | *no_add_attrs = true; |
2837 | } |
2838 | else if ((TREE_CODE (decl) == FUNCTION_DECL && DECL_INITIAL (decl)) |
2839 | || (TREE_CODE (decl) != FUNCTION_DECL |
2840 | && TREE_PUBLIC (decl) && !DECL_EXTERNAL (decl)) |
2841 | /* A static variable declaration is always a tentative definition, |
2842 | but the alias is a non-tentative definition which overrides. */ |
2843 | || (TREE_CODE (decl) != FUNCTION_DECL |
2844 | && ! TREE_PUBLIC (decl) && DECL_INITIAL (decl))) |
2845 | { |
2846 | error ("%q+D defined both normally and as %qE attribute" , decl, name); |
2847 | *no_add_attrs = true; |
2848 | return NULL_TREE; |
2849 | } |
2850 | else if (!is_alias |
2851 | && (lookup_attribute (attr_name: "weak" , DECL_ATTRIBUTES (decl)) |
2852 | || lookup_attribute (attr_name: "weakref" , DECL_ATTRIBUTES (decl)))) |
2853 | { |
2854 | error ("weak %q+D cannot be defined %qE" , decl, name); |
2855 | *no_add_attrs = true; |
2856 | return NULL_TREE; |
2857 | } |
2858 | |
2859 | /* Note that the very first time we process a nested declaration, |
2860 | decl_function_context will not be set. Indeed, *would* never |
2861 | be set except for the DECL_INITIAL/DECL_EXTERNAL frobbery that |
2862 | we do below. After such frobbery, pushdecl would set the context. |
2863 | In any case, this is never what we want. */ |
2864 | else if (decl_function_context (decl) == 0 && current_function_decl == NULL) |
2865 | { |
2866 | tree id; |
2867 | |
2868 | id = TREE_VALUE (args); |
2869 | if (TREE_CODE (id) != STRING_CST) |
2870 | { |
2871 | error ("attribute %qE argument not a string" , name); |
2872 | *no_add_attrs = true; |
2873 | return NULL_TREE; |
2874 | } |
2875 | id = get_identifier (TREE_STRING_POINTER (id)); |
2876 | /* This counts as a use of the object pointed to. */ |
2877 | TREE_USED (id) = 1; |
2878 | |
2879 | if (TREE_CODE (decl) == FUNCTION_DECL) |
2880 | DECL_INITIAL (decl) = error_mark_node; |
2881 | else |
2882 | TREE_STATIC (decl) = 1; |
2883 | |
2884 | if (!is_alias) |
2885 | { |
2886 | /* ifuncs are also aliases, so set that attribute too. */ |
2887 | DECL_ATTRIBUTES (decl) |
2888 | = tree_cons (get_identifier ("alias" ), args, |
2889 | DECL_ATTRIBUTES (decl)); |
2890 | DECL_ATTRIBUTES (decl) = tree_cons (get_identifier ("ifunc" ), |
2891 | NULL, DECL_ATTRIBUTES (decl)); |
2892 | } |
2893 | } |
2894 | else |
2895 | { |
2896 | warning (OPT_Wattributes, "%qE attribute ignored" , name); |
2897 | *no_add_attrs = true; |
2898 | } |
2899 | |
2900 | if (decl_in_symtab_p (decl: *node)) |
2901 | { |
2902 | struct symtab_node *n = symtab_node::get (decl); |
2903 | if (n && n->refuse_visibility_changes) |
2904 | error ("%+qD declared %qs after being used" , |
2905 | decl, is_alias ? "alias" : "ifunc" ); |
2906 | } |
2907 | |
2908 | |
2909 | return NULL_TREE; |
2910 | } |
2911 | |
2912 | /* Handle an "alias" or "ifunc" attribute; arguments as in |
2913 | struct attribute_spec.handler. */ |
2914 | |
2915 | static tree |
2916 | handle_ifunc_attribute (tree *node, tree name, tree args, |
2917 | int ARG_UNUSED (flags), bool *no_add_attrs) |
2918 | { |
2919 | return handle_alias_ifunc_attribute (is_alias: false, node, name, args, no_add_attrs); |
2920 | } |
2921 | |
2922 | /* Handle an "alias" or "ifunc" attribute; arguments as in |
2923 | struct attribute_spec.handler. */ |
2924 | |
2925 | static tree |
2926 | handle_alias_attribute (tree *node, tree name, tree args, |
2927 | int ARG_UNUSED (flags), bool *no_add_attrs) |
2928 | { |
2929 | return handle_alias_ifunc_attribute (is_alias: true, node, name, args, no_add_attrs); |
2930 | } |
2931 | |
2932 | /* Handle the "copy" attribute NAME by copying the set of attributes |
2933 | from the symbol referenced by ARGS to the declaration of *NODE. */ |
2934 | |
2935 | static tree |
2936 | handle_copy_attribute (tree *node, tree name, tree args, |
2937 | int flags, bool *no_add_attrs) |
2938 | { |
2939 | /* Do not apply the copy attribute itself. It serves no purpose |
2940 | other than to copy other attributes. */ |
2941 | *no_add_attrs = true; |
2942 | |
2943 | tree decl = *node; |
2944 | |
2945 | tree ref = TREE_VALUE (args); |
2946 | if (ref == error_mark_node) |
2947 | return NULL_TREE; |
2948 | |
2949 | if (TREE_CODE (ref) == STRING_CST) |
2950 | { |
2951 | /* Explicitly handle this case since using a string literal |
2952 | as an argument is a likely mistake. */ |
2953 | error_at (DECL_SOURCE_LOCATION (decl), |
2954 | "%qE attribute argument cannot be a string" , |
2955 | name); |
2956 | return NULL_TREE; |
2957 | } |
2958 | |
2959 | if (CONSTANT_CLASS_P (ref) |
2960 | && (INTEGRAL_TYPE_P (TREE_TYPE (ref)) |
2961 | || FLOAT_TYPE_P (TREE_TYPE (ref)))) |
2962 | { |
2963 | /* Similar to the string case, since some function attributes |
2964 | accept literal numbers as arguments (e.g., alloc_size or |
2965 | nonnull) using one here is a likely mistake. */ |
2966 | error_at (DECL_SOURCE_LOCATION (decl), |
2967 | "%qE attribute argument cannot be a constant arithmetic " |
2968 | "expression" , |
2969 | name); |
2970 | return NULL_TREE; |
2971 | } |
2972 | |
2973 | if (ref == node[1]) |
2974 | { |
2975 | /* Another possible mistake (but indirect self-references aren't |
2976 | and diagnosed and shouldn't be). */ |
2977 | if (warning_at (DECL_SOURCE_LOCATION (decl), OPT_Wattributes, |
2978 | "%qE attribute ignored on a redeclaration " |
2979 | "of the referenced symbol" , |
2980 | name)) |
2981 | inform (DECL_SOURCE_LOCATION (node[1]), |
2982 | "previous declaration here" ); |
2983 | return NULL_TREE; |
2984 | } |
2985 | |
2986 | /* Consider address-of expressions in the attribute argument |
2987 | as requests to copy from the referenced entity. */ |
2988 | if (TREE_CODE (ref) == ADDR_EXPR) |
2989 | ref = TREE_OPERAND (ref, 0); |
2990 | |
2991 | do |
2992 | { |
2993 | /* Drill down into references to find the referenced decl. */ |
2994 | tree_code refcode = TREE_CODE (ref); |
2995 | if (refcode == ARRAY_REF |
2996 | || refcode == INDIRECT_REF) |
2997 | ref = TREE_OPERAND (ref, 0); |
2998 | else if (refcode == COMPONENT_REF) |
2999 | ref = TREE_OPERAND (ref, 1); |
3000 | else |
3001 | break; |
3002 | } while (!DECL_P (ref)); |
3003 | |
3004 | /* For object pointer expressions, consider those to be requests |
3005 | to copy from their type, such as in: |
3006 | struct __attribute__ (copy ((struct T *)0)) U { ... }; |
3007 | which copies type attributes from struct T to the declaration |
3008 | of struct U. */ |
3009 | if ((CONSTANT_CLASS_P (ref) || EXPR_P (ref)) |
3010 | && POINTER_TYPE_P (TREE_TYPE (ref)) |
3011 | && !FUNCTION_POINTER_TYPE_P (TREE_TYPE (ref))) |
3012 | ref = TREE_TYPE (ref); |
3013 | |
3014 | tree reftype = TYPE_P (ref) ? ref : TREE_TYPE (ref); |
3015 | |
3016 | if (DECL_P (decl)) |
3017 | { |
3018 | if ((VAR_P (decl) |
3019 | && (TREE_CODE (ref) == FUNCTION_DECL |
3020 | || (EXPR_P (ref) |
3021 | && POINTER_TYPE_P (reftype) |
3022 | && FUNC_OR_METHOD_TYPE_P (TREE_TYPE (reftype))))) |
3023 | || (TREE_CODE (decl) == FUNCTION_DECL |
3024 | && (VAR_P (ref) |
3025 | || (EXPR_P (ref) |
3026 | && !FUNC_OR_METHOD_TYPE_P (reftype) |
3027 | && (!POINTER_TYPE_P (reftype) |
3028 | || !FUNC_OR_METHOD_TYPE_P (TREE_TYPE (reftype))))))) |
3029 | { |
3030 | /* It makes no sense to try to copy function attributes |
3031 | to a variable, or variable attributes to a function. */ |
3032 | if (warning (OPT_Wattributes, |
3033 | "%qE attribute ignored on a declaration of " |
3034 | "a different kind than referenced symbol" , |
3035 | name) |
3036 | && DECL_P (ref)) |
3037 | inform (DECL_SOURCE_LOCATION (ref), |
3038 | "symbol %qD referenced by %qD declared here" , ref, decl); |
3039 | return NULL_TREE; |
3040 | } |
3041 | |
3042 | tree attrs = NULL_TREE; |
3043 | if (DECL_P (ref)) |
3044 | attrs = DECL_ATTRIBUTES (ref); |
3045 | else if (TYPE_P (ref)) |
3046 | attrs = TYPE_ATTRIBUTES (ref); |
3047 | |
3048 | /* Copy decl attributes from REF to DECL. */ |
3049 | for (tree at = attrs; at; at = TREE_CHAIN (at)) |
3050 | { |
3051 | /* Avoid copying attributes that affect a symbol linkage, |
3052 | inlining, or visibility since those in all likelihood |
3053 | only apply to the target. |
3054 | FIXME: make it possible to specify which attributes to |
3055 | copy or not to copy in the copy attribute itself. */ |
3056 | tree atname = get_attribute_name (at); |
3057 | if (is_attribute_p (attr_name: "alias" , ident: atname) |
3058 | || is_attribute_p (attr_name: "always_inline" , ident: atname) |
3059 | || is_attribute_p (attr_name: "gnu_inline" , ident: atname) |
3060 | || is_attribute_p (attr_name: "ifunc" , ident: atname) |
3061 | || is_attribute_p (attr_name: "noinline" , ident: atname) |
3062 | || is_attribute_p (attr_name: "visibility" , ident: atname) |
3063 | || is_attribute_p (attr_name: "weak" , ident: atname) |
3064 | || is_attribute_p (attr_name: "weakref" , ident: atname) |
3065 | || is_attribute_p (attr_name: "target_clones" , ident: atname)) |
3066 | continue; |
3067 | |
3068 | /* Attribute leaf only applies to extern functions. |
3069 | Avoid copying it to static ones. */ |
3070 | if (!TREE_PUBLIC (decl) |
3071 | && is_attribute_p (attr_name: "leaf" , ident: atname)) |
3072 | continue; |
3073 | |
3074 | tree atargs = TREE_VALUE (at); |
3075 | /* Create a copy of just the one attribute ar AT, including |
3076 | its argumentsm and add it to DECL. */ |
3077 | tree attr = tree_cons (atname, copy_list (atargs), NULL_TREE); |
3078 | decl_attributes (node, attr, flags, EXPR_P (ref) ? NULL_TREE : ref); |
3079 | } |
3080 | |
3081 | /* Proceed to copy type attributes below. */ |
3082 | } |
3083 | else if (!TYPE_P (decl)) |
3084 | { |
3085 | error_at (DECL_SOURCE_LOCATION (decl), |
3086 | "%qE attribute must apply to a declaration" , |
3087 | name); |
3088 | return NULL_TREE; |
3089 | } |
3090 | |
3091 | /* A function declared with attribute nothrow has the attribute |
3092 | attached to it, but a C++ throw() function does not. */ |
3093 | if (TREE_NOTHROW (ref)) |
3094 | TREE_NOTHROW (decl) = true; |
3095 | |
3096 | /* Similarly, a function declared with attribute noreturn has it |
3097 | attached on to it, but a C11 _Noreturn function does not. */ |
3098 | if (DECL_P (ref) |
3099 | && TREE_THIS_VOLATILE (ref) |
3100 | && FUNC_OR_METHOD_TYPE_P (reftype)) |
3101 | TREE_THIS_VOLATILE (decl) = true; |
3102 | |
3103 | if (POINTER_TYPE_P (reftype)) |
3104 | reftype = TREE_TYPE (reftype); |
3105 | |
3106 | if (!TYPE_P (reftype)) |
3107 | return NULL_TREE; |
3108 | |
3109 | tree attrs = TYPE_ATTRIBUTES (reftype); |
3110 | |
3111 | /* Copy type attributes from REF to DECL. Pass in REF if it's a DECL |
3112 | or a type but not if it's an expression. Set ATTR_FLAG_INTERNAL |
3113 | since the attributes' arguments may be in their internal form. */ |
3114 | for (tree at = attrs; at; at = TREE_CHAIN (at)) |
3115 | decl_attributes (node, at, flags | ATTR_FLAG_INTERNAL, |
3116 | EXPR_P (ref) ? NULL_TREE : ref); |
3117 | |
3118 | return NULL_TREE; |
3119 | } |
3120 | |
3121 | /* Handle a "weakref" attribute; arguments as in struct |
3122 | attribute_spec.handler. */ |
3123 | |
3124 | static tree |
3125 | handle_weakref_attribute (tree *node, tree name, tree args, |
3126 | int flags, bool *no_add_attrs) |
3127 | { |
3128 | tree attr = NULL_TREE; |
3129 | |
3130 | /* We must ignore the attribute when it is associated with |
3131 | local-scoped decls, since attribute alias is ignored and many |
3132 | such symbols do not even have a DECL_WEAK field. */ |
3133 | if (decl_function_context (*node) |
3134 | || current_function_decl |
3135 | || !VAR_OR_FUNCTION_DECL_P (*node)) |
3136 | { |
3137 | warning (OPT_Wattributes, "%qE attribute ignored" , name); |
3138 | *no_add_attrs = true; |
3139 | return NULL_TREE; |
3140 | } |
3141 | |
3142 | if (lookup_attribute (attr_name: "ifunc" , DECL_ATTRIBUTES (*node))) |
3143 | { |
3144 | error ("indirect function %q+D cannot be declared %qE" , |
3145 | *node, name); |
3146 | *no_add_attrs = true; |
3147 | return NULL_TREE; |
3148 | } |
3149 | |
3150 | /* The idea here is that `weakref("name")' mutates into `weakref, |
3151 | alias("name")', and weakref without arguments, in turn, |
3152 | implicitly adds weak. */ |
3153 | |
3154 | if (args) |
3155 | { |
3156 | attr = tree_cons (get_identifier ("alias" ), args, attr); |
3157 | attr = tree_cons (get_identifier ("weakref" ), NULL_TREE, attr); |
3158 | |
3159 | *no_add_attrs = true; |
3160 | |
3161 | decl_attributes (node, attr, flags); |
3162 | } |
3163 | else |
3164 | { |
3165 | if (lookup_attribute (attr_name: "alias" , DECL_ATTRIBUTES (*node))) |
3166 | error_at (DECL_SOURCE_LOCATION (*node), |
3167 | "%qE attribute must appear before %qs attribute" , |
3168 | name, "alias" ); |
3169 | |
3170 | /* Can't call declare_weak because it wants this to be TREE_PUBLIC, |
3171 | and that isn't supported; and because it wants to add it to |
3172 | the list of weak decls, which isn't helpful. */ |
3173 | DECL_WEAK (*node) = 1; |
3174 | } |
3175 | |
3176 | if (decl_in_symtab_p (decl: *node)) |
3177 | { |
3178 | struct symtab_node *n = symtab_node::get (decl: *node); |
3179 | if (n && n->refuse_visibility_changes) |
3180 | error ("%+qD declared %qE after being used" , *node, name); |
3181 | } |
3182 | |
3183 | return NULL_TREE; |
3184 | } |
3185 | |
3186 | /* Handle an "visibility" attribute; arguments as in |
3187 | struct attribute_spec.handler. */ |
3188 | |
3189 | static tree |
3190 | handle_visibility_attribute (tree *node, tree name, tree args, |
3191 | int ARG_UNUSED (flags), |
3192 | bool *ARG_UNUSED (no_add_attrs)) |
3193 | { |
3194 | tree decl = *node; |
3195 | tree id = TREE_VALUE (args); |
3196 | enum symbol_visibility vis; |
3197 | |
3198 | if (TYPE_P (*node)) |
3199 | { |
3200 | if (TREE_CODE (*node) == ENUMERAL_TYPE) |
3201 | /* OK */; |
3202 | else if (!RECORD_OR_UNION_TYPE_P (*node)) |
3203 | { |
3204 | warning (OPT_Wattributes, "%qE attribute ignored on non-class types" , |
3205 | name); |
3206 | return NULL_TREE; |
3207 | } |
3208 | else if (TYPE_FIELDS (*node)) |
3209 | { |
3210 | error ("%qE attribute ignored because %qT is already defined" , |
3211 | name, *node); |
3212 | return NULL_TREE; |
3213 | } |
3214 | } |
3215 | else if (decl_function_context (decl) != 0 || !TREE_PUBLIC (decl)) |
3216 | { |
3217 | warning (OPT_Wattributes, "%qE attribute ignored" , name); |
3218 | return NULL_TREE; |
3219 | } |
3220 | |
3221 | if (TREE_CODE (id) != STRING_CST) |
3222 | { |
3223 | error ("visibility argument not a string" ); |
3224 | return NULL_TREE; |
3225 | } |
3226 | |
3227 | /* If this is a type, set the visibility on the type decl. */ |
3228 | if (TYPE_P (decl)) |
3229 | { |
3230 | decl = TYPE_NAME (decl); |
3231 | if (!decl) |
3232 | return NULL_TREE; |
3233 | if (TREE_CODE (decl) == IDENTIFIER_NODE) |
3234 | { |
3235 | warning (OPT_Wattributes, "%qE attribute ignored on types" , |
3236 | name); |
3237 | return NULL_TREE; |
3238 | } |
3239 | } |
3240 | |
3241 | if (strcmp (TREE_STRING_POINTER (id), s2: "default" ) == 0) |
3242 | vis = VISIBILITY_DEFAULT; |
3243 | else if (strcmp (TREE_STRING_POINTER (id), s2: "internal" ) == 0) |
3244 | vis = VISIBILITY_INTERNAL; |
3245 | else if (strcmp (TREE_STRING_POINTER (id), s2: "hidden" ) == 0) |
3246 | vis = VISIBILITY_HIDDEN; |
3247 | else if (strcmp (TREE_STRING_POINTER (id), s2: "protected" ) == 0) |
3248 | vis = VISIBILITY_PROTECTED; |
3249 | else |
3250 | { |
3251 | error ("attribute %qE argument must be one of %qs, %qs, %qs, or %qs" , |
3252 | name, "default" , "hidden" , "protected" , "internal" ); |
3253 | vis = VISIBILITY_DEFAULT; |
3254 | } |
3255 | |
3256 | if (DECL_VISIBILITY_SPECIFIED (decl) |
3257 | && vis != DECL_VISIBILITY (decl)) |
3258 | { |
3259 | tree attributes = (TYPE_P (*node) |
3260 | ? TYPE_ATTRIBUTES (*node) |
3261 | : DECL_ATTRIBUTES (decl)); |
3262 | if (lookup_attribute (attr_name: "visibility" , list: attributes)) |
3263 | error ("%qD redeclared with different visibility" , decl); |
3264 | else if (TARGET_DLLIMPORT_DECL_ATTRIBUTES |
3265 | && lookup_attribute (attr_name: "dllimport" , list: attributes)) |
3266 | error ("%qD was declared %qs which implies default visibility" , |
3267 | decl, "dllimport" ); |
3268 | else if (TARGET_DLLIMPORT_DECL_ATTRIBUTES |
3269 | && lookup_attribute (attr_name: "dllexport" , list: attributes)) |
3270 | error ("%qD was declared %qs which implies default visibility" , |
3271 | decl, "dllexport" ); |
3272 | } |
3273 | |
3274 | DECL_VISIBILITY (decl) = vis; |
3275 | DECL_VISIBILITY_SPECIFIED (decl) = 1; |
3276 | |
3277 | /* Go ahead and attach the attribute to the node as well. This is needed |
3278 | so we can determine whether we have VISIBILITY_DEFAULT because the |
3279 | visibility was not specified, or because it was explicitly overridden |
3280 | from the containing scope. */ |
3281 | |
3282 | return NULL_TREE; |
3283 | } |
3284 | |
3285 | /* Handle an "tls_model" attribute; arguments as in |
3286 | struct attribute_spec.handler. */ |
3287 | |
3288 | static tree |
3289 | handle_tls_model_attribute (tree *node, tree name, tree args, |
3290 | int ARG_UNUSED (flags), |
3291 | bool *ARG_UNUSED (no_add_attrs)) |
3292 | { |
3293 | tree id; |
3294 | tree decl = *node; |
3295 | enum tls_model kind; |
3296 | |
3297 | if (!VAR_P (decl)) |
3298 | { |
3299 | warning (OPT_Wattributes, "%qE attribute ignored because %qD " |
3300 | "is not a variable" , |
3301 | name, decl); |
3302 | return NULL_TREE; |
3303 | } |
3304 | |
3305 | if (!DECL_THREAD_LOCAL_P (decl)) |
3306 | { |
3307 | warning (OPT_Wattributes, "%qE attribute ignored because %qD does " |
3308 | "not have thread storage duration" , name, decl); |
3309 | return NULL_TREE; |
3310 | } |
3311 | |
3312 | kind = DECL_TLS_MODEL (decl); |
3313 | id = TREE_VALUE (args); |
3314 | if (TREE_CODE (id) != STRING_CST) |
3315 | { |
3316 | error ("%qE argument not a string" , name); |
3317 | return NULL_TREE; |
3318 | } |
3319 | |
3320 | if (!strcmp (TREE_STRING_POINTER (id), s2: "local-exec" )) |
3321 | kind = TLS_MODEL_LOCAL_EXEC; |
3322 | else if (!strcmp (TREE_STRING_POINTER (id), s2: "initial-exec" )) |
3323 | kind = TLS_MODEL_INITIAL_EXEC; |
3324 | else if (!strcmp (TREE_STRING_POINTER (id), s2: "local-dynamic" )) |
3325 | kind = optimize ? TLS_MODEL_LOCAL_DYNAMIC : TLS_MODEL_GLOBAL_DYNAMIC; |
3326 | else if (!strcmp (TREE_STRING_POINTER (id), s2: "global-dynamic" )) |
3327 | kind = TLS_MODEL_GLOBAL_DYNAMIC; |
3328 | else |
3329 | error ("%qE argument must be one of %qs, %qs, %qs, or %qs" , |
3330 | name, |
3331 | "local-exec" , "initial-exec" , "local-dynamic" , "global-dynamic" ); |
3332 | |
3333 | set_decl_tls_model (decl, kind); |
3334 | return NULL_TREE; |
3335 | } |
3336 | |
3337 | /* Handle a "no_instrument_function" attribute; arguments as in |
3338 | struct attribute_spec.handler. */ |
3339 | |
3340 | static tree |
3341 | handle_no_instrument_function_attribute (tree *node, tree name, |
3342 | tree ARG_UNUSED (args), |
3343 | int ARG_UNUSED (flags), |
3344 | bool *no_add_attrs) |
3345 | { |
3346 | tree decl = *node; |
3347 | |
3348 | if (TREE_CODE (decl) != FUNCTION_DECL) |
3349 | { |
3350 | error_at (DECL_SOURCE_LOCATION (decl), |
3351 | "%qE attribute applies only to functions" , name); |
3352 | *no_add_attrs = true; |
3353 | } |
3354 | else |
3355 | DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (decl) = 1; |
3356 | |
3357 | return NULL_TREE; |
3358 | } |
3359 | |
3360 | /* Handle a "no_profile_instrument_function" attribute; arguments as in |
3361 | struct attribute_spec.handler. */ |
3362 | |
3363 | static tree |
3364 | handle_no_profile_instrument_function_attribute (tree *node, tree name, tree, |
3365 | int, bool *no_add_attrs) |
3366 | { |
3367 | if (TREE_CODE (*node) != FUNCTION_DECL) |
3368 | { |
3369 | warning (OPT_Wattributes, "%qE attribute ignored" , name); |
3370 | *no_add_attrs = true; |
3371 | } |
3372 | |
3373 | return NULL_TREE; |
3374 | } |
3375 | |
3376 | /* If ALLOC_DECL and DEALLOC_DECL are a pair of user-defined functions, |
3377 | if they are declared inline issue warnings and return null. Otherwise |
3378 | create attribute noinline, install it in ALLOC_DECL, and return it. |
3379 | Otherwise return null. */ |
3380 | |
3381 | static tree |
3382 | maybe_add_noinline (tree name, tree alloc_decl, tree dealloc_decl, |
3383 | bool *no_add_attrs) |
3384 | { |
3385 | if (fndecl_built_in_p (node: alloc_decl) || fndecl_built_in_p (node: dealloc_decl)) |
3386 | return NULL_TREE; |
3387 | |
3388 | /* When inlining (or optimization) is enabled and the allocator and |
3389 | deallocator are not built-in functions, ignore the attribute on |
3390 | functions declared inline since it could lead to false positives |
3391 | when inlining one or the other call would wind up calling |
3392 | a mismatched allocator or deallocator. */ |
3393 | if ((optimize && DECL_DECLARED_INLINE_P (alloc_decl)) |
3394 | || lookup_attribute (attr_name: "always_inline" , DECL_ATTRIBUTES (alloc_decl))) |
3395 | { |
3396 | warning (OPT_Wattributes, |
3397 | "%<%E (%E)%> attribute ignored on functions " |
3398 | "declared %qs" , name, DECL_NAME (dealloc_decl), "inline" ); |
3399 | *no_add_attrs = true; |
3400 | return NULL_TREE; |
3401 | } |
3402 | |
3403 | if ((optimize && DECL_DECLARED_INLINE_P (dealloc_decl)) |
3404 | || lookup_attribute (attr_name: "always_inline" , DECL_ATTRIBUTES (dealloc_decl))) |
3405 | { |
3406 | warning (OPT_Wattributes, |
3407 | "%<%E (%E)%> attribute ignored with deallocation " |
3408 | "functions declared %qs" , |
3409 | name, DECL_NAME (dealloc_decl), "inline" ); |
3410 | inform (DECL_SOURCE_LOCATION (dealloc_decl), |
3411 | "deallocation function declared here" ); |
3412 | *no_add_attrs = true; |
3413 | return NULL_TREE; |
3414 | } |
3415 | |
3416 | /* Disable inlining for non-standard deallocators to avoid false |
3417 | positives due to mismatches between the inlined implementation |
3418 | of one and not the other pair of functions. */ |
3419 | tree attr = tree_cons (get_identifier ("noinline" ), NULL_TREE, NULL_TREE); |
3420 | decl_attributes (&alloc_decl, attr, 0); |
3421 | return attr; |
3422 | } |
3423 | |
3424 | /* Handle the "malloc" attribute. */ |
3425 | |
3426 | static tree |
3427 | handle_malloc_attribute (tree *node, tree name, tree args, int flags, |
3428 | bool *no_add_attrs) |
3429 | { |
3430 | if (flags & ATTR_FLAG_INTERNAL) |
3431 | /* Recursive call. */ |
3432 | return NULL_TREE; |
3433 | |
3434 | tree fndecl = *node; |
3435 | |
3436 | if (TREE_CODE (*node) != FUNCTION_DECL) |
3437 | { |
3438 | warning (OPT_Wattributes, "%qE attribute ignored; valid only " |
3439 | "for functions" , |
3440 | name); |
3441 | *no_add_attrs = true; |
3442 | return NULL_TREE; |
3443 | } |
3444 | |
3445 | tree rettype = TREE_TYPE (TREE_TYPE (*node)); |
3446 | if (!POINTER_TYPE_P (rettype)) |
3447 | { |
3448 | warning (OPT_Wattributes, "%qE attribute ignored on functions " |
3449 | "returning %qT; valid only for pointer return types" , |
3450 | name, rettype); |
3451 | *no_add_attrs = true; |
3452 | return NULL_TREE; |
3453 | } |
3454 | |
3455 | if (!args) |
3456 | { |
3457 | /* Only the form of the attribute with no arguments declares |
3458 | a function malloc-like. */ |
3459 | DECL_IS_MALLOC (*node) = 1; |
3460 | return NULL_TREE; |
3461 | } |
3462 | |
3463 | tree dealloc = TREE_VALUE (args); |
3464 | if (error_operand_p (t: dealloc)) |
3465 | { |
3466 | /* If the argument is in error it will have already been diagnosed. |
3467 | Avoid issuing redundant errors here. */ |
3468 | *no_add_attrs = true; |
3469 | return NULL_TREE; |
3470 | } |
3471 | |
3472 | STRIP_NOPS (dealloc); |
3473 | if (TREE_CODE (dealloc) == ADDR_EXPR) |
3474 | { |
3475 | /* In C++ the argument may be wrapped in a cast to disambiguate |
3476 | one of a number of overloads (such as operator delete). To |
3477 | make things interesting, the cast looks different between |
3478 | different C++ versions. Strip it and install the attribute |
3479 | with the disambiguated function. */ |
3480 | dealloc = TREE_OPERAND (dealloc, 0); |
3481 | |
3482 | *no_add_attrs = true; |
3483 | tree attr = tree_cons (NULL_TREE, dealloc, TREE_CHAIN (args)); |
3484 | attr = build_tree_list (name, attr); |
3485 | return decl_attributes (node, attr, 0); |
3486 | } |
3487 | |
3488 | if (TREE_CODE (dealloc) != FUNCTION_DECL) |
3489 | { |
3490 | if (TREE_CODE (dealloc) == OVERLOAD) |
3491 | { |
3492 | /* Handle specially the common case of specifying one of a number |
3493 | of overloads, such as operator delete. */ |
3494 | error ("%qE attribute argument 1 is ambiguous" , name); |
3495 | inform (input_location, |
3496 | "use a cast to the expected type to disambiguate" ); |
3497 | *no_add_attrs = true; |
3498 | return NULL_TREE; |
3499 | } |
3500 | |
3501 | error ("%qE attribute argument 1 does not name a function" , name); |
3502 | if (DECL_P (dealloc)) |
3503 | inform (DECL_SOURCE_LOCATION (dealloc), |
3504 | "argument references a symbol declared here" ); |
3505 | *no_add_attrs = true; |
3506 | return NULL_TREE; |
3507 | } |
3508 | |
3509 | /* Mentioning the deallocation function qualifies as its use. */ |
3510 | TREE_USED (dealloc) = 1; |
3511 | |
3512 | tree fntype = TREE_TYPE (dealloc); |
3513 | tree argpos = TREE_CHAIN (args) ? TREE_VALUE (TREE_CHAIN (args)) : NULL_TREE; |
3514 | if (!argpos) |
3515 | { |
3516 | tree argtypes = TYPE_ARG_TYPES (fntype); |
3517 | if (!argtypes) |
3518 | { |
3519 | /* Reject functions without a prototype. */ |
3520 | error ("%qE attribute argument 1 must take a pointer " |
3521 | "type as its first argument" , name); |
3522 | inform (DECL_SOURCE_LOCATION (dealloc), |
3523 | "referenced symbol declared here" ); |
3524 | *no_add_attrs = true; |
3525 | return NULL_TREE; |
3526 | } |
3527 | |
3528 | tree argtype = TREE_VALUE (argtypes); |
3529 | if (TREE_CODE (argtype) != POINTER_TYPE) |
3530 | { |
3531 | /* Reject functions that don't take a pointer as their first |
3532 | argument. */ |
3533 | error ("%qE attribute argument 1 must take a pointer type " |
3534 | "as its first argument; have %qT" , name, argtype); |
3535 | inform (DECL_SOURCE_LOCATION (dealloc), |
3536 | "referenced symbol declared here" ); |
3537 | *no_add_attrs = true; |
3538 | return NULL_TREE; |
3539 | } |
3540 | |
3541 | /* Disable inlining for non-standard deallocators to avoid false |
3542 | positives (or warn if either function is explicitly inline). */ |
3543 | tree at_noinline = |
3544 | maybe_add_noinline (name, alloc_decl: fndecl, dealloc_decl: dealloc, no_add_attrs); |
3545 | if (*no_add_attrs) |
3546 | return NULL_TREE; |
3547 | |
3548 | /* Add attribute *dealloc to the deallocator function associating |
3549 | it with this one. Ideally, the attribute would reference |
3550 | the DECL of the deallocator but since that changes for each |
3551 | redeclaration, use DECL_NAME instead. (DECL_ASSEMBLER_NAME |
3552 | need not be set at this point and setting it here is too early. */ |
3553 | tree attrs = build_tree_list (NULL_TREE, DECL_NAME (fndecl)); |
3554 | attrs = tree_cons (get_identifier ("*dealloc" ), attrs, at_noinline); |
3555 | decl_attributes (&dealloc, attrs, 0); |
3556 | return NULL_TREE; |
3557 | } |
3558 | |
3559 | /* Validate the positional argument. */ |
3560 | argpos = positional_argument (fn: fntype, atname: name, pos&: argpos, code: POINTER_TYPE); |
3561 | if (!argpos) |
3562 | { |
3563 | *no_add_attrs = true; |
3564 | return NULL_TREE; |
3565 | } |
3566 | |
3567 | /* As above, disable inlining for non-standard deallocators to avoid |
3568 | false positives (or warn). */ |
3569 | tree at_noinline = |
3570 | maybe_add_noinline (name, alloc_decl: fndecl, dealloc_decl: dealloc, no_add_attrs); |
3571 | if (*no_add_attrs) |
3572 | return NULL_TREE; |
3573 | |
3574 | /* It's valid to declare the same function with multiple instances |
3575 | of attribute malloc, each naming the same or different deallocator |
3576 | functions, and each referencing either the same or a different |
3577 | positional argument. */ |
3578 | tree attrs = tree_cons (NULL_TREE, argpos, NULL_TREE); |
3579 | attrs = tree_cons (NULL_TREE, DECL_NAME (fndecl), attrs); |
3580 | attrs = tree_cons (get_identifier ("*dealloc" ), attrs, at_noinline); |
3581 | decl_attributes (&dealloc, attrs, 0); |
3582 | return NULL_TREE; |
3583 | } |
3584 | |
3585 | /* Handle the internal "*dealloc" attribute added for functions declared |
3586 | with the one- and two-argument forms of attribute malloc. Add it |
3587 | to *NODE unless it's already there with the same arguments. */ |
3588 | |
3589 | static tree |
3590 | handle_dealloc_attribute (tree *node, tree name, tree args, int, |
3591 | bool *no_add_attrs) |
3592 | { |
3593 | tree fndecl = *node; |
3594 | |
3595 | tree attrs = DECL_ATTRIBUTES (fndecl); |
3596 | if (!attrs) |
3597 | return NULL_TREE; |
3598 | |
3599 | tree arg = TREE_VALUE (args); |
3600 | args = TREE_CHAIN (args); |
3601 | tree arg_pos = args ? TREE_VALUE (args) : integer_zero_node; |
3602 | |
3603 | gcc_checking_assert ((DECL_P (arg) |
3604 | && fndecl_built_in_p (arg, BUILT_IN_NORMAL)) |
3605 | || TREE_CODE (arg) == IDENTIFIER_NODE); |
3606 | |
3607 | const char* const namestr = IDENTIFIER_POINTER (name); |
3608 | for (tree at = attrs; (at = lookup_attribute (attr_name: namestr, list: at)); |
3609 | at = TREE_CHAIN (at)) |
3610 | { |
3611 | tree alloc = TREE_VALUE (at); |
3612 | if (!alloc) |
3613 | continue; |
3614 | |
3615 | tree pos = TREE_CHAIN (alloc); |
3616 | alloc = TREE_VALUE (alloc); |
3617 | pos = pos ? TREE_VALUE (pos) : integer_zero_node; |
3618 | gcc_checking_assert ((DECL_P (alloc) |
3619 | && fndecl_built_in_p (alloc, BUILT_IN_NORMAL)) |
3620 | || TREE_CODE (alloc) == IDENTIFIER_NODE); |
3621 | |
3622 | if (alloc == arg && tree_int_cst_equal (pos, arg_pos)) |
3623 | { |
3624 | /* The function already has the attribute either without any |
3625 | arguments or with the same arguments as the attribute that's |
3626 | being added. Return without adding another copy. */ |
3627 | *no_add_attrs = true; |
3628 | return NULL_TREE; |
3629 | } |
3630 | } |
3631 | |
3632 | return NULL_TREE; |
3633 | } |
3634 | |
3635 | /* Handle the "alloc_size (argpos1 [, argpos2])" function type attribute. |
3636 | *NODE is the type of the function the attribute is being applied to. */ |
3637 | |
3638 | static tree |
3639 | handle_alloc_size_attribute (tree *node, tree name, tree args, |
3640 | int ARG_UNUSED (flags), bool *no_add_attrs) |
3641 | { |
3642 | tree fntype = *node; |
3643 | tree rettype = TREE_TYPE (fntype); |
3644 | if (!POINTER_TYPE_P (rettype)) |
3645 | { |
3646 | warning (OPT_Wattributes, |
3647 | "%qE attribute ignored on a function returning %qT" , |
3648 | name, rettype); |
3649 | *no_add_attrs = true; |
3650 | return NULL_TREE; |
3651 | } |
3652 | |
3653 | tree newargs[2] = { NULL_TREE, NULL_TREE }; |
3654 | for (int i = 1; args; ++i) |
3655 | { |
3656 | tree pos = TREE_VALUE (args); |
3657 | /* NEXT is null when the attribute includes just one argument. |
3658 | That's used to tell positional_argument to avoid mentioning |
3659 | the argument number in diagnostics (since there's just one |
3660 | mentioning it is unnecessary and coule be confusing). */ |
3661 | tree next = TREE_CHAIN (args); |
3662 | if (tree val = positional_argument (fn: fntype, atname: name, pos, code: INTEGER_TYPE, |
3663 | argno: next || i > 1 ? i : 0)) |
3664 | { |
3665 | TREE_VALUE (args) = val; |
3666 | newargs[i - 1] = val; |
3667 | } |
3668 | else |
3669 | { |
3670 | *no_add_attrs = true; |
3671 | return NULL_TREE; |
3672 | } |
3673 | |
3674 | args = next; |
3675 | } |
3676 | |
3677 | if (!validate_attr_args (node, name, newargs)) |
3678 | *no_add_attrs = true; |
3679 | |
3680 | return NULL_TREE; |
3681 | } |
3682 | |
3683 | |
3684 | /* Handle an "alloc_align (argpos)" attribute. */ |
3685 | |
3686 | static tree |
3687 | handle_alloc_align_attribute (tree *node, tree name, tree args, int, |
3688 | bool *no_add_attrs) |
3689 | { |
3690 | tree fntype = *node; |
3691 | tree rettype = TREE_TYPE (fntype); |
3692 | if (!POINTER_TYPE_P (rettype)) |
3693 | { |
3694 | warning (OPT_Wattributes, |
3695 | "%qE attribute ignored on a function returning %qT" , |
3696 | name, rettype); |
3697 | *no_add_attrs = true; |
3698 | return NULL_TREE; |
3699 | } |
3700 | |
3701 | if (tree val = positional_argument (fn: *node, atname: name, TREE_VALUE (args), |
3702 | code: INTEGER_TYPE)) |
3703 | if (validate_attr_arg (node, name, newarg: val)) |
3704 | return NULL_TREE; |
3705 | |
3706 | *no_add_attrs = true; |
3707 | return NULL_TREE; |
3708 | } |
3709 | |
3710 | /* Handle a "assume_aligned" attribute; arguments as in |
3711 | struct attribute_spec.handler. */ |
3712 | |
3713 | static tree |
3714 | handle_assume_aligned_attribute (tree *node, tree name, tree args, int, |
3715 | bool *no_add_attrs) |
3716 | { |
3717 | tree decl = *node; |
3718 | tree rettype = TREE_TYPE (decl); |
3719 | if (TREE_CODE (rettype) != POINTER_TYPE) |
3720 | { |
3721 | warning (OPT_Wattributes, |
3722 | "%qE attribute ignored on a function returning %qT" , |
3723 | name, rettype); |
3724 | *no_add_attrs = true; |
3725 | return NULL_TREE; |
3726 | } |
3727 | |
3728 | /* The alignment specified by the first argument. */ |
3729 | tree align = NULL_TREE; |
3730 | |
3731 | for (; args; args = TREE_CHAIN (args)) |
3732 | { |
3733 | tree val = TREE_VALUE (args); |
3734 | if (val && TREE_CODE (val) != IDENTIFIER_NODE |
3735 | && TREE_CODE (val) != FUNCTION_DECL) |
3736 | val = default_conversion (val); |
3737 | |
3738 | if (!tree_fits_shwi_p (val)) |
3739 | { |
3740 | warning (OPT_Wattributes, |
3741 | "%qE attribute argument %E is not an integer constant" , |
3742 | name, val); |
3743 | *no_add_attrs = true; |
3744 | return NULL_TREE; |
3745 | } |
3746 | else if (tree_int_cst_sgn (val) < 0) |
3747 | { |
3748 | warning (OPT_Wattributes, |
3749 | "%qE attribute argument %E is not positive" , name, val); |
3750 | *no_add_attrs = true; |
3751 | return NULL_TREE; |
3752 | } |
3753 | |
3754 | if (!align) |
3755 | { |
3756 | /* Validate and save the alignment. */ |
3757 | if (!integer_pow2p (val)) |
3758 | { |
3759 | warning (OPT_Wattributes, |
3760 | "%qE attribute argument %E is not a power of 2" , |
3761 | name, val); |
3762 | *no_add_attrs = true; |
3763 | return NULL_TREE; |
3764 | } |
3765 | |
3766 | align = val; |
3767 | } |
3768 | else if (tree_int_cst_le (t1: align, t2: val)) |
3769 | { |
3770 | /* The misalignment specified by the second argument |
3771 | must be non-negative and less than the alignment. */ |
3772 | warning (OPT_Wattributes, |
3773 | "%qE attribute argument %E is not in the range [0, %wu]" , |
3774 | name, val, tree_to_uhwi (align) - 1); |
3775 | *no_add_attrs = true; |
3776 | return NULL_TREE; |
3777 | } |
3778 | } |
3779 | return NULL_TREE; |
3780 | } |
3781 | |
3782 | /* Handle the internal-only "arg spec" attribute. */ |
3783 | |
3784 | static tree |
3785 | handle_argspec_attribute (tree *, tree, tree args, int, bool *) |
3786 | { |
3787 | /* Verify the attribute has one or two arguments and their kind. */ |
3788 | gcc_assert (args && TREE_CODE (TREE_VALUE (args)) == STRING_CST); |
3789 | for (tree next = TREE_CHAIN (args); next; next = TREE_CHAIN (next)) |
3790 | { |
3791 | tree val = TREE_VALUE (next); |
3792 | gcc_assert (DECL_P (val) || EXPR_P (val)); |
3793 | } |
3794 | return NULL_TREE; |
3795 | } |
3796 | |
3797 | /* Handle the internal-only "fn spec" attribute. */ |
3798 | |
3799 | static tree |
3800 | handle_fnspec_attribute (tree *node ATTRIBUTE_UNUSED, tree ARG_UNUSED (name), |
3801 | tree args, int ARG_UNUSED (flags), |
3802 | bool *no_add_attrs ATTRIBUTE_UNUSED) |
3803 | { |
3804 | gcc_assert (args |
3805 | && TREE_CODE (TREE_VALUE (args)) == STRING_CST |
3806 | && !TREE_CHAIN (args)); |
3807 | return NULL_TREE; |
3808 | } |
3809 | |
3810 | /* Handle a "warn_unused" attribute; arguments as in |
3811 | struct attribute_spec.handler. */ |
3812 | |
3813 | static tree |
3814 | handle_warn_unused_attribute (tree *node, tree name, |
3815 | tree args ATTRIBUTE_UNUSED, |
3816 | int flags ATTRIBUTE_UNUSED, bool *no_add_attrs) |
3817 | { |
3818 | if (TYPE_P (*node)) |
3819 | /* Do nothing else, just set the attribute. We'll get at |
3820 | it later with lookup_attribute. */ |
3821 | ; |
3822 | else |
3823 | { |
3824 | warning (OPT_Wattributes, "%qE attribute ignored" , name); |
3825 | *no_add_attrs = true; |
3826 | } |
3827 | |
3828 | return NULL_TREE; |
3829 | } |
3830 | |
3831 | /* Handle an "omp declare simd" attribute; arguments as in |
3832 | struct attribute_spec.handler. */ |
3833 | |
3834 | static tree |
3835 | handle_omp_declare_simd_attribute (tree *, tree, tree, int, bool *) |
3836 | { |
3837 | return NULL_TREE; |
3838 | } |
3839 | |
3840 | /* Handle an "omp declare variant {base,variant}" attribute; arguments as in |
3841 | struct attribute_spec.handler. */ |
3842 | |
3843 | static tree |
3844 | handle_omp_declare_variant_attribute (tree *, tree, tree, int, bool *) |
3845 | { |
3846 | return NULL_TREE; |
3847 | } |
3848 | |
3849 | /* Handle a "simd" attribute. */ |
3850 | |
3851 | static tree |
3852 | handle_simd_attribute (tree *node, tree name, tree args, int, bool *no_add_attrs) |
3853 | { |
3854 | if (TREE_CODE (*node) == FUNCTION_DECL) |
3855 | { |
3856 | tree t = get_identifier ("omp declare simd" ); |
3857 | tree attr = NULL_TREE; |
3858 | if (args) |
3859 | { |
3860 | tree id = TREE_VALUE (args); |
3861 | |
3862 | if (TREE_CODE (id) != STRING_CST) |
3863 | { |
3864 | error ("attribute %qE argument not a string" , name); |
3865 | *no_add_attrs = true; |
3866 | return NULL_TREE; |
3867 | } |
3868 | |
3869 | if (strcmp (TREE_STRING_POINTER (id), s2: "notinbranch" ) == 0) |
3870 | attr = build_omp_clause (DECL_SOURCE_LOCATION (*node), |
3871 | OMP_CLAUSE_NOTINBRANCH); |
3872 | else if (strcmp (TREE_STRING_POINTER (id), s2: "inbranch" ) == 0) |
3873 | attr = build_omp_clause (DECL_SOURCE_LOCATION (*node), |
3874 | OMP_CLAUSE_INBRANCH); |
3875 | else |
3876 | { |
3877 | error ("only %<inbranch%> and %<notinbranch%> flags are " |
3878 | "allowed for %<__simd__%> attribute" ); |
3879 | *no_add_attrs = true; |
3880 | return NULL_TREE; |
3881 | } |
3882 | } |
3883 | |
3884 | DECL_ATTRIBUTES (*node) |
3885 | = tree_cons (t, build_tree_list (NULL_TREE, attr), |
3886 | DECL_ATTRIBUTES (*node)); |
3887 | } |
3888 | else |
3889 | { |
3890 | warning (OPT_Wattributes, "%qE attribute ignored" , name); |
3891 | *no_add_attrs = true; |
3892 | } |
3893 | |
3894 | return NULL_TREE; |
3895 | } |
3896 | |
3897 | /* Handle an "omp declare target" attribute; arguments as in |
3898 | struct attribute_spec.handler. */ |
3899 | |
3900 | static tree |
3901 | handle_omp_declare_target_attribute (tree *, tree, tree, int, bool *) |
3902 | { |
3903 | return NULL_TREE; |
3904 | } |
3905 | |
3906 | /* Handle an "non overlapping" attribute; arguments as in |
3907 | struct attribute_spec.handler. */ |
3908 | |
3909 | static tree |
3910 | handle_non_overlapping_attribute (tree *, tree, tree, int, bool *) |
3911 | { |
3912 | return NULL_TREE; |
3913 | } |
3914 | |
3915 | /* Handle a "returns_twice" attribute; arguments as in |
3916 | struct attribute_spec.handler. */ |
3917 | |
3918 | static tree |
3919 | handle_returns_twice_attribute (tree *node, tree name, tree ARG_UNUSED (args), |
3920 | int ARG_UNUSED (flags), bool *no_add_attrs) |
3921 | { |
3922 | if (TREE_CODE (*node) == FUNCTION_DECL) |
3923 | DECL_IS_RETURNS_TWICE (*node) = 1; |
3924 | else |
3925 | { |
3926 | warning (OPT_Wattributes, "%qE attribute ignored" , name); |
3927 | *no_add_attrs = true; |
3928 | } |
3929 | |
3930 | return NULL_TREE; |
3931 | } |
3932 | |
3933 | /* Handle a "no_limit_stack" attribute; arguments as in |
3934 | struct attribute_spec.handler. */ |
3935 | |
3936 | static tree |
3937 | handle_no_limit_stack_attribute (tree *node, tree name, |
3938 | tree ARG_UNUSED (args), |
3939 | int ARG_UNUSED (flags), |
3940 | bool *no_add_attrs) |
3941 | { |
3942 | tree decl = *node; |
3943 | |
3944 | if (TREE_CODE (decl) != FUNCTION_DECL) |
3945 | { |
3946 | error_at (DECL_SOURCE_LOCATION (decl), |
3947 | "%qE attribute applies only to functions" , name); |
3948 | *no_add_attrs = true; |
3949 | } |
3950 | else if (DECL_INITIAL (decl)) |
3951 | { |
3952 | error_at (DECL_SOURCE_LOCATION (decl), |
3953 | "cannot set %qE attribute after definition" , name); |
3954 | *no_add_attrs = true; |
3955 | } |
3956 | else |
3957 | DECL_NO_LIMIT_STACK (decl) = 1; |
3958 | |
3959 | return NULL_TREE; |
3960 | } |
3961 | |
3962 | /* Handle a "pure" attribute; arguments as in |
3963 | struct attribute_spec.handler. */ |
3964 | |
3965 | static tree |
3966 | handle_pure_attribute (tree *node, tree name, tree ARG_UNUSED (args), |
3967 | int ARG_UNUSED (flags), bool *no_add_attrs) |
3968 | { |
3969 | if (TREE_CODE (*node) == FUNCTION_DECL) |
3970 | { |
3971 | tree type = TREE_TYPE (*node); |
3972 | if (VOID_TYPE_P (TREE_TYPE (type))) |
3973 | warning (OPT_Wattributes, "%qE attribute on function " |
3974 | "returning %<void%>" , name); |
3975 | |
3976 | DECL_PURE_P (*node) = 1; |
3977 | /* ??? TODO: Support types. */ |
3978 | } |
3979 | else |
3980 | { |
3981 | warning (OPT_Wattributes, "%qE attribute ignored" , name); |
3982 | *no_add_attrs = true; |
3983 | } |
3984 | |
3985 | return NULL_TREE; |
3986 | } |
3987 | |
3988 | /* Digest an attribute list destined for a transactional memory statement. |
3989 | ALLOWED is the set of attributes that are allowed for this statement; |
3990 | return the attribute we parsed. Multiple attributes are never allowed. */ |
3991 | |
3992 | int |
3993 | parse_tm_stmt_attr (tree attrs, int allowed) |
3994 | { |
3995 | tree a_seen = NULL; |
3996 | int m_seen = 0; |
3997 | |
3998 | for ( ; attrs ; attrs = TREE_CHAIN (attrs)) |
3999 | { |
4000 | tree a = get_attribute_name (attrs); |
4001 | tree ns = get_attribute_namespace (attrs); |
4002 | int m = 0; |
4003 | |
4004 | if (is_attribute_p (attr_name: "outer" , ident: a) |
4005 | && (ns == NULL_TREE || strcmp (IDENTIFIER_POINTER (ns), s2: "gnu" ) == 0)) |
4006 | m = TM_STMT_ATTR_OUTER; |
4007 | |
4008 | if ((m & allowed) == 0) |
4009 | { |
4010 | warning (OPT_Wattributes, "%qE attribute directive ignored" , a); |
4011 | continue; |
4012 | } |
4013 | |
4014 | if (m_seen == 0) |
4015 | { |
4016 | a_seen = a; |
4017 | m_seen = m; |
4018 | } |
4019 | else if (m_seen == m) |
4020 | warning (OPT_Wattributes, "%qE attribute duplicated" , a); |
4021 | else |
4022 | warning (OPT_Wattributes, "%qE attribute follows %qE" , a, a_seen); |
4023 | } |
4024 | |
4025 | return m_seen; |
4026 | } |
4027 | |
4028 | /* Transform a TM attribute name into a maskable integer and back. |
4029 | Note that NULL (i.e. no attribute) is mapped to UNKNOWN, corresponding |
4030 | to how the lack of an attribute is treated. */ |
4031 | |
4032 | int |
4033 | tm_attr_to_mask (tree attr) |
4034 | { |
4035 | if (attr == NULL) |
4036 | return 0; |
4037 | if (is_attribute_p (attr_name: "transaction_safe" , ident: attr)) |
4038 | return TM_ATTR_SAFE; |
4039 | if (is_attribute_p (attr_name: "transaction_callable" , ident: attr)) |
4040 | return TM_ATTR_CALLABLE; |
4041 | if (is_attribute_p (attr_name: "transaction_pure" , ident: attr)) |
4042 | return TM_ATTR_PURE; |
4043 | if (is_attribute_p (attr_name: "transaction_unsafe" , ident: attr)) |
4044 | return TM_ATTR_IRREVOCABLE; |
4045 | if (is_attribute_p (attr_name: "transaction_may_cancel_outer" , ident: attr)) |
4046 | return TM_ATTR_MAY_CANCEL_OUTER; |
4047 | return 0; |
4048 | } |
4049 | |
4050 | tree |
4051 | tm_mask_to_attr (int mask) |
4052 | { |
4053 | const char *str; |
4054 | switch (mask) |
4055 | { |
4056 | case TM_ATTR_SAFE: |
4057 | str = "transaction_safe" ; |
4058 | break; |
4059 | case TM_ATTR_CALLABLE: |
4060 | str = "transaction_callable" ; |
4061 | break; |
4062 | case TM_ATTR_PURE: |
4063 | str = "transaction_pure" ; |
4064 | break; |
4065 | case TM_ATTR_IRREVOCABLE: |
4066 | str = "transaction_unsafe" ; |
4067 | break; |
4068 | case TM_ATTR_MAY_CANCEL_OUTER: |
4069 | str = "transaction_may_cancel_outer" ; |
4070 | break; |
4071 | default: |
4072 | gcc_unreachable (); |
4073 | } |
4074 | return get_identifier (str); |
4075 | } |
4076 | |
4077 | /* Return the first TM attribute seen in LIST. */ |
4078 | |
4079 | tree |
4080 | find_tm_attribute (tree list) |
4081 | { |
4082 | for (; list ; list = TREE_CHAIN (list)) |
4083 | { |
4084 | tree name = get_attribute_name (list); |
4085 | if (tm_attr_to_mask (attr: name) != 0) |
4086 | return name; |
4087 | } |
4088 | return NULL_TREE; |
4089 | } |
4090 | |
4091 | /* Handle the TM attributes; arguments as in struct attribute_spec.handler. |
4092 | Here we accept only function types, and verify that none of the other |
4093 | function TM attributes are also applied. */ |
4094 | /* ??? We need to accept class types for C++, but not C. This greatly |
4095 | complicates this function, since we can no longer rely on the extra |
4096 | processing given by function_type_required. */ |
4097 | |
4098 | static tree |
4099 | handle_tm_attribute (tree *node, tree name, tree args, |
4100 | int flags, bool *no_add_attrs) |
4101 | { |
4102 | /* Only one path adds the attribute; others don't. */ |
4103 | *no_add_attrs = true; |
4104 | |
4105 | switch (TREE_CODE (*node)) |
4106 | { |
4107 | case RECORD_TYPE: |
4108 | case UNION_TYPE: |
4109 | /* Only tm_callable and tm_safe apply to classes. */ |
4110 | if (tm_attr_to_mask (attr: name) & ~(TM_ATTR_SAFE | TM_ATTR_CALLABLE)) |
4111 | goto ignored; |
4112 | /* FALLTHRU */ |
4113 | |
4114 | case FUNCTION_TYPE: |
4115 | case METHOD_TYPE: |
4116 | { |
4117 | tree old_name = find_tm_attribute (TYPE_ATTRIBUTES (*node)); |
4118 | if (old_name == name) |
4119 | ; |
4120 | else if (old_name != NULL_TREE) |
4121 | error ("type was previously declared %qE" , old_name); |
4122 | else |
4123 | *no_add_attrs = false; |
4124 | } |
4125 | break; |
4126 | |
4127 | case FUNCTION_DECL: |
4128 | { |
4129 | /* transaction_safe_dynamic goes on the FUNCTION_DECL, but we also |
4130 | want to set transaction_safe on the type. */ |
4131 | gcc_assert (is_attribute_p ("transaction_safe_dynamic" , name)); |
4132 | if (!TYPE_P (DECL_CONTEXT (*node))) |
4133 | error_at (DECL_SOURCE_LOCATION (*node), |
4134 | "%<transaction_safe_dynamic%> may only be specified for " |
4135 | "a virtual function" ); |
4136 | *no_add_attrs = false; |
4137 | decl_attributes (&TREE_TYPE (*node), |
4138 | build_tree_list (get_identifier ("transaction_safe" ), |
4139 | NULL_TREE), |
4140 | 0); |
4141 | break; |
4142 | } |
4143 | |
4144 | case POINTER_TYPE: |
4145 | { |
4146 | enum tree_code subcode = TREE_CODE (TREE_TYPE (*node)); |
4147 | if (subcode == FUNCTION_TYPE || subcode == METHOD_TYPE) |
4148 | { |
4149 | tree fn_tmp = TREE_TYPE (*node); |
4150 | decl_attributes (&fn_tmp, tree_cons (name, args, NULL), 0); |
4151 | *node = build_pointer_type (fn_tmp); |
4152 | break; |
4153 | } |
4154 | } |
4155 | /* FALLTHRU */ |
4156 | |
4157 | default: |
4158 | /* If a function is next, pass it on to be tried next. */ |
4159 | if (flags & (int) ATTR_FLAG_FUNCTION_NEXT) |
4160 | return tree_cons (name, args, NULL); |
4161 | |
4162 | ignored: |
4163 | warning (OPT_Wattributes, "%qE attribute ignored" , name); |
4164 | break; |
4165 | } |
4166 | |
4167 | return NULL_TREE; |
4168 | } |
4169 | |
4170 | /* Handle the TM_WRAP attribute; arguments as in |
4171 | struct attribute_spec.handler. */ |
4172 | |
4173 | static tree |
4174 | handle_tm_wrap_attribute (tree *node, tree name, tree args, |
4175 | int ARG_UNUSED (flags), bool *no_add_attrs) |
4176 | { |
4177 | tree decl = *node; |
4178 | |
4179 | /* We don't need the attribute even on success, since we |
4180 | record the entry in an external table. */ |
4181 | *no_add_attrs = true; |
4182 | |
4183 | if (TREE_CODE (decl) != FUNCTION_DECL) |
4184 | warning (OPT_Wattributes, "%qE attribute ignored" , name); |
4185 | else |
4186 | { |
4187 | tree wrap_decl = TREE_VALUE (args); |
4188 | if (error_operand_p (t: wrap_decl)) |
4189 | ; |
4190 | else if (TREE_CODE (wrap_decl) != IDENTIFIER_NODE |
4191 | && !VAR_OR_FUNCTION_DECL_P (wrap_decl)) |
4192 | error ("%qE argument not an identifier" , name); |
4193 | else |
4194 | { |
4195 | if (TREE_CODE (wrap_decl) == IDENTIFIER_NODE) |
4196 | wrap_decl = lookup_name (wrap_decl); |
4197 | if (wrap_decl && TREE_CODE (wrap_decl) == FUNCTION_DECL) |
4198 | { |
4199 | if (lang_hooks.types_compatible_p (TREE_TYPE (decl), |
4200 | TREE_TYPE (wrap_decl))) |
4201 | record_tm_replacement (wrap_decl, decl); |
4202 | else |
4203 | error ("%qD is not compatible with %qD" , wrap_decl, decl); |
4204 | } |
4205 | else |
4206 | error ("%qE argument is not a function" , name); |
4207 | } |
4208 | } |
4209 | |
4210 | return NULL_TREE; |
4211 | } |
4212 | |
4213 | /* Ignore the given attribute. Used when this attribute may be usefully |
4214 | overridden by the target, but is not used generically. */ |
4215 | |
4216 | static tree |
4217 | ignore_attribute (tree * ARG_UNUSED (node), tree ARG_UNUSED (name), |
4218 | tree ARG_UNUSED (args), int ARG_UNUSED (flags), |
4219 | bool *no_add_attrs) |
4220 | { |
4221 | *no_add_attrs = true; |
4222 | return NULL_TREE; |
4223 | } |
4224 | |
4225 | /* Handle a "no vops" attribute; arguments as in |
4226 | struct attribute_spec.handler. */ |
4227 | |
4228 | static tree |
4229 | handle_novops_attribute (tree *node, tree ARG_UNUSED (name), |
4230 | tree ARG_UNUSED (args), int ARG_UNUSED (flags), |
4231 | bool *ARG_UNUSED (no_add_attrs)) |
4232 | { |
4233 | gcc_assert (TREE_CODE (*node) == FUNCTION_DECL); |
4234 | DECL_IS_NOVOPS (*node) = 1; |
4235 | return NULL_TREE; |
4236 | } |
4237 | |
4238 | /* Handle a "deprecated" attribute; arguments as in |
4239 | struct attribute_spec.handler. */ |
4240 | |
4241 | tree |
4242 | handle_deprecated_attribute (tree *node, tree name, |
4243 | tree args, int flags, |
4244 | bool *no_add_attrs) |
4245 | { |
4246 | tree type = NULL_TREE; |
4247 | int warn = 0; |
4248 | tree what = NULL_TREE; |
4249 | |
4250 | if (!args) |
4251 | *no_add_attrs = true; |
4252 | else if (TREE_CODE (TREE_VALUE (args)) != STRING_CST) |
4253 | { |
4254 | error ("deprecated message is not a string" ); |
4255 | *no_add_attrs = true; |
4256 | } |
4257 | |
4258 | if (DECL_P (*node)) |
4259 | { |
4260 | tree decl = *node; |
4261 | type = TREE_TYPE (decl); |
4262 | |
4263 | if (TREE_CODE (decl) == TYPE_DECL |
4264 | || TREE_CODE (decl) == PARM_DECL |
4265 | || VAR_OR_FUNCTION_DECL_P (decl) |
4266 | || TREE_CODE (decl) == FIELD_DECL |
4267 | || TREE_CODE (decl) == CONST_DECL |
4268 | || objc_method_decl (TREE_CODE (decl)) |
4269 | || TREE_CODE (decl) == CONCEPT_DECL) |
4270 | TREE_DEPRECATED (decl) = 1; |
4271 | else if (TREE_CODE (decl) == LABEL_DECL) |
4272 | { |
4273 | pedwarn (input_location, OPT_Wattributes, "%qE attribute ignored" , |
4274 | name); |
4275 | *no_add_attrs = true; |
4276 | return NULL_TREE; |
4277 | } |
4278 | else |
4279 | warn = 1; |
4280 | } |
4281 | else if (TYPE_P (*node)) |
4282 | { |
4283 | if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE)) |
4284 | *node = build_variant_type_copy (*node); |
4285 | TREE_DEPRECATED (*node) = 1; |
4286 | type = *node; |
4287 | } |
4288 | else |
4289 | warn = 1; |
4290 | |
4291 | if (warn) |
4292 | { |
4293 | *no_add_attrs = true; |
4294 | if (type && TYPE_NAME (type)) |
4295 | { |
4296 | if (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE) |
4297 | what = TYPE_NAME (type); |
4298 | else if (TREE_CODE (TYPE_NAME (type)) == TYPE_DECL |
4299 | && DECL_NAME (TYPE_NAME (type))) |
4300 | what = DECL_NAME (TYPE_NAME (type)); |
4301 | } |
4302 | if (what) |
4303 | warning (OPT_Wattributes, "%qE attribute ignored for %qE" , name, what); |
4304 | else |
4305 | warning (OPT_Wattributes, "%qE attribute ignored" , name); |
4306 | } |
4307 | |
4308 | return NULL_TREE; |
4309 | } |
4310 | |
4311 | /* Handle a "unavailable" attribute; arguments as in |
4312 | struct attribute_spec.handler. */ |
4313 | |
4314 | static tree |
4315 | handle_unavailable_attribute (tree *node, tree name, |
4316 | tree args, int flags, |
4317 | bool *no_add_attrs) |
4318 | { |
4319 | tree type = NULL_TREE; |
4320 | int warn = 0; |
4321 | tree what = NULL_TREE; |
4322 | |
4323 | if (!args) |
4324 | *no_add_attrs = true; |
4325 | else if (TREE_CODE (TREE_VALUE (args)) != STRING_CST) |
4326 | { |
4327 | error ("the message attached to %<unavailable%> is not a string" ); |
4328 | *no_add_attrs = true; |
4329 | } |
4330 | |
4331 | if (DECL_P (*node)) |
4332 | { |
4333 | tree decl = *node; |
4334 | type = TREE_TYPE (decl); |
4335 | |
4336 | if (TREE_CODE (decl) == TYPE_DECL |
4337 | || TREE_CODE (decl) == PARM_DECL |
4338 | || VAR_OR_FUNCTION_DECL_P (decl) |
4339 | || TREE_CODE (decl) == FIELD_DECL |
4340 | || TREE_CODE (decl) == CONST_DECL |
4341 | || objc_method_decl (TREE_CODE (decl))) |
4342 | TREE_UNAVAILABLE (decl) = 1; |
4343 | else |
4344 | warn = 1; |
4345 | } |
4346 | else if (TYPE_P (*node)) |
4347 | { |
4348 | if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE)) |
4349 | *node = build_variant_type_copy (*node); |
4350 | TREE_UNAVAILABLE (*node) = 1; |
4351 | type = *node; |
4352 | } |
4353 | else |
4354 | warn = 1; |
4355 | |
4356 | if (warn) |
4357 | { |
4358 | *no_add_attrs = true; |
4359 | if (type && TYPE_NAME (type)) |
4360 | { |
4361 | if (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE) |
4362 | what = TYPE_NAME (*node); |
4363 | else if (TREE_CODE (TYPE_NAME (type)) == TYPE_DECL |
4364 | && DECL_NAME (TYPE_NAME (type))) |
4365 | what = DECL_NAME (TYPE_NAME (type)); |
4366 | } |
4367 | if (what) |
4368 | warning (OPT_Wattributes, "%qE attribute ignored for %qE" , name, what); |
4369 | else |
4370 | warning (OPT_Wattributes, "%qE attribute ignored" , name); |
4371 | } |
4372 | |
4373 | return NULL_TREE; |
4374 | } |
4375 | |
4376 | /* Return the "base" type from TYPE that is suitable to apply attribute |
4377 | vector_size to by stripping arrays, function types, etc. */ |
4378 | static tree |
4379 | type_for_vector_size (tree type) |
4380 | { |
4381 | /* We need to provide for vector pointers, vector arrays, and |
4382 | functions returning vectors. For example: |
4383 | |
4384 | __attribute__((vector_size(16))) short *foo; |
4385 | |
4386 | In this case, the mode is SI, but the type being modified is |
4387 | HI, so we need to look further. */ |
4388 | |
4389 | while (POINTER_TYPE_P (type) |
4390 | || TREE_CODE (type) == FUNCTION_TYPE |
4391 | || TREE_CODE (type) == METHOD_TYPE |
4392 | || TREE_CODE (type) == ARRAY_TYPE |
4393 | || TREE_CODE (type) == OFFSET_TYPE) |
4394 | type = TREE_TYPE (type); |
4395 | |
4396 | return type; |
4397 | } |
4398 | |
4399 | /* Given TYPE, return the base type to which the vector_size attribute |
4400 | ATNAME with ARGS, when non-null, can be applied, if one exists. |
4401 | On success and when both ARGS and PTRNUNITS are non-null, set |
4402 | *PTRNUNINTS to the number of vector units. When PTRNUNITS is not |
4403 | null, issue a warning when the attribute argument is not constant |
4404 | and an error if there is no such type. Otherwise issue a warning |
4405 | in the latter case and return null. */ |
4406 | |
4407 | static tree |
4408 | type_valid_for_vector_size (tree type, tree atname, tree args, |
4409 | unsigned HOST_WIDE_INT *ptrnunits) |
4410 | { |
4411 | bool error_p = ptrnunits != NULL; |
4412 | |
4413 | /* Get the mode of the type being modified. */ |
4414 | machine_mode orig_mode = TYPE_MODE (type); |
4415 | |
4416 | if ((!INTEGRAL_TYPE_P (type) |
4417 | && !SCALAR_FLOAT_TYPE_P (type) |
4418 | && !FIXED_POINT_TYPE_P (type)) |
4419 | || (!SCALAR_FLOAT_MODE_P (orig_mode) |
4420 | && GET_MODE_CLASS (orig_mode) != MODE_INT |
4421 | && !ALL_SCALAR_FIXED_POINT_MODE_P (orig_mode)) |
4422 | || !tree_fits_uhwi_p (TYPE_SIZE_UNIT (type)) |
4423 | || TREE_CODE (type) == BOOLEAN_TYPE |
4424 | || TREE_CODE (type) == BITINT_TYPE) |
4425 | { |
4426 | if (error_p) |
4427 | error ("invalid vector type for attribute %qE" , atname); |
4428 | else |
4429 | warning (OPT_Wattributes, "invalid vector type for attribute %qE" , |
4430 | atname); |
4431 | return NULL_TREE; |
4432 | } |
4433 | |
4434 | /* When no argument has been provided this is just a request to validate |
4435 | the type above. Return TYPE to indicate success. */ |
4436 | if (!args) |
4437 | return type; |
4438 | |
4439 | tree size = TREE_VALUE (args); |
4440 | /* Erroneous arguments have already been diagnosed. */ |
4441 | if (size == error_mark_node) |
4442 | return NULL_TREE; |
4443 | |
4444 | if (size && TREE_CODE (size) != IDENTIFIER_NODE |
4445 | && TREE_CODE (size) != FUNCTION_DECL) |
4446 | size = default_conversion (size); |
4447 | |
4448 | if (TREE_CODE (size) != INTEGER_CST) |
4449 | { |
4450 | if (error_p) |
4451 | error ("%qE attribute argument value %qE is not an integer constant" , |
4452 | atname, size); |
4453 | else |
4454 | warning (OPT_Wattributes, |
4455 | "%qE attribute argument value %qE is not an integer constant" , |
4456 | atname, size); |
4457 | return NULL_TREE; |
4458 | } |
4459 | |
4460 | if (!TYPE_UNSIGNED (TREE_TYPE (size)) |
4461 | && tree_int_cst_sgn (size) < 0) |
4462 | { |
4463 | if (error_p) |
4464 | error ("%qE attribute argument value %qE is negative" , |
4465 | atname, size); |
4466 | else |
4467 | warning (OPT_Wattributes, |
4468 | "%qE attribute argument value %qE is negative" , |
4469 | atname, size); |
4470 | return NULL_TREE; |
4471 | } |
4472 | |
4473 | /* The attribute argument value is constrained by the maximum bit |
4474 | alignment representable in unsigned int on the host. */ |
4475 | unsigned HOST_WIDE_INT vecsize; |
4476 | unsigned HOST_WIDE_INT maxsize = tree_to_uhwi (max_object_size ()); |
4477 | if (!tree_fits_uhwi_p (size) |
4478 | || (vecsize = tree_to_uhwi (size)) > maxsize) |
4479 | { |
4480 | if (error_p) |
4481 | error ("%qE attribute argument value %qE exceeds %wu" , |
4482 | atname, size, maxsize); |
4483 | else |
4484 | warning (OPT_Wattributes, |
4485 | "%qE attribute argument value %qE exceeds %wu" , |
4486 | atname, size, maxsize); |
4487 | return NULL_TREE; |
4488 | } |
4489 | |
4490 | if (vecsize % tree_to_uhwi (TYPE_SIZE_UNIT (type))) |
4491 | { |
4492 | if (error_p) |
4493 | error ("vector size not an integral multiple of component size" ); |
4494 | return NULL_TREE; |
4495 | } |
4496 | |
4497 | if (vecsize == 0) |
4498 | { |
4499 | error ("zero vector size" ); |
4500 | return NULL; |
4501 | } |
4502 | |
4503 | /* Calculate how many units fit in the vector. */ |
4504 | unsigned HOST_WIDE_INT nunits = vecsize / tree_to_uhwi (TYPE_SIZE_UNIT (type)); |
4505 | if (nunits & (nunits - 1)) |
4506 | { |
4507 | if (error_p) |
4508 | error ("number of vector components %wu not a power of two" , nunits); |
4509 | else |
4510 | warning (OPT_Wattributes, |
4511 | "number of vector components %wu not a power of two" , nunits); |
4512 | return NULL_TREE; |
4513 | } |
4514 | |
4515 | if (nunits >= (unsigned HOST_WIDE_INT)INT_MAX) |
4516 | { |
4517 | if (error_p) |
4518 | error ("number of vector components %wu exceeds %d" , |
4519 | nunits, INT_MAX - 1); |
4520 | else |
4521 | warning (OPT_Wattributes, |
4522 | "number of vector components %wu exceeds %d" , |
4523 | nunits, INT_MAX - 1); |
4524 | return NULL_TREE; |
4525 | } |
4526 | |
4527 | if (ptrnunits) |
4528 | *ptrnunits = nunits; |
4529 | |
4530 | return type; |
4531 | } |
4532 | |
4533 | /* Handle a "vector_size" attribute; arguments as in |
4534 | struct attribute_spec.handler. */ |
4535 | |
4536 | static tree |
4537 | handle_vector_size_attribute (tree *node, tree name, tree args, |
4538 | int ARG_UNUSED (flags), |
4539 | bool *no_add_attrs) |
4540 | { |
4541 | *no_add_attrs = true; |
4542 | |
4543 | /* Determine the "base" type to apply the attribute to. */ |
4544 | tree type = type_for_vector_size (type: *node); |
4545 | |
4546 | /* Get the vector size (in bytes) and let the function compute |
4547 | the number of vector units. */ |
4548 | unsigned HOST_WIDE_INT nunits; |
4549 | type = type_valid_for_vector_size (type, atname: name, args, ptrnunits: &nunits); |
4550 | if (!type) |
4551 | return NULL_TREE; |
4552 | |
4553 | gcc_checking_assert (args != NULL); |
4554 | |
4555 | tree new_type = build_vector_type (type, nunits); |
4556 | |
4557 | /* Build back pointers if needed. */ |
4558 | *node = lang_hooks.types.reconstruct_complex_type (*node, new_type); |
4559 | |
4560 | return NULL_TREE; |
4561 | } |
4562 | |
4563 | /* Handle a "vector_mask" attribute; arguments as in |
4564 | struct attribute_spec.handler. */ |
4565 | |
4566 | static tree |
4567 | handle_vector_mask_attribute (tree *node, tree name, tree, |
4568 | int ARG_UNUSED (flags), |
4569 | bool *no_add_attrs) |
4570 | { |
4571 | *no_add_attrs = true; |
4572 | if (!flag_gimple) |
4573 | { |
4574 | warning (OPT_Wattributes, "%qE attribute ignored" , name); |
4575 | return NULL_TREE; |
4576 | } |
4577 | |
4578 | /* Determine the "base" type to apply the attribute to. */ |
4579 | tree type = type_for_vector_size (type: *node); |
4580 | if (!VECTOR_TYPE_P (type) || VECTOR_BOOLEAN_TYPE_P (type)) |
4581 | { |
4582 | warning (OPT_Wattributes, "%qE attribute only supported on " |
4583 | "non-mask vector types" , name); |
4584 | return NULL_TREE; |
4585 | } |
4586 | |
4587 | tree new_type = truth_type_for (type); |
4588 | |
4589 | /* Build back pointers if needed. */ |
4590 | *node = lang_hooks.types.reconstruct_complex_type (*node, new_type); |
4591 | |
4592 | return NULL_TREE; |
4593 | } |
4594 | |
4595 | /* Handle the "nonnull" attribute. */ |
4596 | |
4597 | static tree |
4598 | handle_nonnull_attribute (tree *node, tree name, |
4599 | tree args, int ARG_UNUSED (flags), |
4600 | bool *no_add_attrs) |
4601 | { |
4602 | tree type = *node; |
4603 | |
4604 | /* If no arguments are specified, all pointer arguments should be |
4605 | non-null. Verify a full prototype is given so that the arguments |
4606 | will have the correct types when we actually check them later. |
4607 | Avoid diagnosing type-generic built-ins since those have no |
4608 | prototype. */ |
4609 | if (!args) |
4610 | { |
4611 | if (!prototype_p (type) |
4612 | && (!TYPE_ATTRIBUTES (type) |
4613 | || !lookup_attribute (attr_name: "type generic" , TYPE_ATTRIBUTES (type)))) |
4614 | { |
4615 | error ("%qE attribute without arguments on a non-prototype" , |
4616 | name); |
4617 | *no_add_attrs = true; |
4618 | } |
4619 | return NULL_TREE; |
4620 | } |
4621 | |
4622 | for (int i = 1; args; ++i) |
4623 | { |
4624 | tree pos = TREE_VALUE (args); |
4625 | /* NEXT is null when the attribute includes just one argument. |
4626 | That's used to tell positional_argument to avoid mentioning |
4627 | the argument number in diagnostics (since there's just one |
4628 | mentioning it is unnecessary and coule be confusing). */ |
4629 | tree next = TREE_CHAIN (args); |
4630 | if (tree val = positional_argument (fn: type, atname: name, pos, code: POINTER_TYPE, |
4631 | argno: next || i > 1 ? i : 0)) |
4632 | TREE_VALUE (args) = val; |
4633 | else |
4634 | { |
4635 | *no_add_attrs = true; |
4636 | break; |
4637 | } |
4638 | args = next; |
4639 | } |
4640 | |
4641 | return NULL_TREE; |
4642 | } |
4643 | |
4644 | /* Handle the "fd_arg", "fd_arg_read" and "fd_arg_write" attributes */ |
4645 | |
4646 | static tree |
4647 | handle_fd_arg_attribute (tree *node, tree name, tree args, |
4648 | int ARG_UNUSED (flags), bool *no_add_attrs) |
4649 | { |
4650 | tree type = *node; |
4651 | if (!args) |
4652 | { |
4653 | if (!prototype_p (type)) |
4654 | { |
4655 | error ("%qE attribute without arguments on a non-prototype" , name); |
4656 | *no_add_attrs = true; |
4657 | } |
4658 | return NULL_TREE; |
4659 | } |
4660 | |
4661 | if (positional_argument (fn: *node, atname: name, TREE_VALUE (args), code: INTEGER_TYPE)) |
4662 | return NULL_TREE; |
4663 | |
4664 | *no_add_attrs = true; |
4665 | return NULL_TREE; |
4666 | } |
4667 | |
4668 | /* Handle the "null_terminated_string_arg" attribute. */ |
4669 | |
4670 | static tree |
4671 | handle_null_terminated_string_arg_attribute (tree *node, tree name, tree args, |
4672 | int ARG_UNUSED (flags), |
4673 | bool *no_add_attrs) |
4674 | { |
4675 | if (positional_argument (fn: *node, atname: name, TREE_VALUE (args), code: POINTER_TYPE)) |
4676 | return NULL_TREE; |
4677 | |
4678 | *no_add_attrs = true; |
4679 | return NULL_TREE; |
4680 | } |
4681 | |
4682 | /* Handle the "nonstring" variable attribute. */ |
4683 | |
4684 | static tree |
4685 | handle_nonstring_attribute (tree *node, tree name, tree ARG_UNUSED (args), |
4686 | int ARG_UNUSED (flags), bool *no_add_attrs) |
4687 | { |
4688 | gcc_assert (!args); |
4689 | tree_code code = TREE_CODE (*node); |
4690 | |
4691 | if (VAR_P (*node) |
4692 | || code == FIELD_DECL |
4693 | || code == PARM_DECL) |
4694 | { |
4695 | tree type = TREE_TYPE (*node); |
4696 | |
4697 | if (POINTER_TYPE_P (type) || TREE_CODE (type) == ARRAY_TYPE) |
4698 | { |
4699 | /* Accept the attribute on arrays and pointers to all three |
4700 | narrow character types. */ |
4701 | tree eltype = TREE_TYPE (type); |
4702 | eltype = TYPE_MAIN_VARIANT (eltype); |
4703 | if (eltype == char_type_node |
4704 | || eltype == signed_char_type_node |
4705 | || eltype == unsigned_char_type_node) |
4706 | return NULL_TREE; |
4707 | } |
4708 | |
4709 | warning (OPT_Wattributes, |
4710 | "%qE attribute ignored on objects of type %qT" , |
4711 | name, type); |
4712 | *no_add_attrs = true; |
4713 | return NULL_TREE; |
4714 | } |
4715 | |
4716 | if (code == FUNCTION_DECL) |
4717 | warning (OPT_Wattributes, |
4718 | "%qE attribute does not apply to functions" , name); |
4719 | else if (code == TYPE_DECL) |
4720 | warning (OPT_Wattributes, |
4721 | "%qE attribute does not apply to types" , name); |
4722 | else |
4723 | warning (OPT_Wattributes, "%qE attribute ignored" , name); |
4724 | |
4725 | *no_add_attrs = true; |
4726 | return NULL_TREE; |
4727 | } |
4728 | |
4729 | /* Given a function type FUNCTYPE, returns the type of the parameter |
4730 | ARGNO or null if ARGNO exceeds the number of parameters. On failure |
4731 | set *NARGS to the number of function parameters. */ |
4732 | |
4733 | static tree |
4734 | get_argument_type (tree functype, unsigned argno, unsigned *nargs) |
4735 | { |
4736 | function_args_iterator iter; |
4737 | function_args_iter_init (i: &iter, fntype: functype); |
4738 | |
4739 | unsigned count = 0; |
4740 | |
4741 | for ( ; iter.next; ++count, function_args_iter_next (i: &iter)) |
4742 | { |
4743 | if (count + 1 == argno) |
4744 | { |
4745 | tree argtype = function_args_iter_cond (i: &iter); |
4746 | if (VOID_TYPE_P (argtype)) |
4747 | break; |
4748 | if (argtype != error_mark_node) |
4749 | return argtype; |
4750 | } |
4751 | } |
4752 | |
4753 | *nargs = count; |
4754 | return NULL_TREE; |
4755 | } |
4756 | |
4757 | /* Given a function FNDECL return the function argument at the zero- |
4758 | based position ARGNO or null if it can't be found. */ |
4759 | |
4760 | static tree |
4761 | get_argument (tree fndecl, unsigned argno) |
4762 | { |
4763 | if (!DECL_P (fndecl)) |
4764 | return NULL_TREE; |
4765 | |
4766 | unsigned i = 0; |
4767 | for (tree arg = DECL_ARGUMENTS (fndecl); arg; arg = TREE_CHAIN (arg)) |
4768 | if (i++ == argno) |
4769 | return arg; |
4770 | |
4771 | return NULL_TREE; |
4772 | } |
4773 | |
4774 | /* Attempt to append attribute access specification ATTRSPEC, optionally |
4775 | described by the human-readable string ATTRSTR, for type T, to one in |
4776 | ATTRS. VBLIST is an optional list of bounds of variable length array |
4777 | parameters described by ATTRSTR. |
4778 | Issue warning for conflicts and return null if any are found. |
4779 | Return the concatenated access string on success. */ |
4780 | |
4781 | static tree |
4782 | append_access_attr (tree node[3], tree attrs, const char *attrstr, |
4783 | const char *attrspec, tree vblist = NULL_TREE) |
4784 | { |
4785 | tree argstr = build_string (strlen (s: attrspec) + 1, attrspec); |
4786 | tree ataccess = tree_cons (NULL_TREE, argstr, vblist); |
4787 | ataccess = tree_cons (get_identifier ("access" ), ataccess, NULL_TREE); |
4788 | |
4789 | /* The access specification being applied. This may be an implicit |
4790 | access spec synthesized for array (or VLA) parameters even for |
4791 | a declaration with an explicit access spec already applied, if |
4792 | this call corresponds to the first declaration of the function. */ |
4793 | rdwr_map new_idxs; |
4794 | init_attr_rdwr_indices (&new_idxs, ataccess); |
4795 | |
4796 | /* The current access specification alrady applied. */ |
4797 | rdwr_map cur_idxs; |
4798 | init_attr_rdwr_indices (&cur_idxs, attrs); |
4799 | |
4800 | tree args = TYPE_ARG_TYPES (node[0]); |
4801 | int argpos = 0; |
4802 | std::string spec; |
4803 | for (tree arg = args; arg; arg = TREE_CHAIN (arg), argpos++) |
4804 | { |
4805 | const attr_access* const newa = new_idxs.get (k: argpos); |
4806 | |
4807 | if (!newa) |
4808 | continue; |
4809 | |
4810 | /* The map has two equal entries for each pointer argument that |
4811 | has an associated size argument. Process just the entry for |
4812 | the former. */ |
4813 | if ((unsigned)argpos != newa->ptrarg) |
4814 | continue; |
4815 | |
4816 | const attr_access* const cura = cur_idxs.get (k: argpos); |
4817 | if (!cura) |
4818 | { |
4819 | /* The new attribute needs to be added. */ |
4820 | tree str = newa->to_internal_string (); |
4821 | spec += TREE_STRING_POINTER (str); |
4822 | continue; |
4823 | } |
4824 | |
4825 | /* The new access spec refers to an array/pointer argument for |
4826 | which an access spec already exists. Check and diagnose any |
4827 | conflicts. If no conflicts are found, merge the two. */ |
4828 | |
4829 | if (!attrstr) |
4830 | { |
4831 | tree str = NULL_TREE; |
4832 | if (newa->mode != access_deferred) |
4833 | str = newa->to_external_string (); |
4834 | else if (cura->mode != access_deferred) |
4835 | str = cura->to_external_string (); |
4836 | if (str) |
4837 | attrstr = TREE_STRING_POINTER (str); |
4838 | } |
4839 | |
4840 | location_t curloc = input_location; |
4841 | if (node[2] && DECL_P (node[2])) |
4842 | curloc = DECL_SOURCE_LOCATION (node[2]); |
4843 | |
4844 | location_t prevloc = UNKNOWN_LOCATION; |
4845 | if (node[1] && DECL_P (node[1])) |
4846 | prevloc = DECL_SOURCE_LOCATION (node[1]); |
4847 | |
4848 | if (newa->mode != cura->mode |
4849 | && newa->mode != access_deferred |
4850 | && cura->mode != access_deferred |
4851 | && newa->internal_p == cura->internal_p) |
4852 | { |
4853 | /* Mismatch in access mode. */ |
4854 | auto_diagnostic_group d; |
4855 | if (warning_at (curloc, OPT_Wattributes, |
4856 | "attribute %qs mismatch with mode %qs" , |
4857 | attrstr, cura->mode_names[cura->mode]) |
4858 | && prevloc != UNKNOWN_LOCATION) |
4859 | inform (prevloc, "previous declaration here" ); |
4860 | continue; |
4861 | } |
4862 | |
4863 | /* Set if PTRARG refers to a VLA with an unspecified bound (T[*]). |
4864 | Be prepared for either CURA or NEWA to refer to it, depending |
4865 | on which happens to come first in the declaration. */ |
4866 | const bool cur_vla_ub = (cura->internal_p |
4867 | && cura->sizarg == UINT_MAX |
4868 | && cura->minsize == HOST_WIDE_INT_M1U); |
4869 | const bool new_vla_ub = (newa->internal_p |
4870 | && newa->sizarg == UINT_MAX |
4871 | && newa->minsize == HOST_WIDE_INT_M1U); |
4872 | |
4873 | if (newa->sizarg != cura->sizarg |
4874 | && attrstr |
4875 | && (!(cur_vla_ub ^ new_vla_ub) |
4876 | || (!cura->internal_p && !newa->internal_p))) |
4877 | { |
4878 | /* Avoid diagnosing redeclarations of functions with no explicit |
4879 | attribute access that add one. */ |
4880 | if (newa->mode == access_deferred |
4881 | && cura->mode != access_deferred |
4882 | && newa->sizarg == UINT_MAX |
4883 | && cura->sizarg != UINT_MAX) |
4884 | continue; |
4885 | |
4886 | if (cura->mode == access_deferred |
4887 | && newa->mode != access_deferred |
4888 | && cura->sizarg == UINT_MAX |
4889 | && newa->sizarg != UINT_MAX) |
4890 | continue; |
4891 | |
4892 | /* The two specs designate different size arguments. It's okay |
4893 | for the explicit spec to specify a size where none is provided |
4894 | by the implicit (VLA) one, as in: |
4895 | __attribute__ ((access (read_write, 1, 2))) |
4896 | void f (int*, int); |
4897 | but not for two explicit access attributes to do that. */ |
4898 | bool warned = false; |
4899 | |
4900 | auto_diagnostic_group d; |
4901 | |
4902 | if (newa->sizarg == UINT_MAX) |
4903 | /* Mismatch in the presence of the size argument. */ |
4904 | warned = warning_at (curloc, OPT_Wattributes, |
4905 | "attribute %qs missing positional argument 2 " |
4906 | "provided in previous designation by argument " |
4907 | "%u" , attrstr, cura->sizarg + 1); |
4908 | else if (cura->sizarg == UINT_MAX) |
4909 | /* Mismatch in the presence of the size argument. */ |
4910 | warned = warning_at (curloc, OPT_Wattributes, |
4911 | "attribute %qs positional argument 2 " |
4912 | "missing in previous designation" , |
4913 | attrstr); |
4914 | else if (newa->internal_p || cura->internal_p) |
4915 | /* Mismatch in the value of the size argument and a VLA bound. */ |
4916 | warned = warning_at (curloc, OPT_Wattributes, |
4917 | "attribute %qs positional argument 2 " |
4918 | "conflicts with previous designation " |
4919 | "by argument %u" , |
4920 | attrstr, cura->sizarg + 1); |
4921 | else |
4922 | /* Mismatch in the value of the size argument between two |
4923 | explicit access attributes. */ |
4924 | warned = warning_at (curloc, OPT_Wattributes, |
4925 | "attribute %qs mismatched positional argument " |
4926 | "values %i and %i" , |
4927 | attrstr, newa->sizarg + 1, cura->sizarg + 1); |
4928 | |
4929 | if (warned) |
4930 | { |
4931 | /* If the previous declaration is a function (as opposed |
4932 | to a typedef of one), find the location of the array |
4933 | or pointer argument that uses the conflicting VLA bound |
4934 | and point to it in the note. */ |
4935 | const attr_access* const pa = cura->size ? cura : newa; |
4936 | tree size = pa->size ? TREE_VALUE (pa->size) : NULL_TREE; |
4937 | if (size && DECL_P (size)) |
4938 | { |
4939 | location_t argloc = UNKNOWN_LOCATION; |
4940 | if (tree arg = get_argument (fndecl: node[2], argno: pa->ptrarg)) |
4941 | argloc = DECL_SOURCE_LOCATION (arg); |
4942 | |
4943 | gcc_rich_location richloc (DECL_SOURCE_LOCATION (size)); |
4944 | if (argloc != UNKNOWN_LOCATION) |
4945 | richloc.add_range (loc: argloc); |
4946 | |
4947 | inform (&richloc, "designating the bound of variable " |
4948 | "length array argument %u" , |
4949 | pa->ptrarg + 1); |
4950 | } |
4951 | else if (prevloc != UNKNOWN_LOCATION) |
4952 | inform (prevloc, "previous declaration here" ); |
4953 | } |
4954 | |
4955 | continue; |
4956 | } |
4957 | |
4958 | if (newa->internal_p == cura->internal_p) |
4959 | continue; |
4960 | |
4961 | /* Merge the CURA and NEWA. */ |
4962 | attr_access merged = *newa; |
4963 | |
4964 | /* VLA seen in a declaration takes precedence. */ |
4965 | if (cura->minsize == HOST_WIDE_INT_M1U) |
4966 | merged.minsize = HOST_WIDE_INT_M1U; |
4967 | |
4968 | /* Use the explicitly specified size positional argument. */ |
4969 | if (cura->sizarg != UINT_MAX) |
4970 | merged.sizarg = cura->sizarg; |
4971 | |
4972 | /* Use the explicitly specified mode. */ |
4973 | if (merged.mode == access_deferred) |
4974 | merged.mode = cura->mode; |
4975 | |
4976 | tree str = merged.to_internal_string (); |
4977 | spec += TREE_STRING_POINTER (str); |
4978 | } |
4979 | |
4980 | if (!spec.length ()) |
4981 | return NULL_TREE; |
4982 | |
4983 | return build_string (spec.length (), spec.c_str ()); |
4984 | } |
4985 | |
4986 | /* Convenience wrapper for the above. */ |
4987 | |
4988 | static tree |
4989 | append_access_attr_idxs (tree node[3], tree attrs, const char *attrstr, |
4990 | char code, HOST_WIDE_INT idxs[2]) |
4991 | { |
4992 | char attrspec[80]; |
4993 | int n = sprintf (s: attrspec, format: "%c%u" , code, (unsigned) idxs[0] - 1); |
4994 | if (idxs[1]) |
4995 | n += sprintf (s: attrspec + n, format: ",%u" , (unsigned) idxs[1] - 1); |
4996 | |
4997 | return append_access_attr (node, attrs, attrstr, attrspec); |
4998 | } |
4999 | |
5000 | /* Handle the access attribute for function type NODE[0], with the function |
5001 | DECL optionally in NODE[1]. The handler is called both in response to |
5002 | an explict attribute access on a declaration with a mode and one or two |
5003 | positional arguments, and for internally synthesized access specifications |
5004 | with a string argument optionally followd by a DECL or expression |
5005 | representing a VLA bound. To speed up parsing, the handler transforms |
5006 | the attribute and its arguments into a string. */ |
5007 | |
5008 | static tree |
5009 | handle_access_attribute (tree node[3], tree name, tree args, int flags, |
5010 | bool *no_add_attrs) |
5011 | { |
5012 | tree attrs = TYPE_ATTRIBUTES (*node); |
5013 | tree type = *node; |
5014 | if (POINTER_TYPE_P (type)) |
5015 | { |
5016 | tree ptype = TREE_TYPE (type); |
5017 | if (FUNC_OR_METHOD_TYPE_P (ptype)) |
5018 | type = ptype; |
5019 | } |
5020 | |
5021 | *no_add_attrs = true; |
5022 | |
5023 | /* Verify a full prototype is provided so that the argument types |
5024 | can be validated. Avoid diagnosing type-generic built-ins since |
5025 | those have no prototype. */ |
5026 | if (!args |
5027 | && !prototype_p (type) |
5028 | && (!attrs || !lookup_attribute (attr_name: "type generic" , list: attrs))) |
5029 | { |
5030 | error ("attribute %qE without arguments on a non-prototype" , name); |
5031 | return NULL_TREE; |
5032 | } |
5033 | |
5034 | tree access_mode = TREE_VALUE (args); |
5035 | if (TREE_CODE (access_mode) == STRING_CST) |
5036 | { |
5037 | const char* const str = TREE_STRING_POINTER (access_mode); |
5038 | if (*str == '+') |
5039 | { |
5040 | /* This is a request to merge an internal specification for |
5041 | a function declaration involving arrays but no explicit |
5042 | attribute access. */ |
5043 | tree vblist = TREE_CHAIN (args); |
5044 | tree axstr = append_access_attr (node, attrs, NULL, attrspec: str + 1, |
5045 | vblist); |
5046 | if (!axstr) |
5047 | return NULL_TREE; |
5048 | |
5049 | /* Replace any existing access attribute specification with |
5050 | the concatenation above. */ |
5051 | tree axsat = tree_cons (NULL_TREE, axstr, vblist); |
5052 | axsat = tree_cons (name, axsat, NULL_TREE); |
5053 | |
5054 | /* Recursively call self to "replace" the documented/external |
5055 | form of the attribute with the condensend internal form. */ |
5056 | decl_attributes (node, axsat, flags | ATTR_FLAG_INTERNAL); |
5057 | return NULL_TREE; |
5058 | } |
5059 | |
5060 | if (flags & ATTR_FLAG_INTERNAL) |
5061 | { |
5062 | /* This is a recursive call to handle the condensed internal |
5063 | form of the attribute (see below). Since all validation |
5064 | has been done simply return here, accepting the attribute |
5065 | as is. */ |
5066 | *no_add_attrs = false; |
5067 | return NULL_TREE; |
5068 | } |
5069 | } |
5070 | |
5071 | /* Set to true when the access mode has the form of a function call |
5072 | as in 'attribute (read_only (1, 2))'. That's an easy mistake to |
5073 | make and so worth a special diagnostic. */ |
5074 | bool funcall = false; |
5075 | if (TREE_CODE (access_mode) == CALL_EXPR) |
5076 | { |
5077 | access_mode = CALL_EXPR_FN (access_mode); |
5078 | if (TREE_CODE (access_mode) != ADDR_EXPR) |
5079 | { |
5080 | error ("attribute %qE invalid mode" , name); |
5081 | return NULL_TREE; |
5082 | } |
5083 | access_mode = TREE_OPERAND (access_mode, 0); |
5084 | access_mode = DECL_NAME (access_mode); |
5085 | funcall = true; |
5086 | } |
5087 | else if (TREE_CODE (access_mode) != IDENTIFIER_NODE) |
5088 | { |
5089 | error ("attribute %qE mode %qE is not an identifier; expected one of " |
5090 | "%qs, %qs, %qs, or %qs" , name, access_mode, |
5091 | "read_only" , "read_write" , "write_only" , "none" ); |
5092 | return NULL_TREE; |
5093 | } |
5094 | |
5095 | const char* const access_str = IDENTIFIER_POINTER (access_mode); |
5096 | const char *ps = access_str; |
5097 | if (ps[0] == '_' && ps[1] == '_') |
5098 | { |
5099 | size_t len = strlen (s: ps); |
5100 | if (ps[len - 1] == '_' && ps[len - 2] == '_') |
5101 | ps += 2; |
5102 | } |
5103 | |
5104 | int imode; |
5105 | |
5106 | { |
5107 | const int nmodes = ARRAY_SIZE (attr_access::mode_names); |
5108 | |
5109 | for (imode = 0; imode != nmodes; ++imode) |
5110 | if (!strncmp (s1: ps, s2: attr_access::mode_names[imode], |
5111 | n: strlen (s: attr_access::mode_names[imode]))) |
5112 | break; |
5113 | |
5114 | if (imode == nmodes) |
5115 | { |
5116 | error ("attribute %qE invalid mode %qs; expected one of " |
5117 | "%qs, %qs, %qs, or %qs" , name, access_str, |
5118 | "read_only" , "read_write" , "write_only" , "none" ); |
5119 | return NULL_TREE; |
5120 | } |
5121 | } |
5122 | |
5123 | const ::access_mode mode = static_cast<::access_mode>(imode); |
5124 | |
5125 | if (funcall) |
5126 | { |
5127 | error ("attribute %qE unexpected %<(%> after mode %qs; expected " |
5128 | "a positional argument or %<)%>" , |
5129 | name, access_str); |
5130 | return NULL_TREE; |
5131 | } |
5132 | |
5133 | args = TREE_CHAIN (args); |
5134 | if (!args) |
5135 | { |
5136 | /* The first positional argument is required. It may be worth |
5137 | dropping the requirement at some point and having read_only |
5138 | apply to all const-qualified pointers and read_write or |
5139 | write_only to the rest. */ |
5140 | error ("attribute %<%E(%s)%> missing an argument" , |
5141 | name, access_str); |
5142 | return NULL_TREE; |
5143 | } |
5144 | |
5145 | /* One or more positional arguments have been specified. Validate |
5146 | them. */ |
5147 | tree idxnodes[2] = { NULL_TREE, NULL_TREE }; |
5148 | tree argtypes[2] = { NULL_TREE, NULL_TREE }; |
5149 | /* 1-based attribute positional arguments or zero if not specified. |
5150 | Invalid negative or excessive values are also stored but used |
5151 | only in diagnostics. */ |
5152 | HOST_WIDE_INT idxs[2] = { 0, 0 }; |
5153 | |
5154 | /* Number of function formal arguments (used in diagnostics). */ |
5155 | unsigned nfuncargs = 0; |
5156 | /* Number of (optional) attribute positional arguments. */ |
5157 | unsigned nattrargs = 0; |
5158 | |
5159 | for (unsigned i = 0; i != 2; ++i, args = TREE_CHAIN (args), ++nattrargs) |
5160 | { |
5161 | if (!args) |
5162 | break; |
5163 | |
5164 | idxnodes[i] = TREE_VALUE (args); |
5165 | |
5166 | if (TREE_CODE (idxnodes[i]) != IDENTIFIER_NODE |
5167 | && TREE_CODE (idxnodes[i]) != FUNCTION_DECL) |
5168 | idxnodes[i] = default_conversion (idxnodes[i]); |
5169 | |
5170 | if (tree_fits_shwi_p (idxnodes[i])) |
5171 | { |
5172 | idxs[i] = tree_to_shwi (idxnodes[i]); |
5173 | argtypes[i] = get_argument_type (functype: type, argno: idxs[i], nargs: &nfuncargs); |
5174 | } |
5175 | } |
5176 | |
5177 | if ((nattrargs == 1 && !idxs[0]) |
5178 | || (nattrargs == 2 && (!idxs[0] || !idxs[1]))) |
5179 | { |
5180 | if (idxnodes[1]) |
5181 | error ("attribute %<%E(%s, %E, %E)%> invalid positional argument %i" , |
5182 | name, access_str, idxnodes[0], idxnodes[1], idxs[0] ? 2 : 1); |
5183 | else |
5184 | error ("attribute %<%E(%s, %E)%> invalid positional argument %i" , |
5185 | name, access_str, idxnodes[0], idxs[0] ? 2 : 1); |
5186 | return NULL_TREE; |
5187 | } |
5188 | |
5189 | /* Format the attribute specification to include in diagnostics. */ |
5190 | char attrstr[80]; |
5191 | if (idxnodes[1]) |
5192 | snprintf (s: attrstr, maxlen: sizeof attrstr, format: "%s(%s, %lli, %lli)" , |
5193 | IDENTIFIER_POINTER (name), access_str, |
5194 | (long long) idxs[0], (long long) idxs[1]); |
5195 | else if (idxnodes[0]) |
5196 | snprintf (s: attrstr, maxlen: sizeof attrstr, format: "%s(%s, %lli)" , |
5197 | IDENTIFIER_POINTER (name), access_str, |
5198 | (long long) idxs[0]); |
5199 | else |
5200 | snprintf (s: attrstr, maxlen: sizeof attrstr, format: "%s(%s)" , |
5201 | IDENTIFIER_POINTER (name), access_str); |
5202 | |
5203 | /* Verify the positional argument values are in range. */ |
5204 | if (!argtypes[0] || (idxnodes[1] && !argtypes[1])) |
5205 | { |
5206 | if (idxnodes[0]) |
5207 | { |
5208 | if (idxs[0] < 0 || idxs[1] < 0) |
5209 | error ("attribute %qs positional argument %i invalid value %wi" , |
5210 | attrstr, idxs[0] < 0 ? 1 : 2, |
5211 | idxs[0] < 0 ? idxs[0] : idxs[1]); |
5212 | else |
5213 | error ("attribute %qs positional argument %i value %wi exceeds " |
5214 | "number of function arguments %u" , |
5215 | attrstr, idxs[0] ? 1 : 2, |
5216 | idxs[0] ? idxs[0] : idxs[1], |
5217 | nfuncargs); |
5218 | } |
5219 | else |
5220 | error ("attribute %qs invalid positional argument" , attrstr); |
5221 | |
5222 | return NULL_TREE; |
5223 | } |
5224 | |
5225 | if (!POINTER_TYPE_P (argtypes[0])) |
5226 | { |
5227 | /* The first argument must have a pointer or reference type. */ |
5228 | error ("attribute %qs positional argument 1 references " |
5229 | "non-pointer argument type %qT" , |
5230 | attrstr, argtypes[0]); |
5231 | return NULL_TREE; |
5232 | } |
5233 | |
5234 | { |
5235 | /* Pointers to functions are not allowed. */ |
5236 | tree ptrtype = TREE_TYPE (argtypes[0]); |
5237 | if (FUNC_OR_METHOD_TYPE_P (ptrtype)) |
5238 | { |
5239 | error ("attribute %qs positional argument 1 references " |
5240 | "argument of function type %qT" , |
5241 | attrstr, ptrtype); |
5242 | return NULL_TREE; |
5243 | } |
5244 | } |
5245 | |
5246 | if (mode == access_read_write || mode == access_write_only) |
5247 | { |
5248 | /* Read_write and write_only modes must reference non-const |
5249 | arguments. */ |
5250 | if (TYPE_READONLY (TREE_TYPE (argtypes[0]))) |
5251 | { |
5252 | error ("attribute %qs positional argument 1 references " |
5253 | "%qs-qualified argument type %qT" , |
5254 | attrstr, "const" , argtypes[0]); |
5255 | return NULL_TREE; |
5256 | } |
5257 | } |
5258 | else if (!TYPE_READONLY (TREE_TYPE (argtypes[0]))) |
5259 | { |
5260 | /* A read_only mode should ideally reference const-qualified |
5261 | arguments but it's not diagnosed error if one doesn't. |
5262 | This makes it possible to annotate legacy, const-incorrect |
5263 | APIs. It might be worth a diagnostic along the lines of |
5264 | -Wsuggest-const. */ |
5265 | ; |
5266 | } |
5267 | |
5268 | if (argtypes[1] && !INTEGRAL_TYPE_P (argtypes[1])) |
5269 | { |
5270 | error ("attribute %qs positional argument 2 references " |
5271 | "non-integer argument type %qT" , |
5272 | attrstr, argtypes[1]); |
5273 | return NULL_TREE; |
5274 | } |
5275 | |
5276 | /* Verify that the new attribute doesn't conflict with any existing |
5277 | attributes specified on previous declarations of the same type |
5278 | and if not, concatenate the two. */ |
5279 | const char code = attr_access::mode_chars[mode]; |
5280 | tree new_attrs = append_access_attr_idxs (node, attrs, attrstr, code, idxs); |
5281 | if (!new_attrs) |
5282 | return NULL_TREE; |
5283 | |
5284 | /* Replace any existing access attribute specification with |
5285 | the concatenation above. */ |
5286 | new_attrs = tree_cons (NULL_TREE, new_attrs, NULL_TREE); |
5287 | new_attrs = tree_cons (name, new_attrs, NULL_TREE); |
5288 | |
5289 | if (node[1]) |
5290 | { |
5291 | /* Repeat for the previously declared type. */ |
5292 | attrs = TYPE_ATTRIBUTES (TREE_TYPE (node[1])); |
5293 | new_attrs = append_access_attr_idxs (node, attrs, attrstr, code, idxs); |
5294 | if (!new_attrs) |
5295 | return NULL_TREE; |
5296 | |
5297 | new_attrs = tree_cons (NULL_TREE, new_attrs, NULL_TREE); |
5298 | new_attrs = tree_cons (name, new_attrs, NULL_TREE); |
5299 | } |
5300 | |
5301 | /* Recursively call self to "replace" the documented/external form |
5302 | of the attribute with the condensed internal form. */ |
5303 | decl_attributes (node, new_attrs, flags | ATTR_FLAG_INTERNAL); |
5304 | return NULL_TREE; |
5305 | } |
5306 | |
5307 | /* Extract attribute "arg spec" from each FNDECL argument that has it, |
5308 | build a single attribute access corresponding to all the arguments, |
5309 | and return the result. SKIP_VOIDPTR set to ignore void* parameters |
5310 | (used for user-defined functions for which, unlike in for built-ins, |
5311 | void* cannot be relied on to determine anything about the access |
5312 | through it or whether it even takes place). |
5313 | |
5314 | For example, the parameters in the declaration: |
5315 | |
5316 | void f (int x, int y, char [x][1][y][3], char [y][2][y][5]); |
5317 | |
5318 | result in the following attribute access: |
5319 | |
5320 | value: "+^2[*],$0$1^3[*],$1$1" |
5321 | list: < <0, x> <1, y> > |
5322 | |
5323 | where the list has a single value which itself is a list, each |
5324 | of whose <node>s corresponds to one VLA bound for each of the two |
5325 | parameters. */ |
5326 | |
5327 | tree |
5328 | build_attr_access_from_parms (tree parms, bool skip_voidptr) |
5329 | { |
5330 | /* Maps each named integral argument DECL seen so far to its position |
5331 | in the argument list; used to associate VLA sizes with arguments. */ |
5332 | hash_map<tree, unsigned> arg2pos; |
5333 | |
5334 | /* The string representation of the access specification for all |
5335 | arguments. */ |
5336 | std::string spec; |
5337 | unsigned argpos = 0; |
5338 | |
5339 | /* A TREE_LIST of VLA bounds. */ |
5340 | tree vblist = NULL_TREE; |
5341 | |
5342 | for (tree arg = parms; arg; arg = TREE_CHAIN (arg), ++argpos) |
5343 | { |
5344 | if (!DECL_P (arg)) |
5345 | continue; |
5346 | |
5347 | tree argtype = TREE_TYPE (arg); |
5348 | if (DECL_NAME (arg) && INTEGRAL_TYPE_P (argtype)) |
5349 | arg2pos.put (k: arg, v: argpos); |
5350 | } |
5351 | |
5352 | argpos = 0; |
5353 | for (tree arg = parms; arg; arg = TREE_CHAIN (arg), ++argpos) |
5354 | { |
5355 | if (!DECL_P (arg)) |
5356 | continue; |
5357 | |
5358 | tree argtype = TREE_TYPE (arg); |
5359 | |
5360 | tree argspec = DECL_ATTRIBUTES (arg); |
5361 | if (!argspec) |
5362 | continue; |
5363 | |
5364 | if (POINTER_TYPE_P (argtype)) |
5365 | { |
5366 | /* void* arguments in user-defined functions could point to |
5367 | anything; skip them. */ |
5368 | tree reftype = TREE_TYPE (argtype); |
5369 | if (skip_voidptr && VOID_TYPE_P (reftype)) |
5370 | continue; |
5371 | } |
5372 | |
5373 | /* Each parameter should have at most one "arg spec" attribute. */ |
5374 | argspec = lookup_attribute (attr_name: "arg spec" , list: argspec); |
5375 | if (!argspec) |
5376 | continue; |
5377 | |
5378 | /* Attribute arg spec should have one or two arguments. */ |
5379 | argspec = TREE_VALUE (argspec); |
5380 | |
5381 | /* The attribute arg spec string. */ |
5382 | tree str = TREE_VALUE (argspec); |
5383 | const char *s = TREE_STRING_POINTER (str); |
5384 | |
5385 | /* Create the attribute access string from the arg spec string, |
5386 | optionally followed by position of the VLA bound argument if |
5387 | it is one. */ |
5388 | { |
5389 | size_t specend = spec.length (); |
5390 | if (!specend) |
5391 | { |
5392 | spec = '+'; |
5393 | specend = 1; |
5394 | } |
5395 | |
5396 | /* Format the access string in place. */ |
5397 | int len = snprintf (NULL, maxlen: 0, format: "%c%u%s" , |
5398 | attr_access::mode_chars[access_deferred], |
5399 | argpos, s); |
5400 | spec.resize (n: specend + len + 1); |
5401 | sprintf (s: &spec[specend], format: "%c%u%s" , |
5402 | attr_access::mode_chars[access_deferred], |
5403 | argpos, s); |
5404 | /* Trim the trailing NUL. */ |
5405 | spec.resize (n: specend + len); |
5406 | } |
5407 | |
5408 | /* The (optional) list of expressions denoting the VLA bounds |
5409 | N in ARGTYPE <arg>[Ni]...[Nj]...[Nk]. */ |
5410 | tree argvbs = TREE_CHAIN (argspec); |
5411 | if (argvbs) |
5412 | { |
5413 | spec += ','; |
5414 | /* Add ARGVBS to the list. Their presence is indicated by |
5415 | appending a comma followed by the dollar sign and, when |
5416 | it corresponds to a function parameter, the position of |
5417 | each bound Ni, so it can be distinguished from |
5418 | an unspecified bound (as in T[*]). The list is in reverse |
5419 | order of arguments and needs to be reversed to access in |
5420 | order. */ |
5421 | vblist = tree_cons (NULL_TREE, argvbs, vblist); |
5422 | |
5423 | unsigned nelts = 0; |
5424 | for (tree vb = argvbs; vb; vb = TREE_CHAIN (vb), ++nelts) |
5425 | { |
5426 | tree bound = TREE_VALUE (vb); |
5427 | if (const unsigned *psizpos = arg2pos.get (k: bound)) |
5428 | { |
5429 | /* BOUND previously seen in the parameter list. */ |
5430 | TREE_PURPOSE (vb) = size_int (*psizpos); |
5431 | /* Format the position string in place. */ |
5432 | int len = snprintf (NULL, maxlen: 0, format: "$%u" , *psizpos); |
5433 | size_t specend = spec.length (); |
5434 | spec.resize (n: specend + len + 1); |
5435 | sprintf (s: &spec[specend], format: "$%u" , *psizpos); |
5436 | /* Trim the trailing NUL. */ |
5437 | spec.resize (n: specend + len); |
5438 | } |
5439 | else |
5440 | { |
5441 | /* BOUND doesn't name a parameter (it could be a global |
5442 | variable or an expression such as a function call). */ |
5443 | spec += '$'; |
5444 | } |
5445 | } |
5446 | } |
5447 | } |
5448 | |
5449 | if (!spec.length ()) |
5450 | return NULL_TREE; |
5451 | |
5452 | /* Attribute access takes a two or three arguments. Wrap VBLIST in |
5453 | another list in case it has more nodes than would otherwise fit. */ |
5454 | vblist = build_tree_list (NULL_TREE, vblist); |
5455 | |
5456 | /* Build a single attribute access with the string describing all |
5457 | array arguments and an optional list of any non-parameter VLA |
5458 | bounds in order. */ |
5459 | tree str = build_string (spec.length (), spec.c_str ()); |
5460 | tree attrargs = tree_cons (NULL_TREE, str, vblist); |
5461 | tree name = get_identifier ("access" ); |
5462 | return build_tree_list (name, attrargs); |
5463 | } |
5464 | |
5465 | /* Handle a "nothrow" attribute; arguments as in |
5466 | struct attribute_spec.handler. */ |
5467 | |
5468 | static tree |
5469 | handle_nothrow_attribute (tree *node, tree name, tree ARG_UNUSED (args), |
5470 | int ARG_UNUSED (flags), bool *no_add_attrs) |
5471 | { |
5472 | if (TREE_CODE (*node) == FUNCTION_DECL) |
5473 | TREE_NOTHROW (*node) = 1; |
5474 | /* ??? TODO: Support types. */ |
5475 | else |
5476 | { |
5477 | warning (OPT_Wattributes, "%qE attribute ignored" , name); |
5478 | *no_add_attrs = true; |
5479 | } |
5480 | |
5481 | return NULL_TREE; |
5482 | } |
5483 | |
5484 | /* Handle a "nothrow" attribute; arguments as in |
5485 | struct attribute_spec.handler. */ |
5486 | |
5487 | static tree |
5488 | handle_expected_throw_attribute (tree *node, tree name, tree ARG_UNUSED (args), |
5489 | int ARG_UNUSED (flags), bool *no_add_attrs) |
5490 | { |
5491 | if (TREE_CODE (*node) == FUNCTION_DECL) |
5492 | /* No flag to set here. */; |
5493 | /* ??? TODO: Support types. */ |
5494 | else |
5495 | { |
5496 | warning (OPT_Wattributes, "%qE attribute ignored" , name); |
5497 | *no_add_attrs = true; |
5498 | } |
5499 | |
5500 | return NULL_TREE; |
5501 | } |
5502 | |
5503 | /* Handle a "cleanup" attribute; arguments as in |
5504 | struct attribute_spec.handler. */ |
5505 | |
5506 | static tree |
5507 | handle_cleanup_attribute (tree *node, tree name, tree args, |
5508 | int ARG_UNUSED (flags), bool *no_add_attrs) |
5509 | { |
5510 | tree decl = *node; |
5511 | tree cleanup_id, cleanup_decl; |
5512 | |
5513 | /* ??? Could perhaps support cleanups on TREE_STATIC, much like we do |
5514 | for global destructors in C++. This requires infrastructure that |
5515 | we don't have generically at the moment. It's also not a feature |
5516 | we'd be missing too much, since we do have attribute constructor. */ |
5517 | if (!VAR_P (decl) || TREE_STATIC (decl)) |
5518 | { |
5519 | warning (OPT_Wattributes, "%qE attribute ignored" , name); |
5520 | *no_add_attrs = true; |
5521 | return NULL_TREE; |
5522 | } |
5523 | |
5524 | /* Verify that the argument is a function in scope. */ |
5525 | /* ??? We could support pointers to functions here as well, if |
5526 | that was considered desirable. */ |
5527 | cleanup_id = TREE_VALUE (args); |
5528 | if (TREE_CODE (cleanup_id) != IDENTIFIER_NODE) |
5529 | { |
5530 | error ("cleanup argument not an identifier" ); |
5531 | *no_add_attrs = true; |
5532 | return NULL_TREE; |
5533 | } |
5534 | cleanup_decl = lookup_name (cleanup_id); |
5535 | if (!cleanup_decl || TREE_CODE (cleanup_decl) != FUNCTION_DECL) |
5536 | { |
5537 | error ("cleanup argument not a function" ); |
5538 | *no_add_attrs = true; |
5539 | return NULL_TREE; |
5540 | } |
5541 | |
5542 | /* That the function has proper type is checked with the |
5543 | eventual call to build_function_call. */ |
5544 | |
5545 | return NULL_TREE; |
5546 | } |
5547 | |
5548 | /* Handle a "warn_unused_result" attribute. No special handling. */ |
5549 | |
5550 | static tree |
5551 | handle_warn_unused_result_attribute (tree *node, tree name, |
5552 | tree ARG_UNUSED (args), |
5553 | int ARG_UNUSED (flags), bool *no_add_attrs) |
5554 | { |
5555 | /* Ignore the attribute for functions not returning any value. */ |
5556 | if (VOID_TYPE_P (TREE_TYPE (*node))) |
5557 | { |
5558 | warning (OPT_Wattributes, "%qE attribute ignored" , name); |
5559 | *no_add_attrs = true; |
5560 | } |
5561 | |
5562 | return NULL_TREE; |
5563 | } |
5564 | |
5565 | /* Handle a "sentinel" attribute. */ |
5566 | |
5567 | static tree |
5568 | handle_sentinel_attribute (tree *node, tree name, tree args, |
5569 | int ARG_UNUSED (flags), bool *no_add_attrs) |
5570 | { |
5571 | if (!prototype_p (*node)) |
5572 | { |
5573 | warning (OPT_Wattributes, |
5574 | "%qE attribute requires prototypes with named arguments" , name); |
5575 | *no_add_attrs = true; |
5576 | } |
5577 | else |
5578 | { |
5579 | if (!stdarg_p (*node)) |
5580 | { |
5581 | warning (OPT_Wattributes, |
5582 | "%qE attribute only applies to variadic functions" , name); |
5583 | *no_add_attrs = true; |
5584 | } |
5585 | } |
5586 | |
5587 | if (args) |
5588 | { |
5589 | tree position = TREE_VALUE (args); |
5590 | if (position && TREE_CODE (position) != IDENTIFIER_NODE |
5591 | && TREE_CODE (position) != FUNCTION_DECL) |
5592 | position = default_conversion (position); |
5593 | |
5594 | if (TREE_CODE (position) != INTEGER_CST |
5595 | || !INTEGRAL_TYPE_P (TREE_TYPE (position))) |
5596 | { |
5597 | warning (OPT_Wattributes, |
5598 | "requested position is not an integer constant" ); |
5599 | *no_add_attrs = true; |
5600 | } |
5601 | else |
5602 | { |
5603 | if (tree_int_cst_lt (t1: position, integer_zero_node)) |
5604 | { |
5605 | warning (OPT_Wattributes, |
5606 | "requested position is less than zero" ); |
5607 | *no_add_attrs = true; |
5608 | } |
5609 | } |
5610 | } |
5611 | |
5612 | return NULL_TREE; |
5613 | } |
5614 | |
5615 | /* Handle a "type_generic" attribute. */ |
5616 | |
5617 | static tree |
5618 | handle_type_generic_attribute (tree *node, tree ARG_UNUSED (name), |
5619 | tree ARG_UNUSED (args), int ARG_UNUSED (flags), |
5620 | bool * ARG_UNUSED (no_add_attrs)) |
5621 | { |
5622 | /* Ensure we have a function type. */ |
5623 | gcc_assert (TREE_CODE (*node) == FUNCTION_TYPE); |
5624 | |
5625 | /* Ensure we have a variadic function. */ |
5626 | gcc_assert (!prototype_p (*node) || stdarg_p (*node)); |
5627 | |
5628 | return NULL_TREE; |
5629 | } |
5630 | |
5631 | /* Handle a "target" attribute. */ |
5632 | |
5633 | static tree |
5634 | handle_target_attribute (tree *node, tree name, tree args, int flags, |
5635 | bool *no_add_attrs) |
5636 | { |
5637 | /* Ensure we have a function type. */ |
5638 | if (TREE_CODE (*node) != FUNCTION_DECL) |
5639 | { |
5640 | warning (OPT_Wattributes, "%qE attribute ignored" , name); |
5641 | *no_add_attrs = true; |
5642 | } |
5643 | else if (lookup_attribute (attr_name: "target_clones" , DECL_ATTRIBUTES (*node))) |
5644 | { |
5645 | warning (OPT_Wattributes, "%qE attribute ignored due to conflict " |
5646 | "with %qs attribute" , name, "target_clones" ); |
5647 | *no_add_attrs = true; |
5648 | } |
5649 | else if (! targetm.target_option.valid_attribute_p (*node, name, args, |
5650 | flags)) |
5651 | *no_add_attrs = true; |
5652 | |
5653 | /* Check that there's no empty string in values of the attribute. */ |
5654 | for (tree t = args; t != NULL_TREE; t = TREE_CHAIN (t)) |
5655 | { |
5656 | tree value = TREE_VALUE (t); |
5657 | if (TREE_CODE (value) == STRING_CST |
5658 | && TREE_STRING_LENGTH (value) == 1 |
5659 | && TREE_STRING_POINTER (value)[0] == '\0') |
5660 | { |
5661 | warning (OPT_Wattributes, "empty string in attribute %<target%>" ); |
5662 | *no_add_attrs = true; |
5663 | } |
5664 | } |
5665 | |
5666 | return NULL_TREE; |
5667 | } |
5668 | |
5669 | /* Handle a "target_clones" attribute. */ |
5670 | |
5671 | static tree |
5672 | handle_target_clones_attribute (tree *node, tree name, tree ARG_UNUSED (args), |
5673 | int ARG_UNUSED (flags), bool *no_add_attrs) |
5674 | { |
5675 | /* Ensure we have a function type. */ |
5676 | if (TREE_CODE (*node) == FUNCTION_DECL) |
5677 | { |
5678 | for (tree t = args; t != NULL_TREE; t = TREE_CHAIN (t)) |
5679 | { |
5680 | tree value = TREE_VALUE (t); |
5681 | if (TREE_CODE (value) != STRING_CST) |
5682 | { |
5683 | error ("%qE attribute argument not a string constant" , name); |
5684 | *no_add_attrs = true; |
5685 | return NULL_TREE; |
5686 | } |
5687 | } |
5688 | |
5689 | if (lookup_attribute (attr_name: "always_inline" , DECL_ATTRIBUTES (*node))) |
5690 | { |
5691 | warning (OPT_Wattributes, "%qE attribute ignored due to conflict " |
5692 | "with %qs attribute" , name, "always_inline" ); |
5693 | *no_add_attrs = true; |
5694 | } |
5695 | else if (lookup_attribute (attr_name: "target" , DECL_ATTRIBUTES (*node))) |
5696 | { |
5697 | warning (OPT_Wattributes, "%qE attribute ignored due to conflict " |
5698 | "with %qs attribute" , name, "target" ); |
5699 | *no_add_attrs = true; |
5700 | } |
5701 | else if (get_target_clone_attr_len (args) == -1) |
5702 | { |
5703 | warning (OPT_Wattributes, |
5704 | "single %<target_clones%> attribute is ignored" ); |
5705 | *no_add_attrs = true; |
5706 | } |
5707 | else |
5708 | /* Do not inline functions with multiple clone targets. */ |
5709 | DECL_UNINLINABLE (*node) = 1; |
5710 | } |
5711 | else |
5712 | { |
5713 | warning (OPT_Wattributes, "%qE attribute ignored" , name); |
5714 | *no_add_attrs = true; |
5715 | } |
5716 | return NULL_TREE; |
5717 | } |
5718 | |
5719 | /* For handling "optimize" attribute. arguments as in |
5720 | struct attribute_spec.handler. */ |
5721 | |
5722 | static tree |
5723 | handle_optimize_attribute (tree *node, tree name, tree args, |
5724 | int ARG_UNUSED (flags), bool *no_add_attrs) |
5725 | { |
5726 | /* Ensure we have a function type. */ |
5727 | if (TREE_CODE (*node) != FUNCTION_DECL) |
5728 | { |
5729 | warning (OPT_Wattributes, "%qE attribute ignored" , name); |
5730 | *no_add_attrs = true; |
5731 | } |
5732 | else |
5733 | { |
5734 | struct cl_optimization cur_opts; |
5735 | tree old_opts = DECL_FUNCTION_SPECIFIC_OPTIMIZATION (*node); |
5736 | |
5737 | /* Save current options. */ |
5738 | cl_optimization_save (&cur_opts, &global_options, &global_options_set); |
5739 | tree prev_target_node = build_target_option_node (opts: &global_options, |
5740 | opts_set: &global_options_set); |
5741 | |
5742 | /* If we previously had some optimization options, use them as the |
5743 | default. */ |
5744 | gcc_options *saved_global_options = NULL; |
5745 | |
5746 | /* When #pragma GCC optimize pragma is used, it modifies global_options |
5747 | without calling targetm.override_options_after_change. That can leave |
5748 | target flags inconsistent for comparison. */ |
5749 | if (flag_checking && optimization_current_node == optimization_default_node) |
5750 | { |
5751 | saved_global_options = XNEW (gcc_options); |
5752 | *saved_global_options = global_options; |
5753 | } |
5754 | |
5755 | if (old_opts) |
5756 | cl_optimization_restore (&global_options, &global_options_set, |
5757 | TREE_OPTIMIZATION (old_opts)); |
5758 | |
5759 | /* Parse options, and update the vector. */ |
5760 | parse_optimize_options (args, true); |
5761 | DECL_FUNCTION_SPECIFIC_OPTIMIZATION (*node) |
5762 | = build_optimization_node (opts: &global_options, opts_set: &global_options_set); |
5763 | tree target_node = build_target_option_node (opts: &global_options, |
5764 | opts_set: &global_options_set); |
5765 | if (prev_target_node != target_node) |
5766 | DECL_FUNCTION_SPECIFIC_TARGET (*node) = target_node; |
5767 | |
5768 | /* Restore current options. */ |
5769 | cl_optimization_restore (&global_options, &global_options_set, |
5770 | &cur_opts); |
5771 | cl_target_option_restore (&global_options, &global_options_set, |
5772 | TREE_TARGET_OPTION (prev_target_node)); |
5773 | |
5774 | if (saved_global_options != NULL) |
5775 | { |
5776 | if (!seen_error ()) |
5777 | cl_optimization_compare (ptr1: saved_global_options, ptr2: &global_options); |
5778 | free (ptr: saved_global_options); |
5779 | } |
5780 | } |
5781 | |
5782 | return NULL_TREE; |
5783 | } |
5784 | |
5785 | /* Handle a "no_split_stack" attribute. */ |
5786 | |
5787 | static tree |
5788 | handle_no_split_stack_attribute (tree *node, tree name, |
5789 | tree ARG_UNUSED (args), |
5790 | int ARG_UNUSED (flags), |
5791 | bool *no_add_attrs) |
5792 | { |
5793 | tree decl = *node; |
5794 | |
5795 | if (TREE_CODE (decl) != FUNCTION_DECL) |
5796 | { |
5797 | error_at (DECL_SOURCE_LOCATION (decl), |
5798 | "%qE attribute applies only to functions" , name); |
5799 | *no_add_attrs = true; |
5800 | } |
5801 | else if (DECL_INITIAL (decl)) |
5802 | { |
5803 | error_at (DECL_SOURCE_LOCATION (decl), |
5804 | "cannot set %qE attribute after definition" , name); |
5805 | *no_add_attrs = true; |
5806 | } |
5807 | |
5808 | return NULL_TREE; |
5809 | } |
5810 | |
5811 | /* Handle a "zero_call_used_regs" attribute; arguments as in |
5812 | struct attribute_spec.handler. */ |
5813 | |
5814 | static tree |
5815 | handle_zero_call_used_regs_attribute (tree *node, tree name, tree args, |
5816 | int ARG_UNUSED (flags), |
5817 | bool *no_add_attrs) |
5818 | { |
5819 | tree decl = *node; |
5820 | tree id = TREE_VALUE (args); |
5821 | |
5822 | if (TREE_CODE (decl) != FUNCTION_DECL) |
5823 | { |
5824 | error_at (DECL_SOURCE_LOCATION (decl), |
5825 | "%qE attribute applies only to functions" , name); |
5826 | *no_add_attrs = true; |
5827 | return NULL_TREE; |
5828 | } |
5829 | |
5830 | if (TREE_CODE (id) != STRING_CST) |
5831 | { |
5832 | error_at (DECL_SOURCE_LOCATION (decl), |
5833 | "%qE argument not a string" , name); |
5834 | *no_add_attrs = true; |
5835 | return NULL_TREE; |
5836 | } |
5837 | |
5838 | bool found = false; |
5839 | for (unsigned int i = 0; zero_call_used_regs_opts[i].name != NULL; ++i) |
5840 | if (strcmp (TREE_STRING_POINTER (id), |
5841 | s2: zero_call_used_regs_opts[i].name) == 0) |
5842 | { |
5843 | found = true; |
5844 | break; |
5845 | } |
5846 | |
5847 | if (!found) |
5848 | { |
5849 | error_at (DECL_SOURCE_LOCATION (decl), |
5850 | "unrecognized %qE attribute argument %qs" , |
5851 | name, TREE_STRING_POINTER (id)); |
5852 | *no_add_attrs = true; |
5853 | } |
5854 | |
5855 | return NULL_TREE; |
5856 | } |
5857 | |
5858 | /* Handle a "returns_nonnull" attribute; arguments as in |
5859 | struct attribute_spec.handler. */ |
5860 | |
5861 | static tree |
5862 | handle_returns_nonnull_attribute (tree *node, tree name, tree, int, |
5863 | bool *no_add_attrs) |
5864 | { |
5865 | // Even without a prototype we still have a return type we can check. |
5866 | if (TREE_CODE (TREE_TYPE (*node)) != POINTER_TYPE) |
5867 | { |
5868 | error ("%qE attribute on a function not returning a pointer" , name); |
5869 | *no_add_attrs = true; |
5870 | } |
5871 | return NULL_TREE; |
5872 | } |
5873 | |
5874 | /* Handle a "designated_init" attribute; arguments as in |
5875 | struct attribute_spec.handler. */ |
5876 | |
5877 | static tree |
5878 | handle_designated_init_attribute (tree *node, tree name, tree, int, |
5879 | bool *no_add_attrs) |
5880 | { |
5881 | if (TREE_CODE (*node) != RECORD_TYPE) |
5882 | { |
5883 | error ("%qE attribute is only valid on %<struct%> type" , name); |
5884 | *no_add_attrs = true; |
5885 | } |
5886 | return NULL_TREE; |
5887 | } |
5888 | |
5889 | |
5890 | /* Handle a "fallthrough" attribute; arguments as in struct |
5891 | attribute_spec.handler. */ |
5892 | |
5893 | tree |
5894 | handle_fallthrough_attribute (tree *, tree name, tree, int, |
5895 | bool *no_add_attrs) |
5896 | { |
5897 | pedwarn (input_location, OPT_Wattributes, "%qE attribute ignored" , name); |
5898 | *no_add_attrs = true; |
5899 | return NULL_TREE; |
5900 | } |
5901 | |
5902 | /* Handle a "assume" attribute; arguments as in struct |
5903 | attribute_spec.handler. */ |
5904 | |
5905 | tree |
5906 | handle_assume_attribute (tree *, tree name, tree, int, |
5907 | bool *no_add_attrs) |
5908 | { |
5909 | pedwarn (input_location, OPT_Wattributes, "%qE attribute ignored" , name); |
5910 | *no_add_attrs = true; |
5911 | return NULL_TREE; |
5912 | } |
5913 | |
5914 | /* Handle a "patchable_function_entry" attributes; arguments as in |
5915 | struct attribute_spec.handler. */ |
5916 | |
5917 | static tree |
5918 | handle_patchable_function_entry_attribute (tree *, tree name, tree args, |
5919 | int, bool *no_add_attrs) |
5920 | { |
5921 | for (; args; args = TREE_CHAIN (args)) |
5922 | { |
5923 | tree val = TREE_VALUE (args); |
5924 | if (val && TREE_CODE (val) != IDENTIFIER_NODE |
5925 | && TREE_CODE (val) != FUNCTION_DECL) |
5926 | val = default_conversion (val); |
5927 | |
5928 | if (!tree_fits_uhwi_p (val)) |
5929 | { |
5930 | warning (OPT_Wattributes, |
5931 | "%qE attribute argument %qE is not an integer constant" , |
5932 | name, val); |
5933 | *no_add_attrs = true; |
5934 | return NULL_TREE; |
5935 | } |
5936 | |
5937 | if (tree_to_uhwi (val) > USHRT_MAX) |
5938 | { |
5939 | warning (OPT_Wattributes, |
5940 | "%qE attribute argument %qE exceeds %u" , |
5941 | name, val, USHRT_MAX); |
5942 | *no_add_attrs = true; |
5943 | return NULL_TREE; |
5944 | } |
5945 | } |
5946 | return NULL_TREE; |
5947 | } |
5948 | |
5949 | /* Handle a "NSObject" attributes; arguments as in |
5950 | struct attribute_spec.handler. */ |
5951 | |
5952 | static tree |
5953 | handle_nsobject_attribute (tree *node, tree name, tree args, |
5954 | int /*flags*/, bool *no_add_attrs) |
5955 | { |
5956 | *no_add_attrs = true; |
5957 | |
5958 | /* This attribute only applies to typedefs (or field decls for properties), |
5959 | we drop it otherwise - but warn about this if enabled. */ |
5960 | if (TREE_CODE (*node) != TYPE_DECL && TREE_CODE (*node) != FIELD_DECL) |
5961 | { |
5962 | warning (OPT_WNSObject_attribute, "%qE attribute may be put on a" |
5963 | " typedef only; attribute is ignored" , name); |
5964 | return NULL_TREE; |
5965 | } |
5966 | |
5967 | /* The original implementation only allowed pointers to records, however |
5968 | recent implementations also allow void *. */ |
5969 | tree type = TREE_TYPE (*node); |
5970 | if (!type || !POINTER_TYPE_P (type) |
5971 | || (TREE_CODE (TREE_TYPE (type)) != RECORD_TYPE |
5972 | && !VOID_TYPE_P (TREE_TYPE (type)))) |
5973 | { |
5974 | error ("%qE attribute is for pointer types only" , name); |
5975 | return NULL_TREE; |
5976 | } |
5977 | |
5978 | tree t = tree_cons (name, args, TYPE_ATTRIBUTES (type)); |
5979 | TREE_TYPE (*node) = build_type_attribute_variant (type, t); |
5980 | |
5981 | return NULL_TREE; |
5982 | } |
5983 | |
5984 | /* Handle a "objc_root_class" attributes; arguments as in |
5985 | struct attribute_spec.handler. */ |
5986 | |
5987 | static tree |
5988 | handle_objc_root_class_attribute (tree */*node*/, tree name, tree /*args*/, |
5989 | int /*flags*/, bool *no_add_attrs) |
5990 | { |
5991 | /* This has no meaning outside Objective-C. */ |
5992 | if (!c_dialect_objc()) |
5993 | warning (OPT_Wattributes, "%qE is only applicable to Objective-C" |
5994 | " class interfaces, attribute ignored" , name); |
5995 | |
5996 | *no_add_attrs = true; |
5997 | return NULL_TREE; |
5998 | } |
5999 | |
6000 | /* Handle an "objc_nullability" attribute; arguments as in |
6001 | struct attribute_spec.handler. */ |
6002 | |
6003 | static tree |
6004 | handle_objc_nullability_attribute (tree *node, tree name, tree args, |
6005 | int /*flags*/, |
6006 | bool *no_add_attrs) |
6007 | { |
6008 | *no_add_attrs = true; |
6009 | |
6010 | tree type = TREE_TYPE (*node); |
6011 | if (TREE_CODE (*node) == FUNCTION_DECL) |
6012 | type = TREE_TYPE (type); |
6013 | |
6014 | if (type && !POINTER_TYPE_P (type)) |
6015 | { |
6016 | error ("%qE cannot be applied to non-pointer type %qT" , name, type); |
6017 | return NULL_TREE; |
6018 | } |
6019 | |
6020 | /* We accept objc_nullability() with a single argument. |
6021 | string: "unspecified", "nullable", "nonnull" or "resettable" |
6022 | integer: 0 and 3 where the values have the same meaning as |
6023 | the strings. */ |
6024 | tree val = TREE_VALUE (args); |
6025 | if (TREE_CODE (val) == INTEGER_CST) |
6026 | { |
6027 | val = default_conversion (val); |
6028 | if (!tree_fits_uhwi_p (val) || tree_to_uhwi (val) > 3) |
6029 | error ("%qE attribute argument %qE is not an integer constant" |
6030 | " between 0 and 3" , name, val); |
6031 | else |
6032 | *no_add_attrs = false; /* OK */ |
6033 | } |
6034 | else if (TREE_CODE (val) == STRING_CST |
6035 | && (strcmp (TREE_STRING_POINTER (val), s2: "nullable" ) == 0 |
6036 | || strcmp (TREE_STRING_POINTER (val), s2: "nonnull" ) == 0 |
6037 | || strcmp (TREE_STRING_POINTER (val), s2: "unspecified" ) == 0 |
6038 | || strcmp (TREE_STRING_POINTER (val), s2: "resettable" ) == 0)) |
6039 | *no_add_attrs = false; /* OK */ |
6040 | else if (val != error_mark_node) |
6041 | error ("%qE attribute argument %qE is not recognised" , name, val); |
6042 | |
6043 | return NULL_TREE; |
6044 | } |
6045 | |
6046 | /* Handle a "tainted_args" attribute; arguments as in |
6047 | struct attribute_spec.handler. */ |
6048 | |
6049 | static tree |
6050 | handle_tainted_args_attribute (tree *node, tree name, tree, int, |
6051 | bool *no_add_attrs) |
6052 | { |
6053 | if (TREE_CODE (*node) != FUNCTION_DECL |
6054 | && TREE_CODE (*node) != FIELD_DECL) |
6055 | { |
6056 | warning (OPT_Wattributes, "%qE attribute ignored; valid only " |
6057 | "for functions and function pointer fields" , |
6058 | name); |
6059 | *no_add_attrs = true; |
6060 | return NULL_TREE; |
6061 | } |
6062 | |
6063 | if (TREE_CODE (*node) == FIELD_DECL |
6064 | && !(TREE_CODE (TREE_TYPE (*node)) == POINTER_TYPE |
6065 | && TREE_CODE (TREE_TYPE (TREE_TYPE (*node))) == FUNCTION_TYPE)) |
6066 | { |
6067 | warning (OPT_Wattributes, "%qE attribute ignored;" |
6068 | " field must be a function pointer" , |
6069 | name); |
6070 | *no_add_attrs = true; |
6071 | return NULL_TREE; |
6072 | } |
6073 | |
6074 | *no_add_attrs = false; /* OK */ |
6075 | |
6076 | return NULL_TREE; |
6077 | } |
6078 | |
6079 | /* Attempt to partially validate a single attribute ATTR as if |
6080 | it were to be applied to an entity OPER. */ |
6081 | |
6082 | static bool |
6083 | validate_attribute (location_t atloc, tree oper, tree attr) |
6084 | { |
6085 | /* Determine whether the name of the attribute is valid |
6086 | and fail with an error if not. */ |
6087 | tree atname = get_attribute_name (attr); |
6088 | if (!lookup_attribute_spec (atname)) |
6089 | { |
6090 | if (atloc != UNKNOWN_LOCATION) |
6091 | error_at (atloc, "unknown attribute %qE" , atname); |
6092 | return false; |
6093 | } |
6094 | |
6095 | tree args = TREE_VALUE (attr); |
6096 | if (!args) |
6097 | return true; |
6098 | |
6099 | /* FIXME: Do some validation. */ |
6100 | const char *atstr = IDENTIFIER_POINTER (atname); |
6101 | if (!strcmp (s1: atstr, s2: "format" )) |
6102 | return true; |
6103 | |
6104 | /* Only when attribute arguments have been provided try to validate |
6105 | the whole thing. decl_attributes doesn't return an indication of |
6106 | success or failure so proceed regardless. */ |
6107 | const char tmpname[] = "__builtin_has_attribute_tmp." ; |
6108 | tree tmpid = get_identifier (tmpname); |
6109 | tree tmpdecl; |
6110 | if (!strcmp (s1: atstr, s2: "vector_size" )) |
6111 | { |
6112 | tree type = TYPE_P (oper) ? oper : TREE_TYPE (oper); |
6113 | /* Check for function type here since type_for_vector_size |
6114 | strips it while looking for a function's return type. */ |
6115 | if (FUNC_OR_METHOD_TYPE_P (type)) |
6116 | { |
6117 | warning_at (atloc, OPT_Wattributes, |
6118 | "invalid operand type %qT for %qs" , type, atstr); |
6119 | return false; |
6120 | } |
6121 | |
6122 | type = type_for_vector_size (type); |
6123 | if (VECTOR_TYPE_P (type)) |
6124 | type = TREE_TYPE (type); |
6125 | /* Avoid trying to apply attribute vector_size to OPER since |
6126 | it's overly restrictive. Simply make sure it has the right |
6127 | type. */ |
6128 | return type_valid_for_vector_size (type, atname, args, NULL); |
6129 | } |
6130 | |
6131 | if (TYPE_P (oper)) |
6132 | tmpdecl = build_decl (atloc, TYPE_DECL, tmpid, oper); |
6133 | else if (DECL_P (oper)) |
6134 | tmpdecl = build_decl (atloc, TREE_CODE (oper), tmpid, TREE_TYPE (oper)); |
6135 | else if (EXPR_P (oper)) |
6136 | tmpdecl = build_decl (atloc, TYPE_DECL, tmpid, TREE_TYPE (oper)); |
6137 | else |
6138 | return false; |
6139 | |
6140 | /* Temporarily clear CURRENT_FUNCTION_DECL to make decl_attributes |
6141 | believe the DECL declared above is at file scope. (See bug 87526.) */ |
6142 | tree save_curfunc = current_function_decl; |
6143 | current_function_decl = NULL_TREE; |
6144 | if (DECL_P (tmpdecl)) |
6145 | { |
6146 | if (DECL_P (oper)) |
6147 | /* An alias cannot be a definition so declare the symbol extern. */ |
6148 | DECL_EXTERNAL (tmpdecl) = true; |
6149 | /* Attribute visibility only applies to symbols visible from other |
6150 | translation units so make it "public." */ |
6151 | TREE_PUBLIC (tmpdecl) = TREE_PUBLIC (oper); |
6152 | } |
6153 | decl_attributes (&tmpdecl, attr, 0); |
6154 | current_function_decl = save_curfunc; |
6155 | |
6156 | /* FIXME: Change decl_attributes to indicate success or failure (and |
6157 | parameterize it to avoid failing with errors). */ |
6158 | return true; |
6159 | } |
6160 | |
6161 | /* Return true if the DECL, EXPR, or TYPE t has been declared with |
6162 | attribute ATTR. For DECL, consider also its type. For EXPR, |
6163 | consider just its type. */ |
6164 | |
6165 | bool |
6166 | has_attribute (location_t atloc, tree t, tree attr, tree (*convert)(tree)) |
6167 | { |
6168 | if (!attr || !t || t == error_mark_node) |
6169 | return false; |
6170 | |
6171 | if (!validate_attribute (atloc, oper: t, attr)) |
6172 | return false; |
6173 | |
6174 | tree type = NULL_TREE; |
6175 | tree expr = NULL_TREE; |
6176 | if (TYPE_P (t)) |
6177 | type = t; |
6178 | else |
6179 | { |
6180 | do |
6181 | { |
6182 | /* Determine the array element/member declaration from |
6183 | a COMPONENT_REF and an INDIRECT_REF involving a refeence. */ |
6184 | STRIP_NOPS (t); |
6185 | tree_code code = TREE_CODE (t); |
6186 | if (code == INDIRECT_REF) |
6187 | { |
6188 | tree op0 = TREE_OPERAND (t, 0); |
6189 | if (TREE_CODE (TREE_TYPE (op0)) == REFERENCE_TYPE) |
6190 | t = op0; |
6191 | else |
6192 | break; |
6193 | } |
6194 | else if (code == COMPONENT_REF) |
6195 | t = TREE_OPERAND (t, 1); |
6196 | else |
6197 | break; |
6198 | } while (true); |
6199 | expr = t; |
6200 | } |
6201 | |
6202 | /* Set to true when an attribute is found in the referenced entity |
6203 | that matches the specified attribute. */ |
6204 | bool found_match = false; |
6205 | |
6206 | tree atname = get_attribute_name (attr); |
6207 | const char *namestr = IDENTIFIER_POINTER (atname); |
6208 | |
6209 | /* Iterate once for a type and twice for a function or variable |
6210 | declaration: once for the DECL and the second time for its |
6211 | TYPE. */ |
6212 | for (bool done = false; !found_match && !done; ) |
6213 | { |
6214 | tree atlist; |
6215 | if (type) |
6216 | { |
6217 | if (type == error_mark_node) |
6218 | { |
6219 | /* This could be a label. FIXME: add support for labels. */ |
6220 | warning_at (atloc, OPT_Wattributes, |
6221 | (TYPE_P (t) |
6222 | ? G_("%qs attribute not supported for %qT " |
6223 | "in %<__builtin_has_attribute%>" ) |
6224 | : G_("%qs attribute not supported for %qE " |
6225 | "in %<__builtin_has_attribute%>" )), |
6226 | namestr, t); |
6227 | return false; |
6228 | } |
6229 | |
6230 | /* Clear EXPR to prevent considering it again below. */ |
6231 | atlist = TYPE_ATTRIBUTES (type); |
6232 | expr = NULL_TREE; |
6233 | done = true; |
6234 | } |
6235 | else if (DECL_P (expr)) |
6236 | { |
6237 | /* Set TYPE to the DECL's type to process it on the next |
6238 | iteration. */ |
6239 | atlist = DECL_ATTRIBUTES (expr); |
6240 | type = TREE_TYPE (expr); |
6241 | } |
6242 | else |
6243 | { |
6244 | type = TREE_TYPE (expr); |
6245 | atlist = TYPE_ATTRIBUTES (type); |
6246 | done = true; |
6247 | } |
6248 | |
6249 | /* True when an attribute with the sought name (though not necessarily |
6250 | with the sought attributes) has been found on the attribute chain. */ |
6251 | bool found_attr = false; |
6252 | |
6253 | /* When clear, the first mismatched attribute argument results |
6254 | in failure. Otherwise, the first matched attribute argument |
6255 | results in success. */ |
6256 | bool attr_nonnull = !strcmp (s1: "nonnull" , s2: namestr); |
6257 | bool ignore_mismatches = attr_nonnull; |
6258 | |
6259 | /* Iterate over the instances of the sought attribute on the DECL or |
6260 | TYPE (there may be multiple instances with different arguments). */ |
6261 | for (; (atlist = lookup_attribute (attr_name: namestr, list: atlist)); |
6262 | found_attr = true, atlist = TREE_CHAIN (atlist)) |
6263 | { |
6264 | /* If there are no arguments to match the result is true except |
6265 | for nonnull where the attribute with no arguments must match. */ |
6266 | if (!TREE_VALUE (attr)) |
6267 | return attr_nonnull ? !TREE_VALUE (atlist) : true; |
6268 | |
6269 | /* Attribute nonnull with no arguments subsumes all values of |
6270 | the attribute. FIXME: This is overly broad since it only |
6271 | applies to pointer arguments, but querying non-pointer |
6272 | arguments is diagnosed. */ |
6273 | if (!TREE_VALUE (atlist) && attr_nonnull) |
6274 | return true; |
6275 | |
6276 | /* Iterate over the DECL or TYPE attribute argument's values. */ |
6277 | for (tree val = TREE_VALUE (atlist); val; val = TREE_CHAIN (val)) |
6278 | { |
6279 | /* Iterate over the arguments in the sought attribute comparing |
6280 | their values to those specified for the DECL or TYPE. */ |
6281 | for (tree arg = TREE_VALUE (attr); arg; arg = TREE_CHAIN (arg)) |
6282 | { |
6283 | tree v1 = TREE_VALUE (val); |
6284 | tree v2 = TREE_VALUE (arg); |
6285 | if (v1 == v2) |
6286 | return true; |
6287 | |
6288 | if (!v1 || !v2) |
6289 | break; |
6290 | |
6291 | if (TREE_CODE (v1) == IDENTIFIER_NODE |
6292 | || TREE_CODE (v2) == IDENTIFIER_NODE) |
6293 | /* Two identifiers are the same if their values are |
6294 | equal (that's handled above). Otherwise ther are |
6295 | either not the same or oneis not an identifier. */ |
6296 | return false; |
6297 | |
6298 | /* Convert to make them equality-comparable. */ |
6299 | v1 = convert (v1); |
6300 | v2 = convert (v2); |
6301 | |
6302 | /* A positive value indicates equality, negative means |
6303 | "don't know." */ |
6304 | if (simple_cst_equal (v1, v2) == 1) |
6305 | return true; |
6306 | |
6307 | if (!ignore_mismatches) |
6308 | break; |
6309 | } |
6310 | } |
6311 | } |
6312 | |
6313 | if (!found_attr) |
6314 | { |
6315 | /* Some attributes are encoded directly in the tree node. */ |
6316 | if (!strcmp (s1: "aligned" , s2: namestr)) |
6317 | { |
6318 | if (tree arg = TREE_VALUE (attr)) |
6319 | { |
6320 | arg = convert (TREE_VALUE (arg)); |
6321 | if (!tree_fits_uhwi_p (arg)) |
6322 | /* Invalid argument. */; |
6323 | else if (expr && DECL_P (expr) |
6324 | && DECL_USER_ALIGN (expr)) |
6325 | found_match = DECL_ALIGN_UNIT (expr) == tree_to_uhwi (arg); |
6326 | else if (type && TYPE_USER_ALIGN (type)) |
6327 | found_match = TYPE_ALIGN_UNIT (type) == tree_to_uhwi (arg); |
6328 | } |
6329 | else if (expr && DECL_P (expr)) |
6330 | found_match = DECL_USER_ALIGN (expr); |
6331 | else if (type) |
6332 | found_match = TYPE_USER_ALIGN (type); |
6333 | } |
6334 | else if (!strcmp (s1: "const" , s2: namestr)) |
6335 | { |
6336 | if (expr && DECL_P (expr)) |
6337 | found_match = TREE_READONLY (expr); |
6338 | } |
6339 | else if (!strcmp (s1: "noreturn" , s2: namestr)) |
6340 | { |
6341 | /* C11 _Noreturn sets the volatile bit without attaching |
6342 | an attribute to the decl. */ |
6343 | if (expr |
6344 | && DECL_P (expr) |
6345 | && FUNC_OR_METHOD_TYPE_P (TREE_TYPE (expr))) |
6346 | found_match = TREE_THIS_VOLATILE (expr); |
6347 | } |
6348 | else if (!strcmp (s1: "pure" , s2: namestr)) |
6349 | { |
6350 | if (expr && DECL_P (expr)) |
6351 | found_match = DECL_PURE_P (expr); |
6352 | } |
6353 | else if (!strcmp (s1: "deprecated" , s2: namestr)) |
6354 | { |
6355 | found_match = TREE_DEPRECATED (expr ? expr : type); |
6356 | if (found_match) |
6357 | return true; |
6358 | } |
6359 | else if (!strcmp (s1: "vector_size" , s2: namestr)) |
6360 | { |
6361 | if (!type || !VECTOR_TYPE_P (type)) |
6362 | return false; |
6363 | |
6364 | if (tree arg = TREE_VALUE (attr)) |
6365 | { |
6366 | /* Compare the vector size argument for equality. */ |
6367 | arg = convert (TREE_VALUE (arg)); |
6368 | return tree_int_cst_equal (arg, TYPE_SIZE_UNIT (type)) == 1; |
6369 | } |
6370 | else |
6371 | return true; |
6372 | } |
6373 | else if (!strcmp (s1: "warn_if_not_aligned" , s2: namestr)) |
6374 | { |
6375 | if (tree arg = TREE_VALUE (attr)) |
6376 | { |
6377 | arg = convert (TREE_VALUE (arg)); |
6378 | if (expr && DECL_P (expr)) |
6379 | found_match = (DECL_WARN_IF_NOT_ALIGN (expr) |
6380 | == tree_to_uhwi (arg) * BITS_PER_UNIT); |
6381 | else if (type) |
6382 | found_match = (TYPE_WARN_IF_NOT_ALIGN (type) |
6383 | == tree_to_uhwi (arg) * BITS_PER_UNIT); |
6384 | } |
6385 | else if (expr && DECL_P (expr)) |
6386 | found_match = DECL_WARN_IF_NOT_ALIGN (expr); |
6387 | else if (type) |
6388 | found_match = TYPE_WARN_IF_NOT_ALIGN (type); |
6389 | } |
6390 | else if (!strcmp (s1: "transparent_union" , s2: namestr)) |
6391 | { |
6392 | if (type) |
6393 | found_match = TYPE_TRANSPARENT_AGGR (type) != 0; |
6394 | } |
6395 | else if (!strcmp (s1: "mode" , s2: namestr)) |
6396 | { |
6397 | /* Finally issue a warning for attributes that cannot |
6398 | be supported in this context. Attribute mode is not |
6399 | added to a symbol and cannot be determined from it. */ |
6400 | warning_at (atloc, OPT_Wattributes, |
6401 | "%qs attribute not supported in " |
6402 | "%<__builtin_has_attribute%>" , namestr); |
6403 | break; |
6404 | } |
6405 | } |
6406 | } |
6407 | return found_match; |
6408 | } |
6409 | |