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