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