File: | build/gcc/vec.h |
Warning: | line 815, column 10 Called C++ object pointer is null |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* Handle #pragma, system V.4 style. Supports #pragma weak and #pragma pack. | |||
2 | Copyright (C) 1992-2021 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 | #include "config.h" | |||
21 | #include "system.h" | |||
22 | #include "coretypes.h" | |||
23 | #include "target.h" | |||
24 | #include "function.h" /* For cfun. */ | |||
25 | #include "c-common.h" | |||
26 | #include "memmodel.h" | |||
27 | #include "tm_p.h" /* For REGISTER_TARGET_PRAGMAS. */ | |||
28 | #include "stringpool.h" | |||
29 | #include "cgraph.h" | |||
30 | #include "diagnostic.h" | |||
31 | #include "attribs.h" | |||
32 | #include "varasm.h" | |||
33 | #include "c-pragma.h" | |||
34 | #include "opts.h" | |||
35 | #include "plugin.h" | |||
36 | #include "opt-suggestions.h" | |||
37 | ||||
38 | #define GCC_BAD(gmsgid)do { warning (OPT_Wpragmas, gmsgid); return; } while (0) \ | |||
39 | do { warning (OPT_Wpragmas, gmsgid); return; } while (0) | |||
40 | #define GCC_BAD2(gmsgid, arg)do { warning (OPT_Wpragmas, gmsgid, arg); return; } while (0) \ | |||
41 | do { warning (OPT_Wpragmas, gmsgid, arg); return; } while (0) | |||
42 | ||||
43 | struct GTY(()) align_stack { | |||
44 | int alignment; | |||
45 | tree id; | |||
46 | struct align_stack * prev; | |||
47 | }; | |||
48 | ||||
49 | static GTY(()) struct align_stack * alignment_stack; | |||
50 | ||||
51 | static void handle_pragma_pack (cpp_reader *); | |||
52 | ||||
53 | /* If we have a "global" #pragma pack(<n>) in effect when the first | |||
54 | #pragma pack(push,<n>) is encountered, this stores the value of | |||
55 | maximum_field_alignment in effect. When the final pop_alignment() | |||
56 | happens, we restore the value to this, not to a value of 0 for | |||
57 | maximum_field_alignment. Value is in bits. */ | |||
58 | static int default_alignment; | |||
59 | #define SET_GLOBAL_ALIGNMENT(ALIGN)(maximum_field_alignment = *(alignment_stack == nullptr ? & default_alignment : &alignment_stack->alignment) = (ALIGN )) (maximum_field_alignment = *(alignment_stack == NULLnullptr \ | |||
60 | ? &default_alignment \ | |||
61 | : &alignment_stack->alignment) = (ALIGN)) | |||
62 | ||||
63 | static void push_alignment (int, tree); | |||
64 | static void pop_alignment (tree); | |||
65 | ||||
66 | /* Push an alignment value onto the stack. */ | |||
67 | static void | |||
68 | push_alignment (int alignment, tree id) | |||
69 | { | |||
70 | align_stack * entry = ggc_alloc<align_stack> (); | |||
71 | ||||
72 | entry->alignment = alignment; | |||
73 | entry->id = id; | |||
74 | entry->prev = alignment_stack; | |||
75 | ||||
76 | /* The current value of maximum_field_alignment is not necessarily | |||
77 | 0 since there may be a #pragma pack(<n>) in effect; remember it | |||
78 | so that we can restore it after the final #pragma pop(). */ | |||
79 | if (alignment_stack == NULLnullptr) | |||
80 | default_alignment = maximum_field_alignment; | |||
81 | ||||
82 | alignment_stack = entry; | |||
83 | ||||
84 | maximum_field_alignment = alignment; | |||
85 | } | |||
86 | ||||
87 | /* Undo a push of an alignment onto the stack. */ | |||
88 | static void | |||
89 | pop_alignment (tree id) | |||
90 | { | |||
91 | align_stack * entry; | |||
92 | ||||
93 | if (alignment_stack == NULLnullptr) | |||
94 | GCC_BAD ("%<#pragma pack (pop)%> encountered without matching "do { warning (OPT_Wpragmas, "%<#pragma pack (pop)%> encountered without matching " "%<#pragma pack (push)%>"); return; } while (0) | |||
95 | "%<#pragma pack (push)%>")do { warning (OPT_Wpragmas, "%<#pragma pack (pop)%> encountered without matching " "%<#pragma pack (push)%>"); return; } while (0); | |||
96 | ||||
97 | /* If we got an identifier, strip away everything above the target | |||
98 | entry so that the next step will restore the state just below it. */ | |||
99 | if (id) | |||
100 | { | |||
101 | for (entry = alignment_stack; entry; entry = entry->prev) | |||
102 | if (entry->id == id) | |||
103 | { | |||
104 | alignment_stack = entry; | |||
105 | break; | |||
106 | } | |||
107 | if (entry == NULLnullptr) | |||
108 | warning (OPT_Wpragmas, | |||
109 | "%<#pragma pack(pop, %E)%> encountered without matching " | |||
110 | "%<#pragma pack(push, %E)%>" | |||
111 | , id, id); | |||
112 | } | |||
113 | ||||
114 | entry = alignment_stack->prev; | |||
115 | ||||
116 | maximum_field_alignment = entry ? entry->alignment : default_alignment; | |||
117 | ||||
118 | alignment_stack = entry; | |||
119 | } | |||
120 | ||||
121 | /* #pragma pack () | |||
122 | #pragma pack (N) | |||
123 | ||||
124 | #pragma pack (push) | |||
125 | #pragma pack (push, N) | |||
126 | #pragma pack (push, ID) | |||
127 | #pragma pack (push, ID, N) | |||
128 | #pragma pack (pop) | |||
129 | #pragma pack (pop, ID) */ | |||
130 | static void | |||
131 | handle_pragma_pack (cpp_reader * ARG_UNUSED (dummy)dummy __attribute__ ((__unused__))) | |||
132 | { | |||
133 | tree x, id = 0; | |||
134 | int align = -1; | |||
135 | enum cpp_ttype token; | |||
136 | enum { set, push, pop } action; | |||
137 | ||||
138 | if (pragma_lex (&x) != CPP_OPEN_PAREN) | |||
139 | GCC_BAD ("missing %<(%> after %<#pragma pack%> - ignored")do { warning (OPT_Wpragmas, "missing %<(%> after %<#pragma pack%> - ignored" ); return; } while (0); | |||
140 | ||||
141 | token = pragma_lex (&x); | |||
142 | if (token == CPP_CLOSE_PAREN) | |||
143 | { | |||
144 | action = set; | |||
145 | align = initial_max_fld_alignglobal_options.x_initial_max_fld_align; | |||
146 | } | |||
147 | else if (token == CPP_NUMBER) | |||
148 | { | |||
149 | if (TREE_CODE (x)((enum tree_code) (x)->base.code) != INTEGER_CST) | |||
150 | GCC_BAD ("invalid constant in %<#pragma pack%> - ignored")do { warning (OPT_Wpragmas, "invalid constant in %<#pragma pack%> - ignored" ); return; } while (0); | |||
151 | align = TREE_INT_CST_LOW (x)((unsigned long) (*tree_int_cst_elt_check ((x), (0), "/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/c-family/c-pragma.c" , 151, __FUNCTION__))); | |||
152 | action = set; | |||
153 | if (pragma_lex (&x) != CPP_CLOSE_PAREN) | |||
154 | GCC_BAD ("malformed %<#pragma pack%> - ignored")do { warning (OPT_Wpragmas, "malformed %<#pragma pack%> - ignored" ); return; } while (0); | |||
155 | } | |||
156 | else if (token == CPP_NAME) | |||
157 | { | |||
158 | #define GCC_BAD_ACTION do { if (action != pop) \ | |||
159 | GCC_BAD ("malformed %<#pragma pack(push[, id][, <n>])%> - ignored")do { warning (OPT_Wpragmas, "malformed %<#pragma pack(push[, id][, <n>])%> - ignored" ); return; } while (0); \ | |||
160 | else \ | |||
161 | GCC_BAD ("malformed %<#pragma pack(pop[, id])%> - ignored")do { warning (OPT_Wpragmas, "malformed %<#pragma pack(pop[, id])%> - ignored" ); return; } while (0); \ | |||
162 | } while (0) | |||
163 | ||||
164 | const char *op = IDENTIFIER_POINTER (x)((const char *) (tree_check ((x), "/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/c-family/c-pragma.c" , 164, __FUNCTION__, (IDENTIFIER_NODE)))->identifier.id.str ); | |||
165 | if (!strcmp (op, "push")) | |||
166 | action = push; | |||
167 | else if (!strcmp (op, "pop")) | |||
168 | action = pop; | |||
169 | else | |||
170 | GCC_BAD2 ("unknown action %qE for %<#pragma pack%> - ignored", x)do { warning (OPT_Wpragmas, "unknown action %qE for %<#pragma pack%> - ignored" , x); return; } while (0); | |||
171 | ||||
172 | while ((token = pragma_lex (&x)) == CPP_COMMA) | |||
173 | { | |||
174 | token = pragma_lex (&x); | |||
175 | if (token == CPP_NAME && id == 0) | |||
176 | { | |||
177 | id = x; | |||
178 | } | |||
179 | else if (token == CPP_NUMBER && action == push && align == -1) | |||
180 | { | |||
181 | if (TREE_CODE (x)((enum tree_code) (x)->base.code) != INTEGER_CST) | |||
182 | GCC_BAD ("invalid constant in %<#pragma pack%> - ignored")do { warning (OPT_Wpragmas, "invalid constant in %<#pragma pack%> - ignored" ); return; } while (0); | |||
183 | align = TREE_INT_CST_LOW (x)((unsigned long) (*tree_int_cst_elt_check ((x), (0), "/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/c-family/c-pragma.c" , 183, __FUNCTION__))); | |||
184 | if (align == -1) | |||
185 | action = set; | |||
186 | } | |||
187 | else | |||
188 | GCC_BAD_ACTION; | |||
189 | } | |||
190 | ||||
191 | if (token != CPP_CLOSE_PAREN) | |||
192 | GCC_BAD_ACTION; | |||
193 | #undef GCC_BAD_ACTION | |||
194 | } | |||
195 | else | |||
196 | GCC_BAD ("malformed %<#pragma pack%> - ignored")do { warning (OPT_Wpragmas, "malformed %<#pragma pack%> - ignored" ); return; } while (0); | |||
197 | ||||
198 | if (pragma_lex (&x) != CPP_EOF) | |||
199 | warning (OPT_Wpragmas, "junk at end of %<#pragma pack%>"); | |||
200 | ||||
201 | if (flag_pack_structglobal_options.x_flag_pack_struct) | |||
202 | GCC_BAD ("%<#pragma pack%> has no effect with %<-fpack-struct%> - ignored")do { warning (OPT_Wpragmas, "%<#pragma pack%> has no effect with %<-fpack-struct%> - ignored" ); return; } while (0); | |||
203 | ||||
204 | if (action != pop) | |||
205 | switch (align) | |||
206 | { | |||
207 | case 0: | |||
208 | case 1: | |||
209 | case 2: | |||
210 | case 4: | |||
211 | case 8: | |||
212 | case 16: | |||
213 | align *= BITS_PER_UNIT(8); | |||
214 | break; | |||
215 | case -1: | |||
216 | if (action == push) | |||
217 | { | |||
218 | align = maximum_field_alignment; | |||
219 | break; | |||
220 | } | |||
221 | /* FALLTHRU */ | |||
222 | default: | |||
223 | GCC_BAD2 ("alignment must be a small power of two, not %d", align)do { warning (OPT_Wpragmas, "alignment must be a small power of two, not %d" , align); return; } while (0); | |||
224 | } | |||
225 | ||||
226 | switch (action) | |||
227 | { | |||
228 | case set: SET_GLOBAL_ALIGNMENT (align)(maximum_field_alignment = *(alignment_stack == nullptr ? & default_alignment : &alignment_stack->alignment) = (align )); break; | |||
229 | case push: push_alignment (align, id); break; | |||
230 | case pop: pop_alignment (id); break; | |||
231 | } | |||
232 | } | |||
233 | ||||
234 | struct GTY(()) pending_weak | |||
235 | { | |||
236 | tree name; | |||
237 | tree value; | |||
238 | }; | |||
239 | ||||
240 | ||||
241 | static GTY(()) vec<pending_weak, va_gc> *pending_weaks; | |||
242 | ||||
243 | static void apply_pragma_weak (tree, tree); | |||
244 | static void handle_pragma_weak (cpp_reader *); | |||
245 | ||||
246 | static void | |||
247 | apply_pragma_weak (tree decl, tree value) | |||
248 | { | |||
249 | if (value) | |||
250 | { | |||
251 | value = build_string (IDENTIFIER_LENGTH (value)((tree_check ((value), "/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/c-family/c-pragma.c" , 251, __FUNCTION__, (IDENTIFIER_NODE)))->identifier.id.len ), | |||
252 | IDENTIFIER_POINTER (value)((const char *) (tree_check ((value), "/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/c-family/c-pragma.c" , 252, __FUNCTION__, (IDENTIFIER_NODE)))->identifier.id.str )); | |||
253 | decl_attributes (&decl, build_tree_list (get_identifier ("alias")(__builtin_constant_p ("alias") ? get_identifier_with_length ( ("alias"), strlen ("alias")) : get_identifier ("alias")), | |||
254 | build_tree_list (NULLnullptr, value)), | |||
255 | 0); | |||
256 | } | |||
257 | ||||
258 | if (SUPPORTS_WEAK1 && DECL_EXTERNAL (decl)((contains_struct_check ((decl), (TS_DECL_COMMON), "/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/c-family/c-pragma.c" , 258, __FUNCTION__))->decl_common.decl_flag_1) && TREE_USED (decl)((decl)->base.used_flag) | |||
259 | && !DECL_WEAK (decl)((contains_struct_check ((decl), (TS_DECL_WITH_VIS), "/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/c-family/c-pragma.c" , 259, __FUNCTION__))->decl_with_vis.weak_flag) /* Don't complain about a redundant #pragma. */ | |||
260 | && DECL_ASSEMBLER_NAME_SET_P (decl)(((contains_struct_check ((decl), (TS_DECL_WITH_VIS), "/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/c-family/c-pragma.c" , 260, __FUNCTION__))->decl_with_vis.assembler_name) != (tree ) nullptr) | |||
261 | && TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl))((tree_check ((decl_assembler_name (decl)), "/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/c-family/c-pragma.c" , 261, __FUNCTION__, (IDENTIFIER_NODE)))->base.static_flag )) | |||
262 | warning (OPT_Wpragmas, "applying %<#pragma weak %+D%> after first use " | |||
263 | "results in unspecified behavior", decl); | |||
264 | ||||
265 | declare_weak (decl); | |||
266 | } | |||
267 | ||||
268 | void | |||
269 | maybe_apply_pragma_weak (tree decl) | |||
270 | { | |||
271 | tree id; | |||
272 | int i; | |||
273 | pending_weak *pe; | |||
274 | ||||
275 | /* Avoid asking for DECL_ASSEMBLER_NAME when it's not needed. */ | |||
276 | ||||
277 | /* No weak symbols pending, take the short-cut. */ | |||
278 | if (vec_safe_is_empty (pending_weaks)) | |||
279 | return; | |||
280 | /* If it's not visible outside this file, it doesn't matter whether | |||
281 | it's weak. */ | |||
282 | if (!DECL_EXTERNAL (decl)((contains_struct_check ((decl), (TS_DECL_COMMON), "/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/c-family/c-pragma.c" , 282, __FUNCTION__))->decl_common.decl_flag_1) && !TREE_PUBLIC (decl)((decl)->base.public_flag)) | |||
283 | return; | |||
284 | /* If it's not a function or a variable, it can't be weak. | |||
285 | FIXME: what kinds of things are visible outside this file but | |||
286 | aren't functions or variables? Should this be an assert instead? */ | |||
287 | if (!VAR_OR_FUNCTION_DECL_P (decl)(((enum tree_code) (decl)->base.code) == VAR_DECL || ((enum tree_code) (decl)->base.code) == FUNCTION_DECL)) | |||
288 | return; | |||
289 | ||||
290 | if (DECL_ASSEMBLER_NAME_SET_P (decl)(((contains_struct_check ((decl), (TS_DECL_WITH_VIS), "/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/c-family/c-pragma.c" , 290, __FUNCTION__))->decl_with_vis.assembler_name) != (tree ) nullptr)) | |||
291 | id = DECL_ASSEMBLER_NAME (decl)decl_assembler_name (decl); | |||
292 | else | |||
293 | { | |||
294 | id = DECL_ASSEMBLER_NAME (decl)decl_assembler_name (decl); | |||
295 | SET_DECL_ASSEMBLER_NAME (decl, NULL_TREE)overwrite_decl_assembler_name (decl, (tree) nullptr); | |||
296 | } | |||
297 | ||||
298 | FOR_EACH_VEC_ELT (*pending_weaks, i, pe)for (i = 0; (*pending_weaks).iterate ((i), &(pe)); ++(i)) | |||
299 | if (id == pe->name) | |||
300 | { | |||
301 | apply_pragma_weak (decl, pe->value); | |||
302 | pending_weaks->unordered_remove (i); | |||
303 | break; | |||
304 | } | |||
305 | } | |||
306 | ||||
307 | /* Process all "#pragma weak A = B" directives where we have not seen | |||
308 | a decl for A. */ | |||
309 | void | |||
310 | maybe_apply_pending_pragma_weaks (void) | |||
311 | { | |||
312 | tree alias_id, id, decl; | |||
313 | int i; | |||
314 | pending_weak *pe; | |||
315 | symtab_node *target; | |||
316 | ||||
317 | if (vec_safe_is_empty (pending_weaks)) | |||
318 | return; | |||
319 | ||||
320 | FOR_EACH_VEC_ELT (*pending_weaks, i, pe)for (i = 0; (*pending_weaks).iterate ((i), &(pe)); ++(i)) | |||
321 | { | |||
322 | alias_id = pe->name; | |||
323 | id = pe->value; | |||
324 | ||||
325 | if (id == NULLnullptr) | |||
326 | continue; | |||
327 | ||||
328 | target = symtab_node::get_for_asmname (id); | |||
329 | decl = build_decl (UNKNOWN_LOCATION((location_t) 0), | |||
330 | target ? TREE_CODE (target->decl)((enum tree_code) (target->decl)->base.code) : FUNCTION_DECL, | |||
331 | alias_id, default_function_typec_global_trees[CTI_DEFAULT_FUNCTION_TYPE]); | |||
332 | ||||
333 | DECL_ARTIFICIAL (decl)((contains_struct_check ((decl), (TS_DECL_COMMON), "/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/c-family/c-pragma.c" , 333, __FUNCTION__))->decl_common.artificial_flag) = 1; | |||
334 | TREE_PUBLIC (decl)((decl)->base.public_flag) = 1; | |||
335 | DECL_WEAK (decl)((contains_struct_check ((decl), (TS_DECL_WITH_VIS), "/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/c-family/c-pragma.c" , 335, __FUNCTION__))->decl_with_vis.weak_flag) = 1; | |||
336 | if (VAR_P (decl)(((enum tree_code) (decl)->base.code) == VAR_DECL)) | |||
337 | TREE_STATIC (decl)((decl)->base.static_flag) = 1; | |||
338 | if (!target) | |||
339 | { | |||
340 | error ("%q+D aliased to undefined symbol %qE", | |||
341 | decl, id); | |||
342 | continue; | |||
343 | } | |||
344 | ||||
345 | assemble_alias (decl, id); | |||
346 | } | |||
347 | } | |||
348 | ||||
349 | /* #pragma weak name [= value] */ | |||
350 | static void | |||
351 | handle_pragma_weak (cpp_reader * ARG_UNUSED (dummy)dummy __attribute__ ((__unused__))) | |||
352 | { | |||
353 | tree name, value, x, decl; | |||
354 | enum cpp_ttype t; | |||
355 | ||||
356 | value = 0; | |||
357 | ||||
358 | if (pragma_lex (&name) != CPP_NAME) | |||
| ||||
359 | GCC_BAD ("malformed %<#pragma weak%>, ignored")do { warning (OPT_Wpragmas, "malformed %<#pragma weak%>, ignored" ); return; } while (0); | |||
360 | t = pragma_lex (&x); | |||
361 | if (t == CPP_EQ) | |||
362 | { | |||
363 | if (pragma_lex (&value) != CPP_NAME) | |||
364 | GCC_BAD ("malformed %<#pragma weak%>, ignored")do { warning (OPT_Wpragmas, "malformed %<#pragma weak%>, ignored" ); return; } while (0); | |||
365 | t = pragma_lex (&x); | |||
366 | } | |||
367 | if (t != CPP_EOF) | |||
368 | warning (OPT_Wpragmas, "junk at end of %<#pragma weak%>"); | |||
369 | ||||
370 | decl = identifier_global_value (name); | |||
371 | if (decl && DECL_P (decl)(tree_code_type[(int) (((enum tree_code) (decl)->base.code ))] == tcc_declaration)) | |||
372 | { | |||
373 | if (!VAR_OR_FUNCTION_DECL_P (decl)(((enum tree_code) (decl)->base.code) == VAR_DECL || ((enum tree_code) (decl)->base.code) == FUNCTION_DECL)) | |||
374 | GCC_BAD2 ("%<#pragma weak%> declaration of %q+D not allowed,"do { warning (OPT_Wpragmas, "%<#pragma weak%> declaration of %q+D not allowed," " ignored", decl); return; } while (0) | |||
375 | " ignored", decl)do { warning (OPT_Wpragmas, "%<#pragma weak%> declaration of %q+D not allowed," " ignored", decl); return; } while (0); | |||
376 | apply_pragma_weak (decl, value); | |||
377 | if (value) | |||
378 | { | |||
379 | DECL_EXTERNAL (decl)((contains_struct_check ((decl), (TS_DECL_COMMON), "/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/c-family/c-pragma.c" , 379, __FUNCTION__))->decl_common.decl_flag_1) = 0; | |||
380 | if (VAR_P (decl)(((enum tree_code) (decl)->base.code) == VAR_DECL)) | |||
381 | TREE_STATIC (decl)((decl)->base.static_flag) = 1; | |||
382 | assemble_alias (decl, value); | |||
383 | } | |||
384 | } | |||
385 | else | |||
386 | { | |||
387 | pending_weak pe = {name, value}; | |||
388 | vec_safe_push (pending_weaks, pe); | |||
389 | } | |||
390 | } | |||
391 | ||||
392 | static enum scalar_storage_order_kind global_sso; | |||
393 | ||||
394 | void | |||
395 | maybe_apply_pragma_scalar_storage_order (tree type) | |||
396 | { | |||
397 | if (global_sso == SSO_NATIVE) | |||
398 | return; | |||
399 | ||||
400 | gcc_assert (RECORD_OR_UNION_TYPE_P (type))((void)(!((((enum tree_code) (type)->base.code) == RECORD_TYPE || ((enum tree_code) (type)->base.code) == UNION_TYPE || ( (enum tree_code) (type)->base.code) == QUAL_UNION_TYPE)) ? fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/c-family/c-pragma.c" , 400, __FUNCTION__), 0 : 0)); | |||
401 | ||||
402 | if (lookup_attribute ("scalar_storage_order", TYPE_ATTRIBUTES (type)((tree_class_check ((type), (tcc_type), "/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/c-family/c-pragma.c" , 402, __FUNCTION__))->type_common.attributes))) | |||
403 | return; | |||
404 | ||||
405 | if (global_sso == SSO_BIG_ENDIAN) | |||
406 | TYPE_REVERSE_STORAGE_ORDER (type)((tree_check4 ((type), "/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/c-family/c-pragma.c" , 406, __FUNCTION__, (RECORD_TYPE), (UNION_TYPE), (QUAL_UNION_TYPE ), (ARRAY_TYPE)))->base.u.bits.saturating_flag) = !BYTES_BIG_ENDIAN0; | |||
407 | else if (global_sso == SSO_LITTLE_ENDIAN) | |||
408 | TYPE_REVERSE_STORAGE_ORDER (type)((tree_check4 ((type), "/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/c-family/c-pragma.c" , 408, __FUNCTION__, (RECORD_TYPE), (UNION_TYPE), (QUAL_UNION_TYPE ), (ARRAY_TYPE)))->base.u.bits.saturating_flag) = BYTES_BIG_ENDIAN0; | |||
409 | else | |||
410 | gcc_unreachable ()(fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/c-family/c-pragma.c" , 410, __FUNCTION__)); | |||
411 | } | |||
412 | ||||
413 | static void | |||
414 | handle_pragma_scalar_storage_order (cpp_reader *ARG_UNUSED(dummy)dummy __attribute__ ((__unused__))) | |||
415 | { | |||
416 | const char *kind_string; | |||
417 | enum cpp_ttype token; | |||
418 | tree x; | |||
419 | ||||
420 | if (BYTES_BIG_ENDIAN0 != WORDS_BIG_ENDIAN0) | |||
421 | { | |||
422 | error ("%<scalar_storage_order%> is not supported because endianness " | |||
423 | "is not uniform"); | |||
424 | return; | |||
425 | } | |||
426 | ||||
427 | if (c_dialect_cxx ()((c_language & clk_cxx) != 0)) | |||
428 | { | |||
429 | if (warn_unknown_pragmasglobal_options.x_warn_unknown_pragmas > in_system_header_at (input_location)) | |||
430 | warning (OPT_Wunknown_pragmas, | |||
431 | "%<#pragma scalar_storage_order%> is not supported for C++"); | |||
432 | return; | |||
433 | } | |||
434 | ||||
435 | token = pragma_lex (&x); | |||
436 | if (token != CPP_NAME) | |||
437 | GCC_BAD ("missing [big-endian|little-endian|default] after %<#pragma scalar_storage_order%>")do { warning (OPT_Wpragmas, "missing [big-endian|little-endian|default] after %<#pragma scalar_storage_order%>" ); return; } while (0); | |||
438 | kind_string = IDENTIFIER_POINTER (x)((const char *) (tree_check ((x), "/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/c-family/c-pragma.c" , 438, __FUNCTION__, (IDENTIFIER_NODE)))->identifier.id.str ); | |||
439 | if (strcmp (kind_string, "default") == 0) | |||
440 | global_sso = default_ssoglobal_options.x_default_sso; | |||
441 | else if (strcmp (kind_string, "big") == 0) | |||
442 | global_sso = SSO_BIG_ENDIAN; | |||
443 | else if (strcmp (kind_string, "little") == 0) | |||
444 | global_sso = SSO_LITTLE_ENDIAN; | |||
445 | else | |||
446 | GCC_BAD ("expected [big-endian|little-endian|default] after %<#pragma scalar_storage_order%>")do { warning (OPT_Wpragmas, "expected [big-endian|little-endian|default] after %<#pragma scalar_storage_order%>" ); return; } while (0); | |||
447 | } | |||
448 | ||||
449 | /* GCC supports two #pragma directives for renaming the external | |||
450 | symbol associated with a declaration (DECL_ASSEMBLER_NAME), for | |||
451 | compatibility with the Solaris and VMS system headers. GCC also | |||
452 | has its own notation for this, __asm__("name") annotations. | |||
453 | ||||
454 | Corner cases of these features and their interaction: | |||
455 | ||||
456 | 1) Both pragmas silently apply only to declarations with external | |||
457 | linkage (that is, TREE_PUBLIC || DECL_EXTERNAL). Asm labels | |||
458 | do not have this restriction. | |||
459 | ||||
460 | 2) In C++, both #pragmas silently apply only to extern "C" declarations. | |||
461 | Asm labels do not have this restriction. | |||
462 | ||||
463 | 3) If any of the three ways of changing DECL_ASSEMBLER_NAME is | |||
464 | applied to a decl whose DECL_ASSEMBLER_NAME is already set, and the | |||
465 | new name is different, a warning issues and the name does not change. | |||
466 | ||||
467 | 4) The "source name" for #pragma redefine_extname is the DECL_NAME, | |||
468 | *not* the DECL_ASSEMBLER_NAME. | |||
469 | ||||
470 | 5) If #pragma extern_prefix is in effect and a declaration occurs | |||
471 | with an __asm__ name, the #pragma extern_prefix is silently | |||
472 | ignored for that declaration. | |||
473 | ||||
474 | 6) If #pragma extern_prefix and #pragma redefine_extname apply to | |||
475 | the same declaration, whichever triggered first wins, and a warning | |||
476 | is issued. (We would like to have #pragma redefine_extname always | |||
477 | win, but it can appear either before or after the declaration, and | |||
478 | if it appears afterward, we have no way of knowing whether a modified | |||
479 | DECL_ASSEMBLER_NAME is due to #pragma extern_prefix.) */ | |||
480 | ||||
481 | struct GTY(()) pending_redefinition { | |||
482 | tree oldname; | |||
483 | tree newname; | |||
484 | }; | |||
485 | ||||
486 | ||||
487 | static GTY(()) vec<pending_redefinition, va_gc> *pending_redefine_extname; | |||
488 | ||||
489 | static void handle_pragma_redefine_extname (cpp_reader *); | |||
490 | ||||
491 | /* #pragma redefine_extname oldname newname */ | |||
492 | static void | |||
493 | handle_pragma_redefine_extname (cpp_reader * ARG_UNUSED (dummy)dummy __attribute__ ((__unused__))) | |||
494 | { | |||
495 | tree oldname, newname, decls, x; | |||
496 | enum cpp_ttype t; | |||
497 | bool found; | |||
498 | ||||
499 | if (pragma_lex (&oldname) != CPP_NAME) | |||
500 | GCC_BAD ("malformed %<#pragma redefine_extname%>, ignored")do { warning (OPT_Wpragmas, "malformed %<#pragma redefine_extname%>, ignored" ); return; } while (0); | |||
501 | if (pragma_lex (&newname) != CPP_NAME) | |||
502 | GCC_BAD ("malformed %<#pragma redefine_extname%>, ignored")do { warning (OPT_Wpragmas, "malformed %<#pragma redefine_extname%>, ignored" ); return; } while (0); | |||
503 | t = pragma_lex (&x); | |||
504 | if (t != CPP_EOF) | |||
505 | warning (OPT_Wpragmas, "junk at end of %<#pragma redefine_extname%>"); | |||
506 | ||||
507 | found = false; | |||
508 | for (decls = c_linkage_bindings (oldname); | |||
509 | decls; ) | |||
510 | { | |||
511 | tree decl; | |||
512 | if (TREE_CODE (decls)((enum tree_code) (decls)->base.code) == TREE_LIST) | |||
513 | { | |||
514 | decl = TREE_VALUE (decls)((tree_check ((decls), "/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/c-family/c-pragma.c" , 514, __FUNCTION__, (TREE_LIST)))->list.value); | |||
515 | decls = TREE_CHAIN (decls)((contains_struct_check ((decls), (TS_COMMON), "/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/c-family/c-pragma.c" , 515, __FUNCTION__))->common.chain); | |||
516 | } | |||
517 | else | |||
518 | { | |||
519 | decl = decls; | |||
520 | decls = NULL_TREE(tree) nullptr; | |||
521 | } | |||
522 | ||||
523 | if ((TREE_PUBLIC (decl)((decl)->base.public_flag) || DECL_EXTERNAL (decl)((contains_struct_check ((decl), (TS_DECL_COMMON), "/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/c-family/c-pragma.c" , 523, __FUNCTION__))->decl_common.decl_flag_1)) | |||
524 | && VAR_OR_FUNCTION_DECL_P (decl)(((enum tree_code) (decl)->base.code) == VAR_DECL || ((enum tree_code) (decl)->base.code) == FUNCTION_DECL)) | |||
525 | { | |||
526 | found = true; | |||
527 | if (DECL_ASSEMBLER_NAME_SET_P (decl)(((contains_struct_check ((decl), (TS_DECL_WITH_VIS), "/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/c-family/c-pragma.c" , 527, __FUNCTION__))->decl_with_vis.assembler_name) != (tree ) nullptr)) | |||
528 | { | |||
529 | const char *name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl))((const char *) (tree_check ((decl_assembler_name (decl)), "/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/c-family/c-pragma.c" , 529, __FUNCTION__, (IDENTIFIER_NODE)))->identifier.id.str ); | |||
530 | name = targetm.strip_name_encoding (name); | |||
531 | ||||
532 | if (!id_equal (newname, name)) | |||
533 | warning (OPT_Wpragmas, "%<#pragma redefine_extname%> " | |||
534 | "ignored due to conflict with previous rename"); | |||
535 | } | |||
536 | else | |||
537 | symtab->change_decl_assembler_name (decl, newname); | |||
538 | } | |||
539 | } | |||
540 | ||||
541 | if (!found) | |||
542 | /* We have to add this to the rename list even if there's already | |||
543 | a global value that doesn't meet the above criteria, because in | |||
544 | C++ "struct foo {...};" puts "foo" in the current namespace but | |||
545 | does *not* conflict with a subsequent declaration of a function | |||
546 | or variable foo. See g++.dg/other/pragma-re-2.C. */ | |||
547 | add_to_renaming_pragma_list (oldname, newname); | |||
548 | } | |||
549 | ||||
550 | /* This is called from here and from ia64-c.c. */ | |||
551 | void | |||
552 | add_to_renaming_pragma_list (tree oldname, tree newname) | |||
553 | { | |||
554 | unsigned ix; | |||
555 | pending_redefinition *p; | |||
556 | ||||
557 | FOR_EACH_VEC_SAFE_ELT (pending_redefine_extname, ix, p)for (ix = 0; vec_safe_iterate ((pending_redefine_extname), (ix ), &(p)); ++(ix)) | |||
558 | if (oldname == p->oldname) | |||
559 | { | |||
560 | if (p->newname != newname) | |||
561 | warning (OPT_Wpragmas, "%<#pragma redefine_extname%> ignored due to " | |||
562 | "conflict with previous %<#pragma redefine_extname%>"); | |||
563 | return; | |||
564 | } | |||
565 | ||||
566 | pending_redefinition e = {oldname, newname}; | |||
567 | vec_safe_push (pending_redefine_extname, e); | |||
568 | } | |||
569 | ||||
570 | /* The current prefix set by #pragma extern_prefix. */ | |||
571 | GTY(()) tree pragma_extern_prefix; | |||
572 | ||||
573 | /* Hook from the front ends to apply the results of one of the preceding | |||
574 | pragmas that rename variables. */ | |||
575 | ||||
576 | tree | |||
577 | maybe_apply_renaming_pragma (tree decl, tree asmname) | |||
578 | { | |||
579 | unsigned ix; | |||
580 | pending_redefinition *p; | |||
581 | ||||
582 | /* The renaming pragmas are only applied to declarations with | |||
583 | external linkage. */ | |||
584 | if (!VAR_OR_FUNCTION_DECL_P (decl)(((enum tree_code) (decl)->base.code) == VAR_DECL || ((enum tree_code) (decl)->base.code) == FUNCTION_DECL) | |||
585 | || (!TREE_PUBLIC (decl)((decl)->base.public_flag) && !DECL_EXTERNAL (decl)((contains_struct_check ((decl), (TS_DECL_COMMON), "/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/c-family/c-pragma.c" , 585, __FUNCTION__))->decl_common.decl_flag_1)) | |||
586 | || !has_c_linkage (decl)) | |||
587 | return asmname; | |||
588 | ||||
589 | /* If the DECL_ASSEMBLER_NAME is already set, it does not change, | |||
590 | but we may warn about a rename that conflicts. */ | |||
591 | if (DECL_ASSEMBLER_NAME_SET_P (decl)(((contains_struct_check ((decl), (TS_DECL_WITH_VIS), "/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/c-family/c-pragma.c" , 591, __FUNCTION__))->decl_with_vis.assembler_name) != (tree ) nullptr)) | |||
592 | { | |||
593 | const char *oldname = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl))((const char *) (tree_check ((decl_assembler_name (decl)), "/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/c-family/c-pragma.c" , 593, __FUNCTION__, (IDENTIFIER_NODE)))->identifier.id.str ); | |||
594 | oldname = targetm.strip_name_encoding (oldname); | |||
595 | ||||
596 | if (asmname && strcmp (TREE_STRING_POINTER (asmname)((const char *)((tree_check ((asmname), "/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/c-family/c-pragma.c" , 596, __FUNCTION__, (STRING_CST)))->string.str)), oldname)) | |||
597 | warning (OPT_Wpragmas, "%<asm%> declaration ignored due to " | |||
598 | "conflict with previous rename"); | |||
599 | ||||
600 | /* Take any pending redefine_extname off the list. */ | |||
601 | FOR_EACH_VEC_SAFE_ELT (pending_redefine_extname, ix, p)for (ix = 0; vec_safe_iterate ((pending_redefine_extname), (ix ), &(p)); ++(ix)) | |||
602 | if (DECL_NAME (decl)((contains_struct_check ((decl), (TS_DECL_MINIMAL), "/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/c-family/c-pragma.c" , 602, __FUNCTION__))->decl_minimal.name) == p->oldname) | |||
603 | { | |||
604 | /* Only warn if there is a conflict. */ | |||
605 | if (!id_equal (p->newname, oldname)) | |||
606 | warning (OPT_Wpragmas, "%<#pragma redefine_extname%> ignored " | |||
607 | "due to conflict with previous rename"); | |||
608 | ||||
609 | pending_redefine_extname->unordered_remove (ix); | |||
610 | break; | |||
611 | } | |||
612 | return NULL_TREE(tree) nullptr; | |||
613 | } | |||
614 | ||||
615 | /* Find out if we have a pending #pragma redefine_extname. */ | |||
616 | FOR_EACH_VEC_SAFE_ELT (pending_redefine_extname, ix, p)for (ix = 0; vec_safe_iterate ((pending_redefine_extname), (ix ), &(p)); ++(ix)) | |||
617 | if (DECL_NAME (decl)((contains_struct_check ((decl), (TS_DECL_MINIMAL), "/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/c-family/c-pragma.c" , 617, __FUNCTION__))->decl_minimal.name) == p->oldname) | |||
618 | { | |||
619 | tree newname = p->newname; | |||
620 | pending_redefine_extname->unordered_remove (ix); | |||
621 | ||||
622 | /* If we already have an asmname, #pragma redefine_extname is | |||
623 | ignored (with a warning if it conflicts). */ | |||
624 | if (asmname) | |||
625 | { | |||
626 | if (strcmp (TREE_STRING_POINTER (asmname)((const char *)((tree_check ((asmname), "/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/c-family/c-pragma.c" , 626, __FUNCTION__, (STRING_CST)))->string.str)), | |||
627 | IDENTIFIER_POINTER (newname)((const char *) (tree_check ((newname), "/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/c-family/c-pragma.c" , 627, __FUNCTION__, (IDENTIFIER_NODE)))->identifier.id.str )) != 0) | |||
628 | warning (OPT_Wpragmas, "%<#pragma redefine_extname%> ignored " | |||
629 | "due to conflict with %<asm%> declaration"); | |||
630 | return asmname; | |||
631 | } | |||
632 | ||||
633 | /* Otherwise we use what we've got; #pragma extern_prefix is | |||
634 | silently ignored. */ | |||
635 | return build_string (IDENTIFIER_LENGTH (newname)((tree_check ((newname), "/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/c-family/c-pragma.c" , 635, __FUNCTION__, (IDENTIFIER_NODE)))->identifier.id.len ), | |||
636 | IDENTIFIER_POINTER (newname)((const char *) (tree_check ((newname), "/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/c-family/c-pragma.c" , 636, __FUNCTION__, (IDENTIFIER_NODE)))->identifier.id.str )); | |||
637 | } | |||
638 | ||||
639 | /* If we've got an asmname, #pragma extern_prefix is silently ignored. */ | |||
640 | if (asmname) | |||
641 | return asmname; | |||
642 | ||||
643 | /* If #pragma extern_prefix is in effect, apply it. */ | |||
644 | if (pragma_extern_prefix) | |||
645 | { | |||
646 | const char *prefix = TREE_STRING_POINTER (pragma_extern_prefix)((const char *)((tree_check ((pragma_extern_prefix), "/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/c-family/c-pragma.c" , 646, __FUNCTION__, (STRING_CST)))->string.str)); | |||
647 | size_t plen = TREE_STRING_LENGTH (pragma_extern_prefix)((tree_check ((pragma_extern_prefix), "/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/c-family/c-pragma.c" , 647, __FUNCTION__, (STRING_CST)))->string.length) - 1; | |||
648 | ||||
649 | const char *id = IDENTIFIER_POINTER (DECL_NAME (decl))((const char *) (tree_check ((((contains_struct_check ((decl) , (TS_DECL_MINIMAL), "/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/c-family/c-pragma.c" , 649, __FUNCTION__))->decl_minimal.name)), "/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/c-family/c-pragma.c" , 649, __FUNCTION__, (IDENTIFIER_NODE)))->identifier.id.str ); | |||
650 | size_t ilen = IDENTIFIER_LENGTH (DECL_NAME (decl))((tree_check ((((contains_struct_check ((decl), (TS_DECL_MINIMAL ), "/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/c-family/c-pragma.c" , 650, __FUNCTION__))->decl_minimal.name)), "/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/c-family/c-pragma.c" , 650, __FUNCTION__, (IDENTIFIER_NODE)))->identifier.id.len ); | |||
651 | ||||
652 | char *newname = (char *) alloca (plen + ilen + 1)__builtin_alloca(plen + ilen + 1); | |||
653 | ||||
654 | memcpy (newname, prefix, plen); | |||
655 | memcpy (newname + plen, id, ilen + 1); | |||
656 | ||||
657 | return build_string (plen + ilen, newname); | |||
658 | } | |||
659 | ||||
660 | /* Nada. */ | |||
661 | return NULL_TREE(tree) nullptr; | |||
662 | } | |||
663 | ||||
664 | ||||
665 | static void handle_pragma_visibility (cpp_reader *); | |||
666 | ||||
667 | static vec<int> visstack; | |||
668 | ||||
669 | /* Push the visibility indicated by STR onto the top of the #pragma | |||
670 | visibility stack. KIND is 0 for #pragma GCC visibility, 1 for | |||
671 | C++ namespace with visibility attribute and 2 for C++ builtin | |||
672 | ABI namespace. push_visibility/pop_visibility calls must have | |||
673 | matching KIND, it is not allowed to push visibility using one | |||
674 | KIND and pop using a different one. */ | |||
675 | ||||
676 | void | |||
677 | push_visibility (const char *str, int kind) | |||
678 | { | |||
679 | visstack.safe_push (((int) default_visibilityglobal_options.x_default_visibility) | (kind << 8)); | |||
680 | if (!strcmp (str, "default")) | |||
681 | default_visibilityglobal_options.x_default_visibility = VISIBILITY_DEFAULT; | |||
682 | else if (!strcmp (str, "internal")) | |||
683 | default_visibilityglobal_options.x_default_visibility = VISIBILITY_INTERNAL; | |||
684 | else if (!strcmp (str, "hidden")) | |||
685 | default_visibilityglobal_options.x_default_visibility = VISIBILITY_HIDDEN; | |||
686 | else if (!strcmp (str, "protected")) | |||
687 | default_visibilityglobal_options.x_default_visibility = VISIBILITY_PROTECTED; | |||
688 | else | |||
689 | GCC_BAD ("%<#pragma GCC visibility push()%> must specify %<default%>, "do { warning (OPT_Wpragmas, "%<#pragma GCC visibility push()%> must specify %<default%>, " "%<internal%>, %<hidden%> or %<protected%>" ); return; } while (0) | |||
690 | "%<internal%>, %<hidden%> or %<protected%>")do { warning (OPT_Wpragmas, "%<#pragma GCC visibility push()%> must specify %<default%>, " "%<internal%>, %<hidden%> or %<protected%>" ); return; } while (0); | |||
691 | visibility_options.inpragma = 1; | |||
692 | } | |||
693 | ||||
694 | /* Pop a level of the #pragma visibility stack. Return true if | |||
695 | successful. */ | |||
696 | ||||
697 | bool | |||
698 | pop_visibility (int kind) | |||
699 | { | |||
700 | if (!visstack.length ()) | |||
701 | return false; | |||
702 | if ((visstack.last () >> 8) != kind) | |||
703 | return false; | |||
704 | default_visibilityglobal_options.x_default_visibility | |||
705 | = (enum symbol_visibility) (visstack.pop () & 0xff); | |||
706 | visibility_options.inpragma | |||
707 | = visstack.length () != 0; | |||
708 | return true; | |||
709 | } | |||
710 | ||||
711 | /* Sets the default visibility for symbols to something other than that | |||
712 | specified on the command line. */ | |||
713 | ||||
714 | static void | |||
715 | handle_pragma_visibility (cpp_reader *dummy ATTRIBUTE_UNUSED__attribute__ ((__unused__))) | |||
716 | { | |||
717 | /* Form is #pragma GCC visibility push(hidden)|pop */ | |||
718 | tree x; | |||
719 | enum cpp_ttype token; | |||
720 | enum { bad, push, pop } action = bad; | |||
721 | ||||
722 | token = pragma_lex (&x); | |||
723 | if (token == CPP_NAME) | |||
724 | { | |||
725 | const char *op = IDENTIFIER_POINTER (x)((const char *) (tree_check ((x), "/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/c-family/c-pragma.c" , 725, __FUNCTION__, (IDENTIFIER_NODE)))->identifier.id.str ); | |||
726 | if (!strcmp (op, "push")) | |||
727 | action = push; | |||
728 | else if (!strcmp (op, "pop")) | |||
729 | action = pop; | |||
730 | } | |||
731 | if (bad == action) | |||
732 | GCC_BAD ("%<#pragma GCC visibility%> must be followed by %<push%> "do { warning (OPT_Wpragmas, "%<#pragma GCC visibility%> must be followed by %<push%> " "or %<pop%>"); return; } while (0) | |||
733 | "or %<pop%>")do { warning (OPT_Wpragmas, "%<#pragma GCC visibility%> must be followed by %<push%> " "or %<pop%>"); return; } while (0); | |||
734 | else | |||
735 | { | |||
736 | if (pop == action) | |||
737 | { | |||
738 | if (! pop_visibility (0)) | |||
739 | GCC_BAD ("no matching push for %<#pragma GCC visibility pop%>")do { warning (OPT_Wpragmas, "no matching push for %<#pragma GCC visibility pop%>" ); return; } while (0); | |||
740 | } | |||
741 | else | |||
742 | { | |||
743 | if (pragma_lex (&x) != CPP_OPEN_PAREN) | |||
744 | GCC_BAD ("missing %<(%> after %<#pragma GCC visibility push%> - ignored")do { warning (OPT_Wpragmas, "missing %<(%> after %<#pragma GCC visibility push%> - ignored" ); return; } while (0); | |||
745 | token = pragma_lex (&x); | |||
746 | if (token != CPP_NAME) | |||
747 | GCC_BAD ("malformed %<#pragma GCC visibility push%>")do { warning (OPT_Wpragmas, "malformed %<#pragma GCC visibility push%>" ); return; } while (0); | |||
748 | else | |||
749 | push_visibility (IDENTIFIER_POINTER (x)((const char *) (tree_check ((x), "/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/c-family/c-pragma.c" , 749, __FUNCTION__, (IDENTIFIER_NODE)))->identifier.id.str ), 0); | |||
750 | if (pragma_lex (&x) != CPP_CLOSE_PAREN) | |||
751 | GCC_BAD ("missing %<(%> after %<#pragma GCC visibility push%> - ignored")do { warning (OPT_Wpragmas, "missing %<(%> after %<#pragma GCC visibility push%> - ignored" ); return; } while (0); | |||
752 | } | |||
753 | } | |||
754 | if (pragma_lex (&x) != CPP_EOF) | |||
755 | warning (OPT_Wpragmas, "junk at end of %<#pragma GCC visibility%>"); | |||
756 | } | |||
757 | ||||
758 | static void | |||
759 | handle_pragma_diagnostic(cpp_reader *ARG_UNUSED(dummy)dummy __attribute__ ((__unused__))) | |||
760 | { | |||
761 | tree x; | |||
762 | location_t loc; | |||
763 | enum cpp_ttype token = pragma_lex (&x, &loc); | |||
764 | if (token != CPP_NAME) | |||
765 | { | |||
766 | warning_at (loc, OPT_Wpragmas, | |||
767 | "missing [error|warning|ignored|push|pop]" | |||
768 | " after %<#pragma GCC diagnostic%>"); | |||
769 | return; | |||
770 | } | |||
771 | ||||
772 | diagnostic_t kind; | |||
773 | const char *kind_string = IDENTIFIER_POINTER (x)((const char *) (tree_check ((x), "/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/c-family/c-pragma.c" , 773, __FUNCTION__, (IDENTIFIER_NODE)))->identifier.id.str ); | |||
774 | if (strcmp (kind_string, "error") == 0) | |||
775 | kind = DK_ERROR; | |||
776 | else if (strcmp (kind_string, "warning") == 0) | |||
777 | kind = DK_WARNING; | |||
778 | else if (strcmp (kind_string, "ignored") == 0) | |||
779 | kind = DK_IGNORED; | |||
780 | else if (strcmp (kind_string, "push") == 0) | |||
781 | { | |||
782 | diagnostic_push_diagnostics (global_dc, input_location); | |||
783 | return; | |||
784 | } | |||
785 | else if (strcmp (kind_string, "pop") == 0) | |||
786 | { | |||
787 | diagnostic_pop_diagnostics (global_dc, input_location); | |||
788 | return; | |||
789 | } | |||
790 | else | |||
791 | { | |||
792 | warning_at (loc, OPT_Wpragmas, | |||
793 | "expected [error|warning|ignored|push|pop]" | |||
794 | " after %<#pragma GCC diagnostic%>"); | |||
795 | return; | |||
796 | } | |||
797 | ||||
798 | token = pragma_lex (&x, &loc); | |||
799 | if (token != CPP_STRING) | |||
800 | { | |||
801 | warning_at (loc, OPT_Wpragmas, | |||
802 | "missing option after %<#pragma GCC diagnostic%> kind"); | |||
803 | return; | |||
804 | } | |||
805 | ||||
806 | const char *option_string = TREE_STRING_POINTER (x)((const char *)((tree_check ((x), "/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/c-family/c-pragma.c" , 806, __FUNCTION__, (STRING_CST)))->string.str)); | |||
807 | unsigned int lang_mask = c_common_option_lang_mask () | CL_COMMON(1U << 21); | |||
808 | /* option_string + 1 to skip the initial '-' */ | |||
809 | unsigned int option_index = find_opt (option_string + 1, lang_mask); | |||
810 | if (option_index == OPT_SPECIAL_unknown) | |||
811 | { | |||
812 | auto_diagnostic_group d; | |||
813 | if (warning_at (loc, OPT_Wpragmas, | |||
814 | "unknown option after %<#pragma GCC diagnostic%> kind")) | |||
815 | { | |||
816 | option_proposer op; | |||
817 | const char *hint = op.suggest_option (option_string + 1); | |||
818 | if (hint) | |||
819 | inform (loc, "did you mean %<-%s%>?", hint); | |||
820 | } | |||
821 | return; | |||
822 | } | |||
823 | else if (!(cl_options[option_index].flags & CL_WARNING(1U << 17))) | |||
824 | { | |||
825 | warning_at (loc, OPT_Wpragmas, | |||
826 | "%qs is not an option that controls warnings", option_string); | |||
827 | return; | |||
828 | } | |||
829 | else if (!(cl_options[option_index].flags & lang_mask)) | |||
830 | { | |||
831 | char *ok_langs = write_langs (cl_options[option_index].flags); | |||
832 | char *bad_lang = write_langs (c_common_option_lang_mask ()); | |||
833 | warning_at (loc, OPT_Wpragmas, | |||
834 | "option %qs is valid for %s but not for %s", | |||
835 | option_string, ok_langs, bad_lang); | |||
836 | free (ok_langs); | |||
837 | free (bad_lang); | |||
838 | return; | |||
839 | } | |||
840 | ||||
841 | struct cl_option_handlers handlers; | |||
842 | set_default_handlers (&handlers, NULLnullptr); | |||
843 | const char *arg = NULLnullptr; | |||
844 | if (cl_options[option_index].flags & CL_JOINED(1U << 22)) | |||
845 | arg = option_string + 1 + cl_options[option_index].opt_len; | |||
846 | /* FIXME: input_location isn't the best location here, but it is | |||
847 | what we used to do here before and changing it breaks e.g. | |||
848 | PR69543 and PR69558. */ | |||
849 | control_warning_option (option_index, (int) kind, | |||
850 | arg, kind != DK_IGNORED, | |||
851 | input_location, lang_mask, &handlers, | |||
852 | &global_options, &global_options_set, | |||
853 | global_dc); | |||
854 | } | |||
855 | ||||
856 | /* Parse #pragma GCC target (xxx) to set target specific options. */ | |||
857 | static void | |||
858 | handle_pragma_target(cpp_reader *ARG_UNUSED(dummy)dummy __attribute__ ((__unused__))) | |||
859 | { | |||
860 | enum cpp_ttype token; | |||
861 | tree x; | |||
862 | bool close_paren_needed_p = false; | |||
863 | ||||
864 | if (cfun(cfun + 0)) | |||
865 | { | |||
866 | error ("%<#pragma GCC option%> is not allowed inside functions"); | |||
867 | return; | |||
868 | } | |||
869 | ||||
870 | token = pragma_lex (&x); | |||
871 | if (token == CPP_OPEN_PAREN) | |||
872 | { | |||
873 | close_paren_needed_p = true; | |||
874 | token = pragma_lex (&x); | |||
875 | } | |||
876 | ||||
877 | if (token != CPP_STRING) | |||
878 | { | |||
879 | GCC_BAD ("%<#pragma GCC option%> is not a string")do { warning (OPT_Wpragmas, "%<#pragma GCC option%> is not a string" ); return; } while (0); | |||
880 | return; | |||
881 | } | |||
882 | ||||
883 | /* Strings are user options. */ | |||
884 | else | |||
885 | { | |||
886 | tree args = NULL_TREE(tree) nullptr; | |||
887 | ||||
888 | do | |||
889 | { | |||
890 | /* Build up the strings now as a tree linked list. Skip empty | |||
891 | strings. */ | |||
892 | if (TREE_STRING_LENGTH (x)((tree_check ((x), "/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/c-family/c-pragma.c" , 892, __FUNCTION__, (STRING_CST)))->string.length) > 0) | |||
893 | args = tree_cons (NULL_TREE(tree) nullptr, x, args); | |||
894 | ||||
895 | token = pragma_lex (&x); | |||
896 | while (token == CPP_COMMA) | |||
897 | token = pragma_lex (&x); | |||
898 | } | |||
899 | while (token == CPP_STRING); | |||
900 | ||||
901 | if (close_paren_needed_p) | |||
902 | { | |||
903 | if (token == CPP_CLOSE_PAREN) | |||
904 | token = pragma_lex (&x); | |||
905 | else | |||
906 | GCC_BAD ("%<#pragma GCC target (string [,string]...)%> does "do { warning (OPT_Wpragmas, "%<#pragma GCC target (string [,string]...)%> does " "not have a final %<)%>"); return; } while (0) | |||
907 | "not have a final %<)%>")do { warning (OPT_Wpragmas, "%<#pragma GCC target (string [,string]...)%> does " "not have a final %<)%>"); return; } while (0); | |||
908 | } | |||
909 | ||||
910 | if (token != CPP_EOF) | |||
911 | { | |||
912 | error ("%<#pragma GCC target%> string is badly formed"); | |||
913 | return; | |||
914 | } | |||
915 | ||||
916 | /* put arguments in the order the user typed them. */ | |||
917 | args = nreverse (args); | |||
918 | ||||
919 | if (targetm.target_option.pragma_parse (args, NULL_TREE(tree) nullptr)) | |||
920 | current_target_pragmaglobal_trees[TI_CURRENT_TARGET_PRAGMA] = chainon (current_target_pragmaglobal_trees[TI_CURRENT_TARGET_PRAGMA], args); | |||
921 | } | |||
922 | } | |||
923 | ||||
924 | /* Handle #pragma GCC optimize to set optimization options. */ | |||
925 | static void | |||
926 | handle_pragma_optimize (cpp_reader *ARG_UNUSED(dummy)dummy __attribute__ ((__unused__))) | |||
927 | { | |||
928 | enum cpp_ttype token; | |||
929 | tree x; | |||
930 | bool close_paren_needed_p = false; | |||
931 | tree optimization_previous_node = optimization_current_nodeglobal_trees[TI_OPTIMIZATION_CURRENT]; | |||
932 | ||||
933 | if (cfun(cfun + 0)) | |||
934 | { | |||
935 | error ("%<#pragma GCC optimize%> is not allowed inside functions"); | |||
936 | return; | |||
937 | } | |||
938 | ||||
939 | token = pragma_lex (&x); | |||
940 | if (token == CPP_OPEN_PAREN) | |||
941 | { | |||
942 | close_paren_needed_p = true; | |||
943 | token = pragma_lex (&x); | |||
944 | } | |||
945 | ||||
946 | if (token != CPP_STRING && token != CPP_NUMBER) | |||
947 | { | |||
948 | GCC_BAD ("%<#pragma GCC optimize%> is not a string or number")do { warning (OPT_Wpragmas, "%<#pragma GCC optimize%> is not a string or number" ); return; } while (0); | |||
949 | return; | |||
950 | } | |||
951 | ||||
952 | /* Strings/numbers are user options. */ | |||
953 | else | |||
954 | { | |||
955 | tree args = NULL_TREE(tree) nullptr; | |||
956 | ||||
957 | do | |||
958 | { | |||
959 | /* Build up the numbers/strings now as a list. */ | |||
960 | if (token != CPP_STRING || TREE_STRING_LENGTH (x)((tree_check ((x), "/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/c-family/c-pragma.c" , 960, __FUNCTION__, (STRING_CST)))->string.length) > 0) | |||
961 | args = tree_cons (NULL_TREE(tree) nullptr, x, args); | |||
962 | ||||
963 | token = pragma_lex (&x); | |||
964 | while (token == CPP_COMMA) | |||
965 | token = pragma_lex (&x); | |||
966 | } | |||
967 | while (token == CPP_STRING || token == CPP_NUMBER); | |||
968 | ||||
969 | if (close_paren_needed_p) | |||
970 | { | |||
971 | if (token == CPP_CLOSE_PAREN) | |||
972 | token = pragma_lex (&x); | |||
973 | else | |||
974 | GCC_BAD ("%<#pragma GCC optimize (string [,string]...)%> does "do { warning (OPT_Wpragmas, "%<#pragma GCC optimize (string [,string]...)%> does " "not have a final %<)%>"); return; } while (0) | |||
975 | "not have a final %<)%>")do { warning (OPT_Wpragmas, "%<#pragma GCC optimize (string [,string]...)%> does " "not have a final %<)%>"); return; } while (0); | |||
976 | } | |||
977 | ||||
978 | if (token != CPP_EOF) | |||
979 | { | |||
980 | error ("%<#pragma GCC optimize%> string is badly formed"); | |||
981 | return; | |||
982 | } | |||
983 | ||||
984 | /* put arguments in the order the user typed them. */ | |||
985 | args = nreverse (args); | |||
986 | ||||
987 | parse_optimize_options (args, false); | |||
988 | current_optimize_pragmaglobal_trees[TI_CURRENT_OPTIMIZE_PRAGMA] = chainon (current_optimize_pragmaglobal_trees[TI_CURRENT_OPTIMIZE_PRAGMA], args); | |||
989 | optimization_current_nodeglobal_trees[TI_OPTIMIZATION_CURRENT] | |||
990 | = build_optimization_node (&global_options, &global_options_set); | |||
991 | c_cpp_builtins_optimize_pragma (parse_in, | |||
992 | optimization_previous_node, | |||
993 | optimization_current_nodeglobal_trees[TI_OPTIMIZATION_CURRENT]); | |||
994 | } | |||
995 | } | |||
996 | ||||
997 | /* Stack of the #pragma GCC options created with #pragma GCC push_option. Save | |||
998 | both the binary representation of the options and the TREE_LIST of | |||
999 | strings that will be added to the function's attribute list. */ | |||
1000 | struct GTY(()) opt_stack { | |||
1001 | struct opt_stack *prev; | |||
1002 | tree target_binary; | |||
1003 | tree target_strings; | |||
1004 | tree optimize_binary; | |||
1005 | tree optimize_strings; | |||
1006 | gcc_options * GTY ((skip)) saved_global_options; | |||
1007 | }; | |||
1008 | ||||
1009 | static GTY(()) struct opt_stack * options_stack; | |||
1010 | ||||
1011 | /* Handle #pragma GCC push_options to save the current target and optimization | |||
1012 | options. */ | |||
1013 | ||||
1014 | static void | |||
1015 | handle_pragma_push_options (cpp_reader *ARG_UNUSED(dummy)dummy __attribute__ ((__unused__))) | |||
1016 | { | |||
1017 | enum cpp_ttype token; | |||
1018 | tree x = 0; | |||
1019 | ||||
1020 | token = pragma_lex (&x); | |||
1021 | if (token != CPP_EOF) | |||
1022 | { | |||
1023 | warning (OPT_Wpragmas, "junk at end of %<#pragma push_options%>"); | |||
1024 | return; | |||
1025 | } | |||
1026 | ||||
1027 | opt_stack *p = ggc_alloc<opt_stack> (); | |||
1028 | p->prev = options_stack; | |||
1029 | options_stack = p; | |||
1030 | ||||
1031 | /* Save optimization and target flags in binary format. */ | |||
1032 | if (flag_checkingglobal_options.x_flag_checking) | |||
1033 | { | |||
1034 | p->saved_global_options = XNEW (gcc_options)((gcc_options *) xmalloc (sizeof (gcc_options))); | |||
1035 | *p->saved_global_options = global_options; | |||
1036 | } | |||
1037 | p->optimize_binary = build_optimization_node (&global_options, | |||
1038 | &global_options_set); | |||
1039 | p->target_binary = build_target_option_node (&global_options, | |||
1040 | &global_options_set); | |||
1041 | ||||
1042 | /* Save optimization and target flags in string list format. */ | |||
1043 | p->optimize_strings = copy_list (current_optimize_pragmaglobal_trees[TI_CURRENT_OPTIMIZE_PRAGMA]); | |||
1044 | p->target_strings = copy_list (current_target_pragmaglobal_trees[TI_CURRENT_TARGET_PRAGMA]); | |||
1045 | } | |||
1046 | ||||
1047 | /* Handle #pragma GCC pop_options to restore the current target and | |||
1048 | optimization options from a previous push_options. */ | |||
1049 | ||||
1050 | static void | |||
1051 | handle_pragma_pop_options (cpp_reader *ARG_UNUSED(dummy)dummy __attribute__ ((__unused__))) | |||
1052 | { | |||
1053 | enum cpp_ttype token; | |||
1054 | tree x = 0; | |||
1055 | opt_stack *p; | |||
1056 | ||||
1057 | token = pragma_lex (&x); | |||
1058 | if (token != CPP_EOF) | |||
1059 | { | |||
1060 | warning (OPT_Wpragmas, "junk at end of %<#pragma pop_options%>"); | |||
1061 | return; | |||
1062 | } | |||
1063 | ||||
1064 | if (! options_stack) | |||
1065 | { | |||
1066 | warning (OPT_Wpragmas, | |||
1067 | "%<#pragma GCC pop_options%> without a corresponding " | |||
1068 | "%<#pragma GCC push_options%>"); | |||
1069 | return; | |||
1070 | } | |||
1071 | ||||
1072 | p = options_stack; | |||
1073 | options_stack = p->prev; | |||
1074 | ||||
1075 | if (p->target_binary != target_option_current_nodeglobal_trees[TI_TARGET_OPTION_CURRENT]) | |||
1076 | { | |||
1077 | (void) targetm.target_option.pragma_parse (NULL_TREE(tree) nullptr, p->target_binary); | |||
1078 | target_option_current_nodeglobal_trees[TI_TARGET_OPTION_CURRENT] = p->target_binary; | |||
1079 | } | |||
1080 | ||||
1081 | if (p->optimize_binary != optimization_current_nodeglobal_trees[TI_OPTIMIZATION_CURRENT]) | |||
1082 | { | |||
1083 | tree old_optimize = optimization_current_nodeglobal_trees[TI_OPTIMIZATION_CURRENT]; | |||
1084 | cl_optimization_restore (&global_options, &global_options_set, | |||
1085 | TREE_OPTIMIZATION (p->optimize_binary)((tree_check ((p->optimize_binary), "/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/c-family/c-pragma.c" , 1085, __FUNCTION__, (OPTIMIZATION_NODE)))->optimization. opts)); | |||
1086 | c_cpp_builtins_optimize_pragma (parse_in, old_optimize, | |||
1087 | p->optimize_binary); | |||
1088 | optimization_current_nodeglobal_trees[TI_OPTIMIZATION_CURRENT] = p->optimize_binary; | |||
1089 | } | |||
1090 | if (flag_checkingglobal_options.x_flag_checking) | |||
1091 | { | |||
1092 | cl_optimization_compare (p->saved_global_options, &global_options); | |||
1093 | free (p->saved_global_options); | |||
1094 | } | |||
1095 | ||||
1096 | current_target_pragmaglobal_trees[TI_CURRENT_TARGET_PRAGMA] = p->target_strings; | |||
1097 | current_optimize_pragmaglobal_trees[TI_CURRENT_OPTIMIZE_PRAGMA] = p->optimize_strings; | |||
1098 | } | |||
1099 | ||||
1100 | /* Handle #pragma GCC reset_options to restore the current target and | |||
1101 | optimization options to the original options used on the command line. */ | |||
1102 | ||||
1103 | static void | |||
1104 | handle_pragma_reset_options (cpp_reader *ARG_UNUSED(dummy)dummy __attribute__ ((__unused__))) | |||
1105 | { | |||
1106 | enum cpp_ttype token; | |||
1107 | tree x = 0; | |||
1108 | tree new_optimize = optimization_default_nodeglobal_trees[TI_OPTIMIZATION_DEFAULT]; | |||
1109 | tree new_target = target_option_default_nodeglobal_trees[TI_TARGET_OPTION_DEFAULT]; | |||
1110 | ||||
1111 | token = pragma_lex (&x); | |||
1112 | if (token != CPP_EOF) | |||
1113 | { | |||
1114 | warning (OPT_Wpragmas, "junk at end of %<#pragma reset_options%>"); | |||
1115 | return; | |||
1116 | } | |||
1117 | ||||
1118 | if (new_target != target_option_current_nodeglobal_trees[TI_TARGET_OPTION_CURRENT]) | |||
1119 | { | |||
1120 | (void) targetm.target_option.pragma_parse (NULL_TREE(tree) nullptr, new_target); | |||
1121 | target_option_current_nodeglobal_trees[TI_TARGET_OPTION_CURRENT] = new_target; | |||
1122 | } | |||
1123 | ||||
1124 | if (new_optimize != optimization_current_nodeglobal_trees[TI_OPTIMIZATION_CURRENT]) | |||
1125 | { | |||
1126 | tree old_optimize = optimization_current_nodeglobal_trees[TI_OPTIMIZATION_CURRENT]; | |||
1127 | cl_optimization_restore (&global_options, &global_options_set, | |||
1128 | TREE_OPTIMIZATION (new_optimize)((tree_check ((new_optimize), "/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/c-family/c-pragma.c" , 1128, __FUNCTION__, (OPTIMIZATION_NODE)))->optimization. opts)); | |||
1129 | c_cpp_builtins_optimize_pragma (parse_in, old_optimize, new_optimize); | |||
1130 | optimization_current_nodeglobal_trees[TI_OPTIMIZATION_CURRENT] = new_optimize; | |||
1131 | } | |||
1132 | ||||
1133 | current_target_pragmaglobal_trees[TI_CURRENT_TARGET_PRAGMA] = NULL_TREE(tree) nullptr; | |||
1134 | current_optimize_pragmaglobal_trees[TI_CURRENT_OPTIMIZE_PRAGMA] = NULL_TREE(tree) nullptr; | |||
1135 | } | |||
1136 | ||||
1137 | /* Print a plain user-specified message. */ | |||
1138 | ||||
1139 | static void | |||
1140 | handle_pragma_message (cpp_reader *ARG_UNUSED(dummy)dummy __attribute__ ((__unused__))) | |||
1141 | { | |||
1142 | enum cpp_ttype token; | |||
1143 | tree x, message = 0; | |||
1144 | ||||
1145 | token = pragma_lex (&x); | |||
1146 | if (token == CPP_OPEN_PAREN) | |||
1147 | { | |||
1148 | token = pragma_lex (&x); | |||
1149 | if (token == CPP_STRING) | |||
1150 | message = x; | |||
1151 | else | |||
1152 | GCC_BAD ("expected a string after %<#pragma message%>")do { warning (OPT_Wpragmas, "expected a string after %<#pragma message%>" ); return; } while (0); | |||
1153 | if (pragma_lex (&x) != CPP_CLOSE_PAREN) | |||
1154 | GCC_BAD ("malformed %<#pragma message%>, ignored")do { warning (OPT_Wpragmas, "malformed %<#pragma message%>, ignored" ); return; } while (0); | |||
1155 | } | |||
1156 | else if (token == CPP_STRING) | |||
1157 | message = x; | |||
1158 | else | |||
1159 | GCC_BAD ("expected a string after %<#pragma message%>")do { warning (OPT_Wpragmas, "expected a string after %<#pragma message%>" ); return; } while (0); | |||
1160 | ||||
1161 | gcc_assert (message)((void)(!(message) ? fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/c-family/c-pragma.c" , 1161, __FUNCTION__), 0 : 0)); | |||
1162 | ||||
1163 | if (pragma_lex (&x) != CPP_EOF) | |||
1164 | warning (OPT_Wpragmas, "junk at end of %<#pragma message%>"); | |||
1165 | ||||
1166 | if (TREE_STRING_LENGTH (message)((tree_check ((message), "/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/c-family/c-pragma.c" , 1166, __FUNCTION__, (STRING_CST)))->string.length) > 1) | |||
1167 | inform (input_location, "%<#pragma message: %s%>", | |||
1168 | TREE_STRING_POINTER (message)((const char *)((tree_check ((message), "/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/c-family/c-pragma.c" , 1168, __FUNCTION__, (STRING_CST)))->string.str))); | |||
1169 | } | |||
1170 | ||||
1171 | /* Mark whether the current location is valid for a STDC pragma. */ | |||
1172 | ||||
1173 | static bool valid_location_for_stdc_pragma; | |||
1174 | ||||
1175 | void | |||
1176 | mark_valid_location_for_stdc_pragma (bool flag) | |||
1177 | { | |||
1178 | valid_location_for_stdc_pragma = flag; | |||
1179 | } | |||
1180 | ||||
1181 | /* Return true if the current location is valid for a STDC pragma. */ | |||
1182 | ||||
1183 | bool | |||
1184 | valid_location_for_stdc_pragma_p (void) | |||
1185 | { | |||
1186 | return valid_location_for_stdc_pragma; | |||
1187 | } | |||
1188 | ||||
1189 | enum pragma_switch_t { PRAGMA_ON, PRAGMA_OFF, PRAGMA_DEFAULT, PRAGMA_BAD }; | |||
1190 | ||||
1191 | /* A STDC pragma must appear outside of external declarations or | |||
1192 | preceding all explicit declarations and statements inside a compound | |||
1193 | statement; its behavior is undefined if used in any other context. | |||
1194 | It takes a switch of ON, OFF, or DEFAULT. */ | |||
1195 | ||||
1196 | static enum pragma_switch_t | |||
1197 | handle_stdc_pragma (const char *pname) | |||
1198 | { | |||
1199 | const char *arg; | |||
1200 | tree t; | |||
1201 | enum pragma_switch_t ret; | |||
1202 | ||||
1203 | if (!valid_location_for_stdc_pragma_p ()) | |||
1204 | { | |||
1205 | warning (OPT_Wpragmas, "invalid location for %<pragma %s%>, ignored", | |||
1206 | pname); | |||
1207 | return PRAGMA_BAD; | |||
1208 | } | |||
1209 | ||||
1210 | if (pragma_lex (&t) != CPP_NAME) | |||
1211 | { | |||
1212 | warning (OPT_Wpragmas, "malformed %<#pragma %s%>, ignored", pname); | |||
1213 | return PRAGMA_BAD; | |||
1214 | } | |||
1215 | ||||
1216 | arg = IDENTIFIER_POINTER (t)((const char *) (tree_check ((t), "/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/c-family/c-pragma.c" , 1216, __FUNCTION__, (IDENTIFIER_NODE)))->identifier.id.str ); | |||
1217 | ||||
1218 | if (!strcmp (arg, "ON")) | |||
1219 | ret = PRAGMA_ON; | |||
1220 | else if (!strcmp (arg, "OFF")) | |||
1221 | ret = PRAGMA_OFF; | |||
1222 | else if (!strcmp (arg, "DEFAULT")) | |||
1223 | ret = PRAGMA_DEFAULT; | |||
1224 | else | |||
1225 | { | |||
1226 | warning (OPT_Wpragmas, "malformed %<#pragma %s%>, ignored", pname); | |||
1227 | return PRAGMA_BAD; | |||
1228 | } | |||
1229 | ||||
1230 | if (pragma_lex (&t) != CPP_EOF) | |||
1231 | { | |||
1232 | warning (OPT_Wpragmas, "junk at end of %<#pragma %s%>", pname); | |||
1233 | return PRAGMA_BAD; | |||
1234 | } | |||
1235 | ||||
1236 | return ret; | |||
1237 | } | |||
1238 | ||||
1239 | /* #pragma STDC FLOAT_CONST_DECIMAL64 ON | |||
1240 | #pragma STDC FLOAT_CONST_DECIMAL64 OFF | |||
1241 | #pragma STDC FLOAT_CONST_DECIMAL64 DEFAULT */ | |||
1242 | ||||
1243 | static void | |||
1244 | handle_pragma_float_const_decimal64 (cpp_reader *ARG_UNUSED (dummy)dummy __attribute__ ((__unused__))) | |||
1245 | { | |||
1246 | if (c_dialect_cxx ()((c_language & clk_cxx) != 0)) | |||
1247 | { | |||
1248 | if (warn_unknown_pragmasglobal_options.x_warn_unknown_pragmas > in_system_header_at (input_location)) | |||
1249 | warning (OPT_Wunknown_pragmas, | |||
1250 | "%<#pragma STDC FLOAT_CONST_DECIMAL64%> is not supported" | |||
1251 | " for C++"); | |||
1252 | return; | |||
1253 | } | |||
1254 | ||||
1255 | if (!targetm.decimal_float_supported_p ()) | |||
1256 | { | |||
1257 | if (warn_unknown_pragmasglobal_options.x_warn_unknown_pragmas > in_system_header_at (input_location)) | |||
1258 | warning (OPT_Wunknown_pragmas, | |||
1259 | "%<#pragma STDC FLOAT_CONST_DECIMAL64%> is not supported" | |||
1260 | " on this target"); | |||
1261 | return; | |||
1262 | } | |||
1263 | ||||
1264 | pedwarn (input_location, OPT_Wpedantic, | |||
1265 | "ISO C does not support %<#pragma STDC FLOAT_CONST_DECIMAL64%>"); | |||
1266 | ||||
1267 | switch (handle_stdc_pragma ("STDC FLOAT_CONST_DECIMAL64")) | |||
1268 | { | |||
1269 | case PRAGMA_ON: | |||
1270 | set_float_const_decimal64 (); | |||
1271 | break; | |||
1272 | case PRAGMA_OFF: | |||
1273 | case PRAGMA_DEFAULT: | |||
1274 | clear_float_const_decimal64 (); | |||
1275 | break; | |||
1276 | case PRAGMA_BAD: | |||
1277 | break; | |||
1278 | } | |||
1279 | } | |||
1280 | ||||
1281 | /* A vector of registered pragma callbacks, which is never freed. */ | |||
1282 | ||||
1283 | static vec<internal_pragma_handler> registered_pragmas; | |||
1284 | ||||
1285 | struct pragma_ns_name | |||
1286 | { | |||
1287 | const char *space; | |||
1288 | const char *name; | |||
1289 | }; | |||
1290 | ||||
1291 | ||||
1292 | static vec<pragma_ns_name> registered_pp_pragmas; | |||
1293 | ||||
1294 | struct omp_pragma_def { const char *name; unsigned int id; }; | |||
1295 | static const struct omp_pragma_def oacc_pragmas[] = { | |||
1296 | { "atomic", PRAGMA_OACC_ATOMIC }, | |||
1297 | { "cache", PRAGMA_OACC_CACHE }, | |||
1298 | { "data", PRAGMA_OACC_DATA }, | |||
1299 | { "declare", PRAGMA_OACC_DECLARE }, | |||
1300 | { "enter", PRAGMA_OACC_ENTER_DATA }, | |||
1301 | { "exit", PRAGMA_OACC_EXIT_DATA }, | |||
1302 | { "host_data", PRAGMA_OACC_HOST_DATA }, | |||
1303 | { "kernels", PRAGMA_OACC_KERNELS }, | |||
1304 | { "loop", PRAGMA_OACC_LOOP }, | |||
1305 | { "parallel", PRAGMA_OACC_PARALLEL }, | |||
1306 | { "routine", PRAGMA_OACC_ROUTINE }, | |||
1307 | { "serial", PRAGMA_OACC_SERIAL }, | |||
1308 | { "update", PRAGMA_OACC_UPDATE }, | |||
1309 | { "wait", PRAGMA_OACC_WAIT } | |||
1310 | }; | |||
1311 | static const struct omp_pragma_def omp_pragmas[] = { | |||
1312 | { "allocate", PRAGMA_OMP_ALLOCATE }, | |||
1313 | { "atomic", PRAGMA_OMP_ATOMIC }, | |||
1314 | { "barrier", PRAGMA_OMP_BARRIER }, | |||
1315 | { "cancel", PRAGMA_OMP_CANCEL }, | |||
1316 | { "cancellation", PRAGMA_OMP_CANCELLATION_POINT }, | |||
1317 | { "critical", PRAGMA_OMP_CRITICAL }, | |||
1318 | { "depobj", PRAGMA_OMP_DEPOBJ }, | |||
1319 | { "end", PRAGMA_OMP_END_DECLARE_TARGET }, | |||
1320 | { "flush", PRAGMA_OMP_FLUSH }, | |||
1321 | { "requires", PRAGMA_OMP_REQUIRES }, | |||
1322 | { "section", PRAGMA_OMP_SECTION }, | |||
1323 | { "sections", PRAGMA_OMP_SECTIONS }, | |||
1324 | { "single", PRAGMA_OMP_SINGLE }, | |||
1325 | { "task", PRAGMA_OMP_TASK }, | |||
1326 | { "taskgroup", PRAGMA_OMP_TASKGROUP }, | |||
1327 | { "taskwait", PRAGMA_OMP_TASKWAIT }, | |||
1328 | { "taskyield", PRAGMA_OMP_TASKYIELD }, | |||
1329 | { "threadprivate", PRAGMA_OMP_THREADPRIVATE } | |||
1330 | }; | |||
1331 | static const struct omp_pragma_def omp_pragmas_simd[] = { | |||
1332 | { "declare", PRAGMA_OMP_DECLARE }, | |||
1333 | { "distribute", PRAGMA_OMP_DISTRIBUTE }, | |||
1334 | { "for", PRAGMA_OMP_FOR }, | |||
1335 | { "loop", PRAGMA_OMP_LOOP }, | |||
1336 | { "master", PRAGMA_OMP_MASTER }, | |||
1337 | { "ordered", PRAGMA_OMP_ORDERED }, | |||
1338 | { "parallel", PRAGMA_OMP_PARALLEL }, | |||
1339 | { "scan", PRAGMA_OMP_SCAN }, | |||
1340 | { "simd", PRAGMA_OMP_SIMD }, | |||
1341 | { "target", PRAGMA_OMP_TARGET }, | |||
1342 | { "taskloop", PRAGMA_OMP_TASKLOOP }, | |||
1343 | { "teams", PRAGMA_OMP_TEAMS }, | |||
1344 | }; | |||
1345 | ||||
1346 | void | |||
1347 | c_pp_lookup_pragma (unsigned int id, const char **space, const char **name) | |||
1348 | { | |||
1349 | const int n_oacc_pragmas = sizeof (oacc_pragmas) / sizeof (*oacc_pragmas); | |||
1350 | const int n_omp_pragmas = sizeof (omp_pragmas) / sizeof (*omp_pragmas); | |||
1351 | const int n_omp_pragmas_simd = sizeof (omp_pragmas_simd) | |||
1352 | / sizeof (*omp_pragmas); | |||
1353 | int i; | |||
1354 | ||||
1355 | for (i = 0; i < n_oacc_pragmas; ++i) | |||
1356 | if (oacc_pragmas[i].id == id) | |||
1357 | { | |||
1358 | *space = "acc"; | |||
1359 | *name = oacc_pragmas[i].name; | |||
1360 | return; | |||
1361 | } | |||
1362 | ||||
1363 | for (i = 0; i < n_omp_pragmas; ++i) | |||
1364 | if (omp_pragmas[i].id == id) | |||
1365 | { | |||
1366 | *space = "omp"; | |||
1367 | *name = omp_pragmas[i].name; | |||
1368 | return; | |||
1369 | } | |||
1370 | ||||
1371 | for (i = 0; i < n_omp_pragmas_simd; ++i) | |||
1372 | if (omp_pragmas_simd[i].id == id) | |||
1373 | { | |||
1374 | *space = "omp"; | |||
1375 | *name = omp_pragmas_simd[i].name; | |||
1376 | return; | |||
1377 | } | |||
1378 | ||||
1379 | if (id >= PRAGMA_FIRST_EXTERNAL | |||
1380 | && (id < PRAGMA_FIRST_EXTERNAL + registered_pp_pragmas.length ())) | |||
1381 | { | |||
1382 | *space = registered_pp_pragmas[id - PRAGMA_FIRST_EXTERNAL].space; | |||
1383 | *name = registered_pp_pragmas[id - PRAGMA_FIRST_EXTERNAL].name; | |||
1384 | return; | |||
1385 | } | |||
1386 | ||||
1387 | gcc_unreachable ()(fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/c-family/c-pragma.c" , 1387, __FUNCTION__)); | |||
1388 | } | |||
1389 | ||||
1390 | /* Front-end wrappers for pragma registration to avoid dragging | |||
1391 | cpplib.h in almost everywhere. */ | |||
1392 | ||||
1393 | static void | |||
1394 | c_register_pragma_1 (const char *space, const char *name, | |||
1395 | internal_pragma_handler ihandler, bool allow_expansion) | |||
1396 | { | |||
1397 | unsigned id; | |||
1398 | ||||
1399 | if (flag_preprocess_onlyglobal_options.x_flag_preprocess_only) | |||
1400 | { | |||
1401 | pragma_ns_name ns_name; | |||
1402 | ||||
1403 | if (!allow_expansion) | |||
1404 | return; | |||
1405 | ||||
1406 | ns_name.space = space; | |||
1407 | ns_name.name = name; | |||
1408 | registered_pp_pragmas.safe_push (ns_name); | |||
1409 | id = registered_pp_pragmas.length (); | |||
1410 | id += PRAGMA_FIRST_EXTERNAL - 1; | |||
1411 | } | |||
1412 | else | |||
1413 | { | |||
1414 | registered_pragmas.safe_push (ihandler); | |||
1415 | id = registered_pragmas.length (); | |||
1416 | id += PRAGMA_FIRST_EXTERNAL - 1; | |||
1417 | ||||
1418 | /* The C front end allocates 8 bits in c_token. The C++ front end | |||
1419 | keeps the pragma kind in the form of INTEGER_CST, so no small | |||
1420 | limit applies. At present this is sufficient. */ | |||
1421 | gcc_assert (id < 256)((void)(!(id < 256) ? fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/c-family/c-pragma.c" , 1421, __FUNCTION__), 0 : 0)); | |||
1422 | } | |||
1423 | ||||
1424 | cpp_register_deferred_pragma (parse_in, space, name, id, | |||
1425 | allow_expansion, false); | |||
1426 | } | |||
1427 | ||||
1428 | /* Register a C pragma handler, using a space and a name. It disallows pragma | |||
1429 | expansion (if you want it, use c_register_pragma_with_expansion instead). */ | |||
1430 | void | |||
1431 | c_register_pragma (const char *space, const char *name, | |||
1432 | pragma_handler_1arg handler) | |||
1433 | { | |||
1434 | internal_pragma_handler ihandler; | |||
1435 | ||||
1436 | ihandler.handler.handler_1arg = handler; | |||
1437 | ihandler.extra_data = false; | |||
1438 | ihandler.data = NULLnullptr; | |||
1439 | c_register_pragma_1 (space, name, ihandler, false); | |||
1440 | } | |||
1441 | ||||
1442 | /* Register a C pragma handler, using a space and a name, it also carries an | |||
1443 | extra data field which can be used by the handler. It disallows pragma | |||
1444 | expansion (if you want it, use c_register_pragma_with_expansion_and_data | |||
1445 | instead). */ | |||
1446 | void | |||
1447 | c_register_pragma_with_data (const char *space, const char *name, | |||
1448 | pragma_handler_2arg handler, void * data) | |||
1449 | { | |||
1450 | internal_pragma_handler ihandler; | |||
1451 | ||||
1452 | ihandler.handler.handler_2arg = handler; | |||
1453 | ihandler.extra_data = true; | |||
1454 | ihandler.data = data; | |||
1455 | c_register_pragma_1 (space, name, ihandler, false); | |||
1456 | } | |||
1457 | ||||
1458 | /* Register a C pragma handler, using a space and a name. It allows pragma | |||
1459 | expansion as in the following example: | |||
1460 | ||||
1461 | #define NUMBER 10 | |||
1462 | #pragma count (NUMBER) | |||
1463 | ||||
1464 | Name expansion is still disallowed. */ | |||
1465 | void | |||
1466 | c_register_pragma_with_expansion (const char *space, const char *name, | |||
1467 | pragma_handler_1arg handler) | |||
1468 | { | |||
1469 | internal_pragma_handler ihandler; | |||
1470 | ||||
1471 | ihandler.handler.handler_1arg = handler; | |||
1472 | ihandler.extra_data = false; | |||
1473 | ihandler.data = NULLnullptr; | |||
1474 | c_register_pragma_1 (space, name, ihandler, true); | |||
1475 | } | |||
1476 | ||||
1477 | /* Register a C pragma handler, using a space and a name, it also carries an | |||
1478 | extra data field which can be used by the handler. It allows pragma | |||
1479 | expansion as in the following example: | |||
1480 | ||||
1481 | #define NUMBER 10 | |||
1482 | #pragma count (NUMBER) | |||
1483 | ||||
1484 | Name expansion is still disallowed. */ | |||
1485 | void | |||
1486 | c_register_pragma_with_expansion_and_data (const char *space, const char *name, | |||
1487 | pragma_handler_2arg handler, | |||
1488 | void *data) | |||
1489 | { | |||
1490 | internal_pragma_handler ihandler; | |||
1491 | ||||
1492 | ihandler.handler.handler_2arg = handler; | |||
1493 | ihandler.extra_data = true; | |||
1494 | ihandler.data = data; | |||
1495 | c_register_pragma_1 (space, name, ihandler, true); | |||
1496 | } | |||
1497 | ||||
1498 | void | |||
1499 | c_invoke_pragma_handler (unsigned int id) | |||
1500 | { | |||
1501 | internal_pragma_handler *ihandler; | |||
1502 | pragma_handler_1arg handler_1arg; | |||
1503 | pragma_handler_2arg handler_2arg; | |||
1504 | ||||
1505 | id -= PRAGMA_FIRST_EXTERNAL; | |||
1506 | ihandler = ®istered_pragmas[id]; | |||
1507 | if (ihandler->extra_data) | |||
1508 | { | |||
1509 | handler_2arg = ihandler->handler.handler_2arg; | |||
1510 | handler_2arg (parse_in, ihandler->data); | |||
1511 | } | |||
1512 | else | |||
1513 | { | |||
1514 | handler_1arg = ihandler->handler.handler_1arg; | |||
1515 | handler_1arg (parse_in); | |||
1516 | } | |||
1517 | } | |||
1518 | ||||
1519 | /* Set up front-end pragmas. */ | |||
1520 | void | |||
1521 | init_pragma (void) | |||
1522 | { | |||
1523 | if (flag_openaccglobal_options.x_flag_openacc) | |||
1524 | { | |||
1525 | const int n_oacc_pragmas | |||
1526 | = sizeof (oacc_pragmas) / sizeof (*oacc_pragmas); | |||
1527 | int i; | |||
1528 | ||||
1529 | for (i = 0; i < n_oacc_pragmas; ++i) | |||
1530 | cpp_register_deferred_pragma (parse_in, "acc", oacc_pragmas[i].name, | |||
1531 | oacc_pragmas[i].id, true, true); | |||
1532 | } | |||
1533 | ||||
1534 | if (flag_openmpglobal_options.x_flag_openmp) | |||
1535 | { | |||
1536 | const int n_omp_pragmas = sizeof (omp_pragmas) / sizeof (*omp_pragmas); | |||
1537 | int i; | |||
1538 | ||||
1539 | for (i = 0; i < n_omp_pragmas; ++i) | |||
1540 | cpp_register_deferred_pragma (parse_in, "omp", omp_pragmas[i].name, | |||
1541 | omp_pragmas[i].id, true, true); | |||
1542 | } | |||
1543 | if (flag_openmpglobal_options.x_flag_openmp || flag_openmp_simdglobal_options.x_flag_openmp_simd) | |||
1544 | { | |||
1545 | const int n_omp_pragmas_simd = sizeof (omp_pragmas_simd) | |||
1546 | / sizeof (*omp_pragmas); | |||
1547 | int i; | |||
1548 | ||||
1549 | for (i = 0; i < n_omp_pragmas_simd; ++i) | |||
1550 | cpp_register_deferred_pragma (parse_in, "omp", omp_pragmas_simd[i].name, | |||
1551 | omp_pragmas_simd[i].id, true, true); | |||
1552 | } | |||
1553 | ||||
1554 | if (!flag_preprocess_onlyglobal_options.x_flag_preprocess_only) | |||
1555 | cpp_register_deferred_pragma (parse_in, "GCC", "pch_preprocess", | |||
1556 | PRAGMA_GCC_PCH_PREPROCESS, false, false); | |||
1557 | ||||
1558 | if (!flag_preprocess_onlyglobal_options.x_flag_preprocess_only) | |||
1559 | cpp_register_deferred_pragma (parse_in, "GCC", "ivdep", PRAGMA_IVDEP, false, | |||
1560 | false); | |||
1561 | ||||
1562 | if (!flag_preprocess_onlyglobal_options.x_flag_preprocess_only) | |||
1563 | cpp_register_deferred_pragma (parse_in, "GCC", "unroll", PRAGMA_UNROLL, | |||
1564 | false, false); | |||
1565 | ||||
1566 | #ifdef HANDLE_PRAGMA_PACK_WITH_EXPANSION | |||
1567 | c_register_pragma_with_expansion (0, "pack", handle_pragma_pack); | |||
1568 | #else | |||
1569 | c_register_pragma (0, "pack", handle_pragma_pack); | |||
1570 | #endif | |||
1571 | c_register_pragma (0, "weak", handle_pragma_weak); | |||
1572 | ||||
1573 | c_register_pragma ("GCC", "visibility", handle_pragma_visibility); | |||
1574 | ||||
1575 | c_register_pragma ("GCC", "diagnostic", handle_pragma_diagnostic); | |||
1576 | c_register_pragma ("GCC", "target", handle_pragma_target); | |||
1577 | c_register_pragma ("GCC", "optimize", handle_pragma_optimize); | |||
1578 | c_register_pragma ("GCC", "push_options", handle_pragma_push_options); | |||
1579 | c_register_pragma ("GCC", "pop_options", handle_pragma_pop_options); | |||
1580 | c_register_pragma ("GCC", "reset_options", handle_pragma_reset_options); | |||
1581 | ||||
1582 | c_register_pragma ("STDC", "FLOAT_CONST_DECIMAL64", | |||
1583 | handle_pragma_float_const_decimal64); | |||
1584 | ||||
1585 | c_register_pragma_with_expansion (0, "redefine_extname", | |||
1586 | handle_pragma_redefine_extname); | |||
1587 | ||||
1588 | c_register_pragma_with_expansion (0, "message", handle_pragma_message); | |||
1589 | ||||
1590 | #ifdef REGISTER_TARGET_PRAGMAS | |||
1591 | REGISTER_TARGET_PRAGMAS ()ix86_register_pragmas (); | |||
1592 | #endif | |||
1593 | ||||
1594 | global_sso = default_ssoglobal_options.x_default_sso; | |||
1595 | c_register_pragma (0, "scalar_storage_order", | |||
1596 | handle_pragma_scalar_storage_order); | |||
1597 | ||||
1598 | /* Allow plugins to register their own pragmas. */ | |||
1599 | invoke_plugin_callbacks (PLUGIN_PRAGMAS, NULLnullptr); | |||
1600 | } | |||
1601 | ||||
1602 | #include "gt-c-family-c-pragma.h" |
1 | /* Vector API for GNU compiler. | ||||
2 | Copyright (C) 2004-2021 Free Software Foundation, Inc. | ||||
3 | Contributed by Nathan Sidwell <nathan@codesourcery.com> | ||||
4 | Re-implemented in C++ by Diego Novillo <dnovillo@google.com> | ||||
5 | |||||
6 | This file is part of GCC. | ||||
7 | |||||
8 | GCC is free software; you can redistribute it and/or modify it under | ||||
9 | the terms of the GNU General Public License as published by the Free | ||||
10 | Software Foundation; either version 3, or (at your option) any later | ||||
11 | version. | ||||
12 | |||||
13 | GCC is distributed in the hope that it will be useful, but WITHOUT ANY | ||||
14 | WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||||
15 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||||
16 | for more details. | ||||
17 | |||||
18 | You should have received a copy of the GNU General Public License | ||||
19 | along with GCC; see the file COPYING3. If not see | ||||
20 | <http://www.gnu.org/licenses/>. */ | ||||
21 | |||||
22 | #ifndef GCC_VEC_H | ||||
23 | #define GCC_VEC_H | ||||
24 | |||||
25 | /* Some gen* file have no ggc support as the header file gtype-desc.h is | ||||
26 | missing. Provide these definitions in case ggc.h has not been included. | ||||
27 | This is not a problem because any code that runs before gengtype is built | ||||
28 | will never need to use GC vectors.*/ | ||||
29 | |||||
30 | extern void ggc_free (void *); | ||||
31 | extern size_t ggc_round_alloc_size (size_t requested_size); | ||||
32 | extern void *ggc_realloc (void *, size_t MEM_STAT_DECL); | ||||
33 | |||||
34 | /* Templated vector type and associated interfaces. | ||||
35 | |||||
36 | The interface functions are typesafe and use inline functions, | ||||
37 | sometimes backed by out-of-line generic functions. The vectors are | ||||
38 | designed to interoperate with the GTY machinery. | ||||
39 | |||||
40 | There are both 'index' and 'iterate' accessors. The index accessor | ||||
41 | is implemented by operator[]. The iterator returns a boolean | ||||
42 | iteration condition and updates the iteration variable passed by | ||||
43 | reference. Because the iterator will be inlined, the address-of | ||||
44 | can be optimized away. | ||||
45 | |||||
46 | Each operation that increases the number of active elements is | ||||
47 | available in 'quick' and 'safe' variants. The former presumes that | ||||
48 | there is sufficient allocated space for the operation to succeed | ||||
49 | (it dies if there is not). The latter will reallocate the | ||||
50 | vector, if needed. Reallocation causes an exponential increase in | ||||
51 | vector size. If you know you will be adding N elements, it would | ||||
52 | be more efficient to use the reserve operation before adding the | ||||
53 | elements with the 'quick' operation. This will ensure there are at | ||||
54 | least as many elements as you ask for, it will exponentially | ||||
55 | increase if there are too few spare slots. If you want reserve a | ||||
56 | specific number of slots, but do not want the exponential increase | ||||
57 | (for instance, you know this is the last allocation), use the | ||||
58 | reserve_exact operation. You can also create a vector of a | ||||
59 | specific size from the get go. | ||||
60 | |||||
61 | You should prefer the push and pop operations, as they append and | ||||
62 | remove from the end of the vector. If you need to remove several | ||||
63 | items in one go, use the truncate operation. The insert and remove | ||||
64 | operations allow you to change elements in the middle of the | ||||
65 | vector. There are two remove operations, one which preserves the | ||||
66 | element ordering 'ordered_remove', and one which does not | ||||
67 | 'unordered_remove'. The latter function copies the end element | ||||
68 | into the removed slot, rather than invoke a memmove operation. The | ||||
69 | 'lower_bound' function will determine where to place an item in the | ||||
70 | array using insert that will maintain sorted order. | ||||
71 | |||||
72 | Vectors are template types with three arguments: the type of the | ||||
73 | elements in the vector, the allocation strategy, and the physical | ||||
74 | layout to use | ||||
75 | |||||
76 | Four allocation strategies are supported: | ||||
77 | |||||
78 | - Heap: allocation is done using malloc/free. This is the | ||||
79 | default allocation strategy. | ||||
80 | |||||
81 | - GC: allocation is done using ggc_alloc/ggc_free. | ||||
82 | |||||
83 | - GC atomic: same as GC with the exception that the elements | ||||
84 | themselves are assumed to be of an atomic type that does | ||||
85 | not need to be garbage collected. This means that marking | ||||
86 | routines do not need to traverse the array marking the | ||||
87 | individual elements. This increases the performance of | ||||
88 | GC activities. | ||||
89 | |||||
90 | Two physical layouts are supported: | ||||
91 | |||||
92 | - Embedded: The vector is structured using the trailing array | ||||
93 | idiom. The last member of the structure is an array of size | ||||
94 | 1. When the vector is initially allocated, a single memory | ||||
95 | block is created to hold the vector's control data and the | ||||
96 | array of elements. These vectors cannot grow without | ||||
97 | reallocation (see discussion on embeddable vectors below). | ||||
98 | |||||
99 | - Space efficient: The vector is structured as a pointer to an | ||||
100 | embedded vector. This is the default layout. It means that | ||||
101 | vectors occupy a single word of storage before initial | ||||
102 | allocation. Vectors are allowed to grow (the internal | ||||
103 | pointer is reallocated but the main vector instance does not | ||||
104 | need to relocate). | ||||
105 | |||||
106 | The type, allocation and layout are specified when the vector is | ||||
107 | declared. | ||||
108 | |||||
109 | If you need to directly manipulate a vector, then the 'address' | ||||
110 | accessor will return the address of the start of the vector. Also | ||||
111 | the 'space' predicate will tell you whether there is spare capacity | ||||
112 | in the vector. You will not normally need to use these two functions. | ||||
113 | |||||
114 | Notes on the different layout strategies | ||||
115 | |||||
116 | * Embeddable vectors (vec<T, A, vl_embed>) | ||||
117 | |||||
118 | These vectors are suitable to be embedded in other data | ||||
119 | structures so that they can be pre-allocated in a contiguous | ||||
120 | memory block. | ||||
121 | |||||
122 | Embeddable vectors are implemented using the trailing array | ||||
123 | idiom, thus they are not resizeable without changing the address | ||||
124 | of the vector object itself. This means you cannot have | ||||
125 | variables or fields of embeddable vector type -- always use a | ||||
126 | pointer to a vector. The one exception is the final field of a | ||||
127 | structure, which could be a vector type. | ||||
128 | |||||
129 | You will have to use the embedded_size & embedded_init calls to | ||||
130 | create such objects, and they will not be resizeable (so the | ||||
131 | 'safe' allocation variants are not available). | ||||
132 | |||||
133 | Properties of embeddable vectors: | ||||
134 | |||||
135 | - The whole vector and control data are allocated in a single | ||||
136 | contiguous block. It uses the trailing-vector idiom, so | ||||
137 | allocation must reserve enough space for all the elements | ||||
138 | in the vector plus its control data. | ||||
139 | - The vector cannot be re-allocated. | ||||
140 | - The vector cannot grow nor shrink. | ||||
141 | - No indirections needed for access/manipulation. | ||||
142 | - It requires 2 words of storage (prior to vector allocation). | ||||
143 | |||||
144 | |||||
145 | * Space efficient vector (vec<T, A, vl_ptr>) | ||||
146 | |||||
147 | These vectors can grow dynamically and are allocated together | ||||
148 | with their control data. They are suited to be included in data | ||||
149 | structures. Prior to initial allocation, they only take a single | ||||
150 | word of storage. | ||||
151 | |||||
152 | These vectors are implemented as a pointer to embeddable vectors. | ||||
153 | The semantics allow for this pointer to be NULL to represent | ||||
154 | empty vectors. This way, empty vectors occupy minimal space in | ||||
155 | the structure containing them. | ||||
156 | |||||
157 | Properties: | ||||
158 | |||||
159 | - The whole vector and control data are allocated in a single | ||||
160 | contiguous block. | ||||
161 | - The whole vector may be re-allocated. | ||||
162 | - Vector data may grow and shrink. | ||||
163 | - Access and manipulation requires a pointer test and | ||||
164 | indirection. | ||||
165 | - It requires 1 word of storage (prior to vector allocation). | ||||
166 | |||||
167 | An example of their use would be, | ||||
168 | |||||
169 | struct my_struct { | ||||
170 | // A space-efficient vector of tree pointers in GC memory. | ||||
171 | vec<tree, va_gc, vl_ptr> v; | ||||
172 | }; | ||||
173 | |||||
174 | struct my_struct *s; | ||||
175 | |||||
176 | if (s->v.length ()) { we have some contents } | ||||
177 | s->v.safe_push (decl); // append some decl onto the end | ||||
178 | for (ix = 0; s->v.iterate (ix, &elt); ix++) | ||||
179 | { do something with elt } | ||||
180 | */ | ||||
181 | |||||
182 | /* Support function for statistics. */ | ||||
183 | extern void dump_vec_loc_statistics (void); | ||||
184 | |||||
185 | /* Hashtable mapping vec addresses to descriptors. */ | ||||
186 | extern htab_t vec_mem_usage_hash; | ||||
187 | |||||
188 | /* Control data for vectors. This contains the number of allocated | ||||
189 | and used slots inside a vector. */ | ||||
190 | |||||
191 | struct vec_prefix | ||||
192 | { | ||||
193 | /* FIXME - These fields should be private, but we need to cater to | ||||
194 | compilers that have stricter notions of PODness for types. */ | ||||
195 | |||||
196 | /* Memory allocation support routines in vec.c. */ | ||||
197 | void register_overhead (void *, size_t, size_t CXX_MEM_STAT_INFO); | ||||
198 | void release_overhead (void *, size_t, size_t, bool CXX_MEM_STAT_INFO); | ||||
199 | static unsigned calculate_allocation (vec_prefix *, unsigned, bool); | ||||
200 | static unsigned calculate_allocation_1 (unsigned, unsigned); | ||||
201 | |||||
202 | /* Note that vec_prefix should be a base class for vec, but we use | ||||
203 | offsetof() on vector fields of tree structures (e.g., | ||||
204 | tree_binfo::base_binfos), and offsetof only supports base types. | ||||
205 | |||||
206 | To compensate, we make vec_prefix a field inside vec and make | ||||
207 | vec a friend class of vec_prefix so it can access its fields. */ | ||||
208 | template <typename, typename, typename> friend struct vec; | ||||
209 | |||||
210 | /* The allocator types also need access to our internals. */ | ||||
211 | friend struct va_gc; | ||||
212 | friend struct va_gc_atomic; | ||||
213 | friend struct va_heap; | ||||
214 | |||||
215 | unsigned m_alloc : 31; | ||||
216 | unsigned m_using_auto_storage : 1; | ||||
217 | unsigned m_num; | ||||
218 | }; | ||||
219 | |||||
220 | /* Calculate the number of slots to reserve a vector, making sure that | ||||
221 | RESERVE slots are free. If EXACT grow exactly, otherwise grow | ||||
222 | exponentially. PFX is the control data for the vector. */ | ||||
223 | |||||
224 | inline unsigned | ||||
225 | vec_prefix::calculate_allocation (vec_prefix *pfx, unsigned reserve, | ||||
226 | bool exact) | ||||
227 | { | ||||
228 | if (exact) | ||||
229 | return (pfx ? pfx->m_num : 0) + reserve; | ||||
230 | else if (!pfx) | ||||
231 | return MAX (4, reserve)((4) > (reserve) ? (4) : (reserve)); | ||||
232 | return calculate_allocation_1 (pfx->m_alloc, pfx->m_num + reserve); | ||||
233 | } | ||||
234 | |||||
235 | template<typename, typename, typename> struct vec; | ||||
236 | |||||
237 | /* Valid vector layouts | ||||
238 | |||||
239 | vl_embed - Embeddable vector that uses the trailing array idiom. | ||||
240 | vl_ptr - Space efficient vector that uses a pointer to an | ||||
241 | embeddable vector. */ | ||||
242 | struct vl_embed { }; | ||||
243 | struct vl_ptr { }; | ||||
244 | |||||
245 | |||||
246 | /* Types of supported allocations | ||||
247 | |||||
248 | va_heap - Allocation uses malloc/free. | ||||
249 | va_gc - Allocation uses ggc_alloc. | ||||
250 | va_gc_atomic - Same as GC, but individual elements of the array | ||||
251 | do not need to be marked during collection. */ | ||||
252 | |||||
253 | /* Allocator type for heap vectors. */ | ||||
254 | struct va_heap | ||||
255 | { | ||||
256 | /* Heap vectors are frequently regular instances, so use the vl_ptr | ||||
257 | layout for them. */ | ||||
258 | typedef vl_ptr default_layout; | ||||
259 | |||||
260 | template<typename T> | ||||
261 | static void reserve (vec<T, va_heap, vl_embed> *&, unsigned, bool | ||||
262 | CXX_MEM_STAT_INFO); | ||||
263 | |||||
264 | template<typename T> | ||||
265 | static void release (vec<T, va_heap, vl_embed> *&); | ||||
266 | }; | ||||
267 | |||||
268 | |||||
269 | /* Allocator for heap memory. Ensure there are at least RESERVE free | ||||
270 | slots in V. If EXACT is true, grow exactly, else grow | ||||
271 | exponentially. As a special case, if the vector had not been | ||||
272 | allocated and RESERVE is 0, no vector will be created. */ | ||||
273 | |||||
274 | template<typename T> | ||||
275 | inline void | ||||
276 | va_heap::reserve (vec<T, va_heap, vl_embed> *&v, unsigned reserve, bool exact | ||||
277 | MEM_STAT_DECL) | ||||
278 | { | ||||
279 | size_t elt_size = sizeof (T); | ||||
280 | unsigned alloc | ||||
281 | = vec_prefix::calculate_allocation (v ? &v->m_vecpfx : 0, reserve, exact); | ||||
282 | gcc_checking_assert (alloc)((void)(!(alloc) ? fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/vec.h" , 282, __FUNCTION__), 0 : 0)); | ||||
283 | |||||
284 | if (GATHER_STATISTICS0 && v) | ||||
285 | v->m_vecpfx.release_overhead (v, elt_size * v->allocated (), | ||||
286 | v->allocated (), false); | ||||
287 | |||||
288 | size_t size = vec<T, va_heap, vl_embed>::embedded_size (alloc); | ||||
289 | unsigned nelem = v ? v->length () : 0; | ||||
290 | v = static_cast <vec<T, va_heap, vl_embed> *> (xrealloc (v, size)); | ||||
291 | v->embedded_init (alloc, nelem); | ||||
292 | |||||
293 | if (GATHER_STATISTICS0) | ||||
294 | v->m_vecpfx.register_overhead (v, alloc, elt_size PASS_MEM_STAT); | ||||
295 | } | ||||
296 | |||||
297 | |||||
298 | #if GCC_VERSION(4 * 1000 + 2) >= 4007 | ||||
299 | #pragma GCC diagnostic push | ||||
300 | #pragma GCC diagnostic ignored "-Wfree-nonheap-object" | ||||
301 | #endif | ||||
302 | |||||
303 | /* Free the heap space allocated for vector V. */ | ||||
304 | |||||
305 | template<typename T> | ||||
306 | void | ||||
307 | va_heap::release (vec<T, va_heap, vl_embed> *&v) | ||||
308 | { | ||||
309 | size_t elt_size = sizeof (T); | ||||
310 | if (v == NULLnullptr) | ||||
311 | return; | ||||
312 | |||||
313 | if (GATHER_STATISTICS0) | ||||
314 | v->m_vecpfx.release_overhead (v, elt_size * v->allocated (), | ||||
315 | v->allocated (), true); | ||||
316 | ::free (v); | ||||
317 | v = NULLnullptr; | ||||
318 | } | ||||
319 | |||||
320 | #if GCC_VERSION(4 * 1000 + 2) >= 4007 | ||||
321 | #pragma GCC diagnostic pop | ||||
322 | #endif | ||||
323 | |||||
324 | /* Allocator type for GC vectors. Notice that we need the structure | ||||
325 | declaration even if GC is not enabled. */ | ||||
326 | |||||
327 | struct va_gc | ||||
328 | { | ||||
329 | /* Use vl_embed as the default layout for GC vectors. Due to GTY | ||||
330 | limitations, GC vectors must always be pointers, so it is more | ||||
331 | efficient to use a pointer to the vl_embed layout, rather than | ||||
332 | using a pointer to a pointer as would be the case with vl_ptr. */ | ||||
333 | typedef vl_embed default_layout; | ||||
334 | |||||
335 | template<typename T, typename A> | ||||
336 | static void reserve (vec<T, A, vl_embed> *&, unsigned, bool | ||||
337 | CXX_MEM_STAT_INFO); | ||||
338 | |||||
339 | template<typename T, typename A> | ||||
340 | static void release (vec<T, A, vl_embed> *&v); | ||||
341 | }; | ||||
342 | |||||
343 | |||||
344 | /* Free GC memory used by V and reset V to NULL. */ | ||||
345 | |||||
346 | template<typename T, typename A> | ||||
347 | inline void | ||||
348 | va_gc::release (vec<T, A, vl_embed> *&v) | ||||
349 | { | ||||
350 | if (v) | ||||
351 | ::ggc_free (v); | ||||
352 | v = NULLnullptr; | ||||
353 | } | ||||
354 | |||||
355 | |||||
356 | /* Allocator for GC memory. Ensure there are at least RESERVE free | ||||
357 | slots in V. If EXACT is true, grow exactly, else grow | ||||
358 | exponentially. As a special case, if the vector had not been | ||||
359 | allocated and RESERVE is 0, no vector will be created. */ | ||||
360 | |||||
361 | template<typename T, typename A> | ||||
362 | void | ||||
363 | va_gc::reserve (vec<T, A, vl_embed> *&v, unsigned reserve, bool exact | ||||
364 | MEM_STAT_DECL) | ||||
365 | { | ||||
366 | unsigned alloc | ||||
367 | = vec_prefix::calculate_allocation (v ? &v->m_vecpfx : 0, reserve, exact); | ||||
368 | if (!alloc) | ||||
369 | { | ||||
370 | ::ggc_free (v); | ||||
371 | v = NULLnullptr; | ||||
372 | return; | ||||
373 | } | ||||
374 | |||||
375 | /* Calculate the amount of space we want. */ | ||||
376 | size_t size = vec<T, A, vl_embed>::embedded_size (alloc); | ||||
377 | |||||
378 | /* Ask the allocator how much space it will really give us. */ | ||||
379 | size = ::ggc_round_alloc_size (size); | ||||
380 | |||||
381 | /* Adjust the number of slots accordingly. */ | ||||
382 | size_t vec_offset = sizeof (vec_prefix); | ||||
383 | size_t elt_size = sizeof (T); | ||||
384 | alloc = (size - vec_offset) / elt_size; | ||||
385 | |||||
386 | /* And finally, recalculate the amount of space we ask for. */ | ||||
387 | size = vec_offset + alloc * elt_size; | ||||
388 | |||||
389 | unsigned nelem = v ? v->length () : 0; | ||||
390 | v = static_cast <vec<T, A, vl_embed> *> (::ggc_realloc (v, size | ||||
391 | PASS_MEM_STAT)); | ||||
392 | v->embedded_init (alloc, nelem); | ||||
393 | } | ||||
394 | |||||
395 | |||||
396 | /* Allocator type for GC vectors. This is for vectors of types | ||||
397 | atomics w.r.t. collection, so allocation and deallocation is | ||||
398 | completely inherited from va_gc. */ | ||||
399 | struct va_gc_atomic : va_gc | ||||
400 | { | ||||
401 | }; | ||||
402 | |||||
403 | |||||
404 | /* Generic vector template. Default values for A and L indicate the | ||||
405 | most commonly used strategies. | ||||
406 | |||||
407 | FIXME - Ideally, they would all be vl_ptr to encourage using regular | ||||
408 | instances for vectors, but the existing GTY machinery is limited | ||||
409 | in that it can only deal with GC objects that are pointers | ||||
410 | themselves. | ||||
411 | |||||
412 | This means that vector operations that need to deal with | ||||
413 | potentially NULL pointers, must be provided as free | ||||
414 | functions (see the vec_safe_* functions above). */ | ||||
415 | template<typename T, | ||||
416 | typename A = va_heap, | ||||
417 | typename L = typename A::default_layout> | ||||
418 | struct GTY((user)) vec | ||||
419 | { | ||||
420 | }; | ||||
421 | |||||
422 | /* Allow C++11 range-based 'for' to work directly on vec<T>*. */ | ||||
423 | template<typename T, typename A, typename L> | ||||
424 | T* begin (vec<T,A,L> *v) { return v ? v->begin () : nullptr; } | ||||
425 | template<typename T, typename A, typename L> | ||||
426 | T* end (vec<T,A,L> *v) { return v ? v->end () : nullptr; } | ||||
427 | template<typename T, typename A, typename L> | ||||
428 | const T* begin (const vec<T,A,L> *v) { return v ? v->begin () : nullptr; } | ||||
429 | template<typename T, typename A, typename L> | ||||
430 | const T* end (const vec<T,A,L> *v) { return v ? v->end () : nullptr; } | ||||
431 | |||||
432 | /* Generic vec<> debug helpers. | ||||
433 | |||||
434 | These need to be instantiated for each vec<TYPE> used throughout | ||||
435 | the compiler like this: | ||||
436 | |||||
437 | DEFINE_DEBUG_VEC (TYPE) | ||||
438 | |||||
439 | The reason we have a debug_helper() is because GDB can't | ||||
440 | disambiguate a plain call to debug(some_vec), and it must be called | ||||
441 | like debug<TYPE>(some_vec). */ | ||||
442 | |||||
443 | template<typename T> | ||||
444 | void | ||||
445 | debug_helper (vec<T> &ref) | ||||
446 | { | ||||
447 | unsigned i; | ||||
448 | for (i = 0; i < ref.length (); ++i) | ||||
449 | { | ||||
450 | fprintf (stderrstderr, "[%d] = ", i); | ||||
451 | debug_slim (ref[i]); | ||||
452 | fputc ('\n', stderrstderr); | ||||
453 | } | ||||
454 | } | ||||
455 | |||||
456 | /* We need a separate va_gc variant here because default template | ||||
457 | argument for functions cannot be used in c++-98. Once this | ||||
458 | restriction is removed, those variant should be folded with the | ||||
459 | above debug_helper. */ | ||||
460 | |||||
461 | template<typename T> | ||||
462 | void | ||||
463 | debug_helper (vec<T, va_gc> &ref) | ||||
464 | { | ||||
465 | unsigned i; | ||||
466 | for (i = 0; i < ref.length (); ++i) | ||||
467 | { | ||||
468 | fprintf (stderrstderr, "[%d] = ", i); | ||||
469 | debug_slim (ref[i]); | ||||
470 | fputc ('\n', stderrstderr); | ||||
471 | } | ||||
472 | } | ||||
473 | |||||
474 | /* Macro to define debug(vec<T>) and debug(vec<T, va_gc>) helper | ||||
475 | functions for a type T. */ | ||||
476 | |||||
477 | #define DEFINE_DEBUG_VEC(T)template void debug_helper (vec<T> &); template void debug_helper (vec<T, va_gc> &); __attribute__ ((__used__ )) void debug (vec<T> &ref) { debug_helper <T> (ref); } __attribute__ ((__used__)) void debug (vec<T> *ptr) { if (ptr) debug (*ptr); else fprintf (stderr, "<nil>\n" ); } __attribute__ ((__used__)) void debug (vec<T, va_gc> &ref) { debug_helper <T> (ref); } __attribute__ (( __used__)) void debug (vec<T, va_gc> *ptr) { if (ptr) debug (*ptr); else fprintf (stderr, "<nil>\n"); } \ | ||||
478 | template void debug_helper (vec<T> &); \ | ||||
479 | template void debug_helper (vec<T, va_gc> &); \ | ||||
480 | /* Define the vec<T> debug functions. */ \ | ||||
481 | DEBUG_FUNCTION__attribute__ ((__used__)) void \ | ||||
482 | debug (vec<T> &ref) \ | ||||
483 | { \ | ||||
484 | debug_helper <T> (ref); \ | ||||
485 | } \ | ||||
486 | DEBUG_FUNCTION__attribute__ ((__used__)) void \ | ||||
487 | debug (vec<T> *ptr) \ | ||||
488 | { \ | ||||
489 | if (ptr) \ | ||||
490 | debug (*ptr); \ | ||||
491 | else \ | ||||
492 | fprintf (stderrstderr, "<nil>\n"); \ | ||||
493 | } \ | ||||
494 | /* Define the vec<T, va_gc> debug functions. */ \ | ||||
495 | DEBUG_FUNCTION__attribute__ ((__used__)) void \ | ||||
496 | debug (vec<T, va_gc> &ref) \ | ||||
497 | { \ | ||||
498 | debug_helper <T> (ref); \ | ||||
499 | } \ | ||||
500 | DEBUG_FUNCTION__attribute__ ((__used__)) void \ | ||||
501 | debug (vec<T, va_gc> *ptr) \ | ||||
502 | { \ | ||||
503 | if (ptr) \ | ||||
504 | debug (*ptr); \ | ||||
505 | else \ | ||||
506 | fprintf (stderrstderr, "<nil>\n"); \ | ||||
507 | } | ||||
508 | |||||
509 | /* Default-construct N elements in DST. */ | ||||
510 | |||||
511 | template <typename T> | ||||
512 | inline void | ||||
513 | vec_default_construct (T *dst, unsigned n) | ||||
514 | { | ||||
515 | #ifdef BROKEN_VALUE_INITIALIZATION | ||||
516 | /* Versions of GCC before 4.4 sometimes leave certain objects | ||||
517 | uninitialized when value initialized, though if the type has | ||||
518 | user defined default ctor, that ctor is invoked. As a workaround | ||||
519 | perform clearing first and then the value initialization, which | ||||
520 | fixes the case when value initialization doesn't initialize due to | ||||
521 | the bugs and should initialize to all zeros, but still allows | ||||
522 | vectors for types with user defined default ctor that initializes | ||||
523 | some or all elements to non-zero. If T has no user defined | ||||
524 | default ctor and some non-static data members have user defined | ||||
525 | default ctors that initialize to non-zero the workaround will | ||||
526 | still not work properly; in that case we just need to provide | ||||
527 | user defined default ctor. */ | ||||
528 | memset (dst, '\0', sizeof (T) * n); | ||||
529 | #endif | ||||
530 | for ( ; n; ++dst, --n) | ||||
531 | ::new (static_cast<void*>(dst)) T (); | ||||
532 | } | ||||
533 | |||||
534 | /* Copy-construct N elements in DST from *SRC. */ | ||||
535 | |||||
536 | template <typename T> | ||||
537 | inline void | ||||
538 | vec_copy_construct (T *dst, const T *src, unsigned n) | ||||
539 | { | ||||
540 | for ( ; n; ++dst, ++src, --n) | ||||
541 | ::new (static_cast<void*>(dst)) T (*src); | ||||
542 | } | ||||
543 | |||||
544 | /* Type to provide NULL values for vec<T, A, L>. This is used to | ||||
545 | provide nil initializers for vec instances. Since vec must be | ||||
546 | a POD, we cannot have proper ctor/dtor for it. To initialize | ||||
547 | a vec instance, you can assign it the value vNULL. This isn't | ||||
548 | needed for file-scope and function-local static vectors, which | ||||
549 | are zero-initialized by default. */ | ||||
550 | struct vnull | ||||
551 | { | ||||
552 | template <typename T, typename A, typename L> | ||||
553 | CONSTEXPRconstexpr operator vec<T, A, L> () const { return vec<T, A, L>(); } | ||||
554 | }; | ||||
555 | extern vnull vNULL; | ||||
556 | |||||
557 | |||||
558 | /* Embeddable vector. These vectors are suitable to be embedded | ||||
559 | in other data structures so that they can be pre-allocated in a | ||||
560 | contiguous memory block. | ||||
561 | |||||
562 | Embeddable vectors are implemented using the trailing array idiom, | ||||
563 | thus they are not resizeable without changing the address of the | ||||
564 | vector object itself. This means you cannot have variables or | ||||
565 | fields of embeddable vector type -- always use a pointer to a | ||||
566 | vector. The one exception is the final field of a structure, which | ||||
567 | could be a vector type. | ||||
568 | |||||
569 | You will have to use the embedded_size & embedded_init calls to | ||||
570 | create such objects, and they will not be resizeable (so the 'safe' | ||||
571 | allocation variants are not available). | ||||
572 | |||||
573 | Properties: | ||||
574 | |||||
575 | - The whole vector and control data are allocated in a single | ||||
576 | contiguous block. It uses the trailing-vector idiom, so | ||||
577 | allocation must reserve enough space for all the elements | ||||
578 | in the vector plus its control data. | ||||
579 | - The vector cannot be re-allocated. | ||||
580 | - The vector cannot grow nor shrink. | ||||
581 | - No indirections needed for access/manipulation. | ||||
582 | - It requires 2 words of storage (prior to vector allocation). */ | ||||
583 | |||||
584 | template<typename T, typename A> | ||||
585 | struct GTY((user)) vec<T, A, vl_embed> | ||||
586 | { | ||||
587 | public: | ||||
588 | unsigned allocated (void) const { return m_vecpfx.m_alloc; } | ||||
589 | unsigned length (void) const { return m_vecpfx.m_num; } | ||||
590 | bool is_empty (void) const { return m_vecpfx.m_num == 0; } | ||||
591 | T *address (void) { return m_vecdata; } | ||||
592 | const T *address (void) const { return m_vecdata; } | ||||
593 | T *begin () { return address (); } | ||||
594 | const T *begin () const { return address (); } | ||||
595 | T *end () { return address () + length (); } | ||||
596 | const T *end () const { return address () + length (); } | ||||
597 | const T &operator[] (unsigned) const; | ||||
598 | T &operator[] (unsigned); | ||||
599 | T &last (void); | ||||
600 | bool space (unsigned) const; | ||||
601 | bool iterate (unsigned, T *) const; | ||||
602 | bool iterate (unsigned, T **) const; | ||||
603 | vec *copy (ALONE_CXX_MEM_STAT_INFO) const; | ||||
604 | void splice (const vec &); | ||||
605 | void splice (const vec *src); | ||||
606 | T *quick_push (const T &); | ||||
607 | T &pop (void); | ||||
608 | void truncate (unsigned); | ||||
609 | void quick_insert (unsigned, const T &); | ||||
610 | void ordered_remove (unsigned); | ||||
611 | void unordered_remove (unsigned); | ||||
612 | void block_remove (unsigned, unsigned); | ||||
613 | void qsort (int (*) (const void *, const void *))qsort (int (*) (const void *, const void *)); | ||||
614 | void sort (int (*) (const void *, const void *, void *), void *); | ||||
615 | T *bsearch (const void *key, int (*compar)(const void *, const void *)); | ||||
616 | T *bsearch (const void *key, | ||||
617 | int (*compar)(const void *, const void *, void *), void *); | ||||
618 | unsigned lower_bound (T, bool (*)(const T &, const T &)) const; | ||||
619 | bool contains (const T &search) const; | ||||
620 | static size_t embedded_size (unsigned); | ||||
621 | void embedded_init (unsigned, unsigned = 0, unsigned = 0); | ||||
622 | void quick_grow (unsigned len); | ||||
623 | void quick_grow_cleared (unsigned len); | ||||
624 | |||||
625 | /* vec class can access our internal data and functions. */ | ||||
626 | template <typename, typename, typename> friend struct vec; | ||||
627 | |||||
628 | /* The allocator types also need access to our internals. */ | ||||
629 | friend struct va_gc; | ||||
630 | friend struct va_gc_atomic; | ||||
631 | friend struct va_heap; | ||||
632 | |||||
633 | /* FIXME - These fields should be private, but we need to cater to | ||||
634 | compilers that have stricter notions of PODness for types. */ | ||||
635 | vec_prefix m_vecpfx; | ||||
636 | T m_vecdata[1]; | ||||
637 | }; | ||||
638 | |||||
639 | |||||
640 | /* Convenience wrapper functions to use when dealing with pointers to | ||||
641 | embedded vectors. Some functionality for these vectors must be | ||||
642 | provided via free functions for these reasons: | ||||
643 | |||||
644 | 1- The pointer may be NULL (e.g., before initial allocation). | ||||
645 | |||||
646 | 2- When the vector needs to grow, it must be reallocated, so | ||||
647 | the pointer will change its value. | ||||
648 | |||||
649 | Because of limitations with the current GC machinery, all vectors | ||||
650 | in GC memory *must* be pointers. */ | ||||
651 | |||||
652 | |||||
653 | /* If V contains no room for NELEMS elements, return false. Otherwise, | ||||
654 | return true. */ | ||||
655 | template<typename T, typename A> | ||||
656 | inline bool | ||||
657 | vec_safe_space (const vec<T, A, vl_embed> *v, unsigned nelems) | ||||
658 | { | ||||
659 | return v ? v->space (nelems) : nelems == 0; | ||||
660 | } | ||||
661 | |||||
662 | |||||
663 | /* If V is NULL, return 0. Otherwise, return V->length(). */ | ||||
664 | template<typename T, typename A> | ||||
665 | inline unsigned | ||||
666 | vec_safe_length (const vec<T, A, vl_embed> *v) | ||||
667 | { | ||||
668 | return v ? v->length () : 0; | ||||
669 | } | ||||
670 | |||||
671 | |||||
672 | /* If V is NULL, return NULL. Otherwise, return V->address(). */ | ||||
673 | template<typename T, typename A> | ||||
674 | inline T * | ||||
675 | vec_safe_address (vec<T, A, vl_embed> *v) | ||||
676 | { | ||||
677 | return v ? v->address () : NULLnullptr; | ||||
678 | } | ||||
679 | |||||
680 | |||||
681 | /* If V is NULL, return true. Otherwise, return V->is_empty(). */ | ||||
682 | template<typename T, typename A> | ||||
683 | inline bool | ||||
684 | vec_safe_is_empty (vec<T, A, vl_embed> *v) | ||||
685 | { | ||||
686 | return v ? v->is_empty () : true; | ||||
687 | } | ||||
688 | |||||
689 | /* If V does not have space for NELEMS elements, call | ||||
690 | V->reserve(NELEMS, EXACT). */ | ||||
691 | template<typename T, typename A> | ||||
692 | inline bool | ||||
693 | vec_safe_reserve (vec<T, A, vl_embed> *&v, unsigned nelems, bool exact = false | ||||
694 | CXX_MEM_STAT_INFO) | ||||
695 | { | ||||
696 | bool extend = nelems
| ||||
697 | if (extend
| ||||
698 | A::reserve (v, nelems, exact PASS_MEM_STAT); | ||||
699 | return extend; | ||||
700 | } | ||||
701 | |||||
702 | template<typename T, typename A> | ||||
703 | inline bool | ||||
704 | vec_safe_reserve_exact (vec<T, A, vl_embed> *&v, unsigned nelems | ||||
705 | CXX_MEM_STAT_INFO) | ||||
706 | { | ||||
707 | return vec_safe_reserve (v, nelems, true PASS_MEM_STAT); | ||||
708 | } | ||||
709 | |||||
710 | |||||
711 | /* Allocate GC memory for V with space for NELEMS slots. If NELEMS | ||||
712 | is 0, V is initialized to NULL. */ | ||||
713 | |||||
714 | template<typename T, typename A> | ||||
715 | inline void | ||||
716 | vec_alloc (vec<T, A, vl_embed> *&v, unsigned nelems CXX_MEM_STAT_INFO) | ||||
717 | { | ||||
718 | v = NULLnullptr; | ||||
719 | vec_safe_reserve (v, nelems, false PASS_MEM_STAT); | ||||
720 | } | ||||
721 | |||||
722 | |||||
723 | /* Free the GC memory allocated by vector V and set it to NULL. */ | ||||
724 | |||||
725 | template<typename T, typename A> | ||||
726 | inline void | ||||
727 | vec_free (vec<T, A, vl_embed> *&v) | ||||
728 | { | ||||
729 | A::release (v); | ||||
730 | } | ||||
731 | |||||
732 | |||||
733 | /* Grow V to length LEN. Allocate it, if necessary. */ | ||||
734 | template<typename T, typename A> | ||||
735 | inline void | ||||
736 | vec_safe_grow (vec<T, A, vl_embed> *&v, unsigned len, | ||||
737 | bool exact = false CXX_MEM_STAT_INFO) | ||||
738 | { | ||||
739 | unsigned oldlen = vec_safe_length (v); | ||||
740 | gcc_checking_assert (len >= oldlen)((void)(!(len >= oldlen) ? fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/vec.h" , 740, __FUNCTION__), 0 : 0)); | ||||
741 | vec_safe_reserve (v, len - oldlen, exact PASS_MEM_STAT); | ||||
742 | v->quick_grow (len); | ||||
743 | } | ||||
744 | |||||
745 | |||||
746 | /* If V is NULL, allocate it. Call V->safe_grow_cleared(LEN). */ | ||||
747 | template<typename T, typename A> | ||||
748 | inline void | ||||
749 | vec_safe_grow_cleared (vec<T, A, vl_embed> *&v, unsigned len, | ||||
750 | bool exact = false CXX_MEM_STAT_INFO) | ||||
751 | { | ||||
752 | unsigned oldlen = vec_safe_length (v); | ||||
753 | vec_safe_grow (v, len, exact PASS_MEM_STAT); | ||||
754 | vec_default_construct (v->address () + oldlen, len - oldlen); | ||||
755 | } | ||||
756 | |||||
757 | |||||
758 | /* Assume V is not NULL. */ | ||||
759 | |||||
760 | template<typename T> | ||||
761 | inline void | ||||
762 | vec_safe_grow_cleared (vec<T, va_heap, vl_ptr> *&v, | ||||
763 | unsigned len, bool exact = false CXX_MEM_STAT_INFO) | ||||
764 | { | ||||
765 | v->safe_grow_cleared (len, exact PASS_MEM_STAT); | ||||
766 | } | ||||
767 | |||||
768 | /* If V does not have space for NELEMS elements, call | ||||
769 | V->reserve(NELEMS, EXACT). */ | ||||
770 | |||||
771 | template<typename T> | ||||
772 | inline bool | ||||
773 | vec_safe_reserve (vec<T, va_heap, vl_ptr> *&v, unsigned nelems, bool exact = false | ||||
774 | CXX_MEM_STAT_INFO) | ||||
775 | { | ||||
776 | return v->reserve (nelems, exact); | ||||
777 | } | ||||
778 | |||||
779 | |||||
780 | /* If V is NULL return false, otherwise return V->iterate(IX, PTR). */ | ||||
781 | template<typename T, typename A> | ||||
782 | inline bool | ||||
783 | vec_safe_iterate (const vec<T, A, vl_embed> *v, unsigned ix, T **ptr) | ||||
784 | { | ||||
785 | if (v) | ||||
786 | return v->iterate (ix, ptr); | ||||
787 | else | ||||
788 | { | ||||
789 | *ptr = 0; | ||||
790 | return false; | ||||
791 | } | ||||
792 | } | ||||
793 | |||||
794 | template<typename T, typename A> | ||||
795 | inline bool | ||||
796 | vec_safe_iterate (const vec<T, A, vl_embed> *v, unsigned ix, T *ptr) | ||||
797 | { | ||||
798 | if (v) | ||||
799 | return v->iterate (ix, ptr); | ||||
800 | else | ||||
801 | { | ||||
802 | *ptr = 0; | ||||
803 | return false; | ||||
804 | } | ||||
805 | } | ||||
806 | |||||
807 | |||||
808 | /* If V has no room for one more element, reallocate it. Then call | ||||
809 | V->quick_push(OBJ). */ | ||||
810 | template<typename T, typename A> | ||||
811 | inline T * | ||||
812 | vec_safe_push (vec<T, A, vl_embed> *&v, const T &obj CXX_MEM_STAT_INFO) | ||||
813 | { | ||||
814 | vec_safe_reserve (v, 1, false PASS_MEM_STAT); | ||||
815 | return v->quick_push (obj); | ||||
| |||||
816 | } | ||||
817 | |||||
818 | |||||
819 | /* if V has no room for one more element, reallocate it. Then call | ||||
820 | V->quick_insert(IX, OBJ). */ | ||||
821 | template<typename T, typename A> | ||||
822 | inline void | ||||
823 | vec_safe_insert (vec<T, A, vl_embed> *&v, unsigned ix, const T &obj | ||||
824 | CXX_MEM_STAT_INFO) | ||||
825 | { | ||||
826 | vec_safe_reserve (v, 1, false PASS_MEM_STAT); | ||||
827 | v->quick_insert (ix, obj); | ||||
828 | } | ||||
829 | |||||
830 | |||||
831 | /* If V is NULL, do nothing. Otherwise, call V->truncate(SIZE). */ | ||||
832 | template<typename T, typename A> | ||||
833 | inline void | ||||
834 | vec_safe_truncate (vec<T, A, vl_embed> *v, unsigned size) | ||||
835 | { | ||||
836 | if (v) | ||||
837 | v->truncate (size); | ||||
838 | } | ||||
839 | |||||
840 | |||||
841 | /* If SRC is not NULL, return a pointer to a copy of it. */ | ||||
842 | template<typename T, typename A> | ||||
843 | inline vec<T, A, vl_embed> * | ||||
844 | vec_safe_copy (vec<T, A, vl_embed> *src CXX_MEM_STAT_INFO) | ||||
845 | { | ||||
846 | return src ? src->copy (ALONE_PASS_MEM_STAT) : NULLnullptr; | ||||
847 | } | ||||
848 | |||||
849 | /* Copy the elements from SRC to the end of DST as if by memcpy. | ||||
850 | Reallocate DST, if necessary. */ | ||||
851 | template<typename T, typename A> | ||||
852 | inline void | ||||
853 | vec_safe_splice (vec<T, A, vl_embed> *&dst, const vec<T, A, vl_embed> *src | ||||
854 | CXX_MEM_STAT_INFO) | ||||
855 | { | ||||
856 | unsigned src_len = vec_safe_length (src); | ||||
857 | if (src_len) | ||||
858 | { | ||||
859 | vec_safe_reserve_exact (dst, vec_safe_length (dst) + src_len | ||||
860 | PASS_MEM_STAT); | ||||
861 | dst->splice (*src); | ||||
862 | } | ||||
863 | } | ||||
864 | |||||
865 | /* Return true if SEARCH is an element of V. Note that this is O(N) in the | ||||
866 | size of the vector and so should be used with care. */ | ||||
867 | |||||
868 | template<typename T, typename A> | ||||
869 | inline bool | ||||
870 | vec_safe_contains (vec<T, A, vl_embed> *v, const T &search) | ||||
871 | { | ||||
872 | return v ? v->contains (search) : false; | ||||
873 | } | ||||
874 | |||||
875 | /* Index into vector. Return the IX'th element. IX must be in the | ||||
876 | domain of the vector. */ | ||||
877 | |||||
878 | template<typename T, typename A> | ||||
879 | inline const T & | ||||
880 | vec<T, A, vl_embed>::operator[] (unsigned ix) const | ||||
881 | { | ||||
882 | gcc_checking_assert (ix < m_vecpfx.m_num)((void)(!(ix < m_vecpfx.m_num) ? fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/vec.h" , 882, __FUNCTION__), 0 : 0)); | ||||
883 | return m_vecdata[ix]; | ||||
884 | } | ||||
885 | |||||
886 | template<typename T, typename A> | ||||
887 | inline T & | ||||
888 | vec<T, A, vl_embed>::operator[] (unsigned ix) | ||||
889 | { | ||||
890 | gcc_checking_assert (ix < m_vecpfx.m_num)((void)(!(ix < m_vecpfx.m_num) ? fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/vec.h" , 890, __FUNCTION__), 0 : 0)); | ||||
891 | return m_vecdata[ix]; | ||||
892 | } | ||||
893 | |||||
894 | |||||
895 | /* Get the final element of the vector, which must not be empty. */ | ||||
896 | |||||
897 | template<typename T, typename A> | ||||
898 | inline T & | ||||
899 | vec<T, A, vl_embed>::last (void) | ||||
900 | { | ||||
901 | gcc_checking_assert (m_vecpfx.m_num > 0)((void)(!(m_vecpfx.m_num > 0) ? fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/vec.h" , 901, __FUNCTION__), 0 : 0)); | ||||
902 | return (*this)[m_vecpfx.m_num - 1]; | ||||
903 | } | ||||
904 | |||||
905 | |||||
906 | /* If this vector has space for NELEMS additional entries, return | ||||
907 | true. You usually only need to use this if you are doing your | ||||
908 | own vector reallocation, for instance on an embedded vector. This | ||||
909 | returns true in exactly the same circumstances that vec::reserve | ||||
910 | will. */ | ||||
911 | |||||
912 | template<typename T, typename A> | ||||
913 | inline bool | ||||
914 | vec<T, A, vl_embed>::space (unsigned nelems) const | ||||
915 | { | ||||
916 | return m_vecpfx.m_alloc - m_vecpfx.m_num >= nelems; | ||||
917 | } | ||||
918 | |||||
919 | |||||
920 | /* Return iteration condition and update PTR to point to the IX'th | ||||
921 | element of this vector. Use this to iterate over the elements of a | ||||
922 | vector as follows, | ||||
923 | |||||
924 | for (ix = 0; vec<T, A>::iterate (v, ix, &ptr); ix++) | ||||
925 | continue; */ | ||||
926 | |||||
927 | template<typename T, typename A> | ||||
928 | inline bool | ||||
929 | vec<T, A, vl_embed>::iterate (unsigned ix, T *ptr) const | ||||
930 | { | ||||
931 | if (ix < m_vecpfx.m_num) | ||||
932 | { | ||||
933 | *ptr = m_vecdata[ix]; | ||||
934 | return true; | ||||
935 | } | ||||
936 | else | ||||
937 | { | ||||
938 | *ptr = 0; | ||||
939 | return false; | ||||
940 | } | ||||
941 | } | ||||
942 | |||||
943 | |||||
944 | /* Return iteration condition and update *PTR to point to the | ||||
945 | IX'th element of this vector. Use this to iterate over the | ||||
946 | elements of a vector as follows, | ||||
947 | |||||
948 | for (ix = 0; v->iterate (ix, &ptr); ix++) | ||||
949 | continue; | ||||
950 | |||||
951 | This variant is for vectors of objects. */ | ||||
952 | |||||
953 | template<typename T, typename A> | ||||
954 | inline bool | ||||
955 | vec<T, A, vl_embed>::iterate (unsigned ix, T **ptr) const | ||||
956 | { | ||||
957 | if (ix < m_vecpfx.m_num) | ||||
958 | { | ||||
959 | *ptr = CONST_CAST (T *, &m_vecdata[ix])(const_cast<T *> ((&m_vecdata[ix]))); | ||||
960 | return true; | ||||
961 | } | ||||
962 | else | ||||
963 | { | ||||
964 | *ptr = 0; | ||||
965 | return false; | ||||
966 | } | ||||
967 | } | ||||
968 | |||||
969 | |||||
970 | /* Return a pointer to a copy of this vector. */ | ||||
971 | |||||
972 | template<typename T, typename A> | ||||
973 | inline vec<T, A, vl_embed> * | ||||
974 | vec<T, A, vl_embed>::copy (ALONE_MEM_STAT_DECLvoid) const | ||||
975 | { | ||||
976 | vec<T, A, vl_embed> *new_vec = NULLnullptr; | ||||
977 | unsigned len = length (); | ||||
978 | if (len) | ||||
979 | { | ||||
980 | vec_alloc (new_vec, len PASS_MEM_STAT); | ||||
981 | new_vec->embedded_init (len, len); | ||||
982 | vec_copy_construct (new_vec->address (), m_vecdata, len); | ||||
983 | } | ||||
984 | return new_vec; | ||||
985 | } | ||||
986 | |||||
987 | |||||
988 | /* Copy the elements from SRC to the end of this vector as if by memcpy. | ||||
989 | The vector must have sufficient headroom available. */ | ||||
990 | |||||
991 | template<typename T, typename A> | ||||
992 | inline void | ||||
993 | vec<T, A, vl_embed>::splice (const vec<T, A, vl_embed> &src) | ||||
994 | { | ||||
995 | unsigned len = src.length (); | ||||
996 | if (len) | ||||
997 | { | ||||
998 | gcc_checking_assert (space (len))((void)(!(space (len)) ? fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/vec.h" , 998, __FUNCTION__), 0 : 0)); | ||||
999 | vec_copy_construct (end (), src.address (), len); | ||||
1000 | m_vecpfx.m_num += len; | ||||
1001 | } | ||||
1002 | } | ||||
1003 | |||||
1004 | template<typename T, typename A> | ||||
1005 | inline void | ||||
1006 | vec<T, A, vl_embed>::splice (const vec<T, A, vl_embed> *src) | ||||
1007 | { | ||||
1008 | if (src) | ||||
1009 | splice (*src); | ||||
1010 | } | ||||
1011 | |||||
1012 | |||||
1013 | /* Push OBJ (a new element) onto the end of the vector. There must be | ||||
1014 | sufficient space in the vector. Return a pointer to the slot | ||||
1015 | where OBJ was inserted. */ | ||||
1016 | |||||
1017 | template<typename T, typename A> | ||||
1018 | inline T * | ||||
1019 | vec<T, A, vl_embed>::quick_push (const T &obj) | ||||
1020 | { | ||||
1021 | gcc_checking_assert (space (1))((void)(!(space (1)) ? fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/vec.h" , 1021, __FUNCTION__), 0 : 0)); | ||||
1022 | T *slot = &m_vecdata[m_vecpfx.m_num++]; | ||||
1023 | *slot = obj; | ||||
1024 | return slot; | ||||
1025 | } | ||||
1026 | |||||
1027 | |||||
1028 | /* Pop and return the last element off the end of the vector. */ | ||||
1029 | |||||
1030 | template<typename T, typename A> | ||||
1031 | inline T & | ||||
1032 | vec<T, A, vl_embed>::pop (void) | ||||
1033 | { | ||||
1034 | gcc_checking_assert (length () > 0)((void)(!(length () > 0) ? fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/vec.h" , 1034, __FUNCTION__), 0 : 0)); | ||||
1035 | return m_vecdata[--m_vecpfx.m_num]; | ||||
1036 | } | ||||
1037 | |||||
1038 | |||||
1039 | /* Set the length of the vector to SIZE. The new length must be less | ||||
1040 | than or equal to the current length. This is an O(1) operation. */ | ||||
1041 | |||||
1042 | template<typename T, typename A> | ||||
1043 | inline void | ||||
1044 | vec<T, A, vl_embed>::truncate (unsigned size) | ||||
1045 | { | ||||
1046 | gcc_checking_assert (length () >= size)((void)(!(length () >= size) ? fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/vec.h" , 1046, __FUNCTION__), 0 : 0)); | ||||
1047 | m_vecpfx.m_num = size; | ||||
1048 | } | ||||
1049 | |||||
1050 | |||||
1051 | /* Insert an element, OBJ, at the IXth position of this vector. There | ||||
1052 | must be sufficient space. */ | ||||
1053 | |||||
1054 | template<typename T, typename A> | ||||
1055 | inline void | ||||
1056 | vec<T, A, vl_embed>::quick_insert (unsigned ix, const T &obj) | ||||
1057 | { | ||||
1058 | gcc_checking_assert (length () < allocated ())((void)(!(length () < allocated ()) ? fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/vec.h" , 1058, __FUNCTION__), 0 : 0)); | ||||
1059 | gcc_checking_assert (ix <= length ())((void)(!(ix <= length ()) ? fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/vec.h" , 1059, __FUNCTION__), 0 : 0)); | ||||
1060 | T *slot = &m_vecdata[ix]; | ||||
1061 | memmove (slot + 1, slot, (m_vecpfx.m_num++ - ix) * sizeof (T)); | ||||
1062 | *slot = obj; | ||||
1063 | } | ||||
1064 | |||||
1065 | |||||
1066 | /* Remove an element from the IXth position of this vector. Ordering of | ||||
1067 | remaining elements is preserved. This is an O(N) operation due to | ||||
1068 | memmove. */ | ||||
1069 | |||||
1070 | template<typename T, typename A> | ||||
1071 | inline void | ||||
1072 | vec<T, A, vl_embed>::ordered_remove (unsigned ix) | ||||
1073 | { | ||||
1074 | gcc_checking_assert (ix < length ())((void)(!(ix < length ()) ? fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/vec.h" , 1074, __FUNCTION__), 0 : 0)); | ||||
1075 | T *slot = &m_vecdata[ix]; | ||||
1076 | memmove (slot, slot + 1, (--m_vecpfx.m_num - ix) * sizeof (T)); | ||||
1077 | } | ||||
1078 | |||||
1079 | |||||
1080 | /* Remove elements in [START, END) from VEC for which COND holds. Ordering of | ||||
1081 | remaining elements is preserved. This is an O(N) operation. */ | ||||
1082 | |||||
1083 | #define VEC_ORDERED_REMOVE_IF_FROM_TO(vec, read_index, write_index, \{ ((void)(!((end) <= (vec).length ()) ? fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/vec.h" , 1084, __FUNCTION__), 0 : 0)); for (read_index = write_index = (start); read_index < (end); ++read_index) { elem_ptr = &(vec)[read_index]; bool remove_p = (cond); if (remove_p ) continue; if (read_index != write_index) (vec)[write_index] = (vec)[read_index]; write_index++; } if (read_index - write_index > 0) (vec).block_remove (write_index, read_index - write_index ); } | ||||
1084 | elem_ptr, start, end, cond){ ((void)(!((end) <= (vec).length ()) ? fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/vec.h" , 1084, __FUNCTION__), 0 : 0)); for (read_index = write_index = (start); read_index < (end); ++read_index) { elem_ptr = &(vec)[read_index]; bool remove_p = (cond); if (remove_p ) continue; if (read_index != write_index) (vec)[write_index] = (vec)[read_index]; write_index++; } if (read_index - write_index > 0) (vec).block_remove (write_index, read_index - write_index ); } \ | ||||
1085 | { \ | ||||
1086 | gcc_assert ((end) <= (vec).length ())((void)(!((end) <= (vec).length ()) ? fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/vec.h" , 1086, __FUNCTION__), 0 : 0)); \ | ||||
1087 | for (read_index = write_index = (start); read_index < (end); \ | ||||
1088 | ++read_index) \ | ||||
1089 | { \ | ||||
1090 | elem_ptr = &(vec)[read_index]; \ | ||||
1091 | bool remove_p = (cond); \ | ||||
1092 | if (remove_p) \ | ||||
1093 | continue; \ | ||||
1094 | \ | ||||
1095 | if (read_index != write_index) \ | ||||
1096 | (vec)[write_index] = (vec)[read_index]; \ | ||||
1097 | \ | ||||
1098 | write_index++; \ | ||||
1099 | } \ | ||||
1100 | \ | ||||
1101 | if (read_index - write_index > 0) \ | ||||
1102 | (vec).block_remove (write_index, read_index - write_index); \ | ||||
1103 | } | ||||
1104 | |||||
1105 | |||||
1106 | /* Remove elements from VEC for which COND holds. Ordering of remaining | ||||
1107 | elements is preserved. This is an O(N) operation. */ | ||||
1108 | |||||
1109 | #define VEC_ORDERED_REMOVE_IF(vec, read_index, write_index, elem_ptr, \{ ((void)(!(((vec).length ()) <= ((vec)).length ()) ? fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/vec.h" , 1110, __FUNCTION__), 0 : 0)); for (read_index = write_index = (0); read_index < ((vec).length ()); ++read_index) { elem_ptr = &((vec))[read_index]; bool remove_p = ((cond)); if (remove_p ) continue; if (read_index != write_index) ((vec))[write_index ] = ((vec))[read_index]; write_index++; } if (read_index - write_index > 0) ((vec)).block_remove (write_index, read_index - write_index ); } | ||||
1110 | cond){ ((void)(!(((vec).length ()) <= ((vec)).length ()) ? fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/vec.h" , 1110, __FUNCTION__), 0 : 0)); for (read_index = write_index = (0); read_index < ((vec).length ()); ++read_index) { elem_ptr = &((vec))[read_index]; bool remove_p = ((cond)); if (remove_p ) continue; if (read_index != write_index) ((vec))[write_index ] = ((vec))[read_index]; write_index++; } if (read_index - write_index > 0) ((vec)).block_remove (write_index, read_index - write_index ); } \ | ||||
1111 | VEC_ORDERED_REMOVE_IF_FROM_TO ((vec), read_index, write_index, \{ ((void)(!(((vec).length ()) <= ((vec)).length ()) ? fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/vec.h" , 1112, __FUNCTION__), 0 : 0)); for (read_index = write_index = (0); read_index < ((vec).length ()); ++read_index) { elem_ptr = &((vec))[read_index]; bool remove_p = ((cond)); if (remove_p ) continue; if (read_index != write_index) ((vec))[write_index ] = ((vec))[read_index]; write_index++; } if (read_index - write_index > 0) ((vec)).block_remove (write_index, read_index - write_index ); } | ||||
1112 | elem_ptr, 0, (vec).length (), (cond)){ ((void)(!(((vec).length ()) <= ((vec)).length ()) ? fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/vec.h" , 1112, __FUNCTION__), 0 : 0)); for (read_index = write_index = (0); read_index < ((vec).length ()); ++read_index) { elem_ptr = &((vec))[read_index]; bool remove_p = ((cond)); if (remove_p ) continue; if (read_index != write_index) ((vec))[write_index ] = ((vec))[read_index]; write_index++; } if (read_index - write_index > 0) ((vec)).block_remove (write_index, read_index - write_index ); } | ||||
1113 | |||||
1114 | /* Remove an element from the IXth position of this vector. Ordering of | ||||
1115 | remaining elements is destroyed. This is an O(1) operation. */ | ||||
1116 | |||||
1117 | template<typename T, typename A> | ||||
1118 | inline void | ||||
1119 | vec<T, A, vl_embed>::unordered_remove (unsigned ix) | ||||
1120 | { | ||||
1121 | gcc_checking_assert (ix < length ())((void)(!(ix < length ()) ? fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/vec.h" , 1121, __FUNCTION__), 0 : 0)); | ||||
1122 | m_vecdata[ix] = m_vecdata[--m_vecpfx.m_num]; | ||||
1123 | } | ||||
1124 | |||||
1125 | |||||
1126 | /* Remove LEN elements starting at the IXth. Ordering is retained. | ||||
1127 | This is an O(N) operation due to memmove. */ | ||||
1128 | |||||
1129 | template<typename T, typename A> | ||||
1130 | inline void | ||||
1131 | vec<T, A, vl_embed>::block_remove (unsigned ix, unsigned len) | ||||
1132 | { | ||||
1133 | gcc_checking_assert (ix + len <= length ())((void)(!(ix + len <= length ()) ? fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/vec.h" , 1133, __FUNCTION__), 0 : 0)); | ||||
1134 | T *slot = &m_vecdata[ix]; | ||||
1135 | m_vecpfx.m_num -= len; | ||||
1136 | memmove (slot, slot + len, (m_vecpfx.m_num - ix) * sizeof (T)); | ||||
1137 | } | ||||
1138 | |||||
1139 | |||||
1140 | /* Sort the contents of this vector with qsort. CMP is the comparison | ||||
1141 | function to pass to qsort. */ | ||||
1142 | |||||
1143 | template<typename T, typename A> | ||||
1144 | inline void | ||||
1145 | vec<T, A, vl_embed>::qsort (int (*cmp) (const void *, const void *))qsort (int (*cmp) (const void *, const void *)) | ||||
1146 | { | ||||
1147 | if (length () > 1) | ||||
1148 | gcc_qsort (address (), length (), sizeof (T), cmp); | ||||
1149 | } | ||||
1150 | |||||
1151 | /* Sort the contents of this vector with qsort. CMP is the comparison | ||||
1152 | function to pass to qsort. */ | ||||
1153 | |||||
1154 | template<typename T, typename A> | ||||
1155 | inline void | ||||
1156 | vec<T, A, vl_embed>::sort (int (*cmp) (const void *, const void *, void *), | ||||
1157 | void *data) | ||||
1158 | { | ||||
1159 | if (length () > 1) | ||||
1160 | gcc_sort_r (address (), length (), sizeof (T), cmp, data); | ||||
1161 | } | ||||
1162 | |||||
1163 | |||||
1164 | /* Search the contents of the sorted vector with a binary search. | ||||
1165 | CMP is the comparison function to pass to bsearch. */ | ||||
1166 | |||||
1167 | template<typename T, typename A> | ||||
1168 | inline T * | ||||
1169 | vec<T, A, vl_embed>::bsearch (const void *key, | ||||
1170 | int (*compar) (const void *, const void *)) | ||||
1171 | { | ||||
1172 | const void *base = this->address (); | ||||
1173 | size_t nmemb = this->length (); | ||||
1174 | size_t size = sizeof (T); | ||||
1175 | /* The following is a copy of glibc stdlib-bsearch.h. */ | ||||
1176 | size_t l, u, idx; | ||||
1177 | const void *p; | ||||
1178 | int comparison; | ||||
1179 | |||||
1180 | l = 0; | ||||
1181 | u = nmemb; | ||||
1182 | while (l < u) | ||||
1183 | { | ||||
1184 | idx = (l + u) / 2; | ||||
1185 | p = (const void *) (((const char *) base) + (idx * size)); | ||||
1186 | comparison = (*compar) (key, p); | ||||
1187 | if (comparison < 0) | ||||
1188 | u = idx; | ||||
1189 | else if (comparison > 0) | ||||
1190 | l = idx + 1; | ||||
1191 | else | ||||
1192 | return (T *)const_cast<void *>(p); | ||||
1193 | } | ||||
1194 | |||||
1195 | return NULLnullptr; | ||||
1196 | } | ||||
1197 | |||||
1198 | /* Search the contents of the sorted vector with a binary search. | ||||
1199 | CMP is the comparison function to pass to bsearch. */ | ||||
1200 | |||||
1201 | template<typename T, typename A> | ||||
1202 | inline T * | ||||
1203 | vec<T, A, vl_embed>::bsearch (const void *key, | ||||
1204 | int (*compar) (const void *, const void *, | ||||
1205 | void *), void *data) | ||||
1206 | { | ||||
1207 | const void *base = this->address (); | ||||
1208 | size_t nmemb = this->length (); | ||||
1209 | size_t size = sizeof (T); | ||||
1210 | /* The following is a copy of glibc stdlib-bsearch.h. */ | ||||
1211 | size_t l, u, idx; | ||||
1212 | const void *p; | ||||
1213 | int comparison; | ||||
1214 | |||||
1215 | l = 0; | ||||
1216 | u = nmemb; | ||||
1217 | while (l < u) | ||||
1218 | { | ||||
1219 | idx = (l + u) / 2; | ||||
1220 | p = (const void *) (((const char *) base) + (idx * size)); | ||||
1221 | comparison = (*compar) (key, p, data); | ||||
1222 | if (comparison < 0) | ||||
1223 | u = idx; | ||||
1224 | else if (comparison > 0) | ||||
1225 | l = idx + 1; | ||||
1226 | else | ||||
1227 | return (T *)const_cast<void *>(p); | ||||
1228 | } | ||||
1229 | |||||
1230 | return NULLnullptr; | ||||
1231 | } | ||||
1232 | |||||
1233 | /* Return true if SEARCH is an element of V. Note that this is O(N) in the | ||||
1234 | size of the vector and so should be used with care. */ | ||||
1235 | |||||
1236 | template<typename T, typename A> | ||||
1237 | inline bool | ||||
1238 | vec<T, A, vl_embed>::contains (const T &search) const | ||||
1239 | { | ||||
1240 | unsigned int len = length (); | ||||
1241 | for (unsigned int i = 0; i < len; i++) | ||||
1242 | if ((*this)[i] == search) | ||||
1243 | return true; | ||||
1244 | |||||
1245 | return false; | ||||
1246 | } | ||||
1247 | |||||
1248 | /* Find and return the first position in which OBJ could be inserted | ||||
1249 | without changing the ordering of this vector. LESSTHAN is a | ||||
1250 | function that returns true if the first argument is strictly less | ||||
1251 | than the second. */ | ||||
1252 | |||||
1253 | template<typename T, typename A> | ||||
1254 | unsigned | ||||
1255 | vec<T, A, vl_embed>::lower_bound (T obj, bool (*lessthan)(const T &, const T &)) | ||||
1256 | const | ||||
1257 | { | ||||
1258 | unsigned int len = length (); | ||||
1259 | unsigned int half, middle; | ||||
1260 | unsigned int first = 0; | ||||
1261 | while (len > 0) | ||||
1262 | { | ||||
1263 | half = len / 2; | ||||
1264 | middle = first; | ||||
1265 | middle += half; | ||||
1266 | T middle_elem = (*this)[middle]; | ||||
1267 | if (lessthan (middle_elem, obj)) | ||||
1268 | { | ||||
1269 | first = middle; | ||||
1270 | ++first; | ||||
1271 | len = len - half - 1; | ||||
1272 | } | ||||
1273 | else | ||||
1274 | len = half; | ||||
1275 | } | ||||
1276 | return first; | ||||
1277 | } | ||||
1278 | |||||
1279 | |||||
1280 | /* Return the number of bytes needed to embed an instance of an | ||||
1281 | embeddable vec inside another data structure. | ||||
1282 | |||||
1283 | Use these methods to determine the required size and initialization | ||||
1284 | of a vector V of type T embedded within another structure (as the | ||||
1285 | final member): | ||||
1286 | |||||
1287 | size_t vec<T, A, vl_embed>::embedded_size (unsigned alloc); | ||||
1288 | void v->embedded_init (unsigned alloc, unsigned num); | ||||
1289 | |||||
1290 | These allow the caller to perform the memory allocation. */ | ||||
1291 | |||||
1292 | template<typename T, typename A> | ||||
1293 | inline size_t | ||||
1294 | vec<T, A, vl_embed>::embedded_size (unsigned alloc) | ||||
1295 | { | ||||
1296 | struct alignas (T) U { char data[sizeof (T)]; }; | ||||
1297 | typedef vec<U, A, vl_embed> vec_embedded; | ||||
1298 | typedef typename std::conditional<std::is_standard_layout<T>::value, | ||||
1299 | vec, vec_embedded>::type vec_stdlayout; | ||||
1300 | static_assert (sizeof (vec_stdlayout) == sizeof (vec), ""); | ||||
1301 | static_assert (alignof (vec_stdlayout) == alignof (vec), ""); | ||||
1302 | return offsetof (vec_stdlayout, m_vecdata)__builtin_offsetof(vec_stdlayout, m_vecdata) + alloc * sizeof (T); | ||||
1303 | } | ||||
1304 | |||||
1305 | |||||
1306 | /* Initialize the vector to contain room for ALLOC elements and | ||||
1307 | NUM active elements. */ | ||||
1308 | |||||
1309 | template<typename T, typename A> | ||||
1310 | inline void | ||||
1311 | vec<T, A, vl_embed>::embedded_init (unsigned alloc, unsigned num, unsigned aut) | ||||
1312 | { | ||||
1313 | m_vecpfx.m_alloc = alloc; | ||||
1314 | m_vecpfx.m_using_auto_storage = aut; | ||||
1315 | m_vecpfx.m_num = num; | ||||
1316 | } | ||||
1317 | |||||
1318 | |||||
1319 | /* Grow the vector to a specific length. LEN must be as long or longer than | ||||
1320 | the current length. The new elements are uninitialized. */ | ||||
1321 | |||||
1322 | template<typename T, typename A> | ||||
1323 | inline void | ||||
1324 | vec<T, A, vl_embed>::quick_grow (unsigned len) | ||||
1325 | { | ||||
1326 | gcc_checking_assert (length () <= len && len <= m_vecpfx.m_alloc)((void)(!(length () <= len && len <= m_vecpfx.m_alloc ) ? fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/vec.h" , 1326, __FUNCTION__), 0 : 0)); | ||||
1327 | m_vecpfx.m_num = len; | ||||
1328 | } | ||||
1329 | |||||
1330 | |||||
1331 | /* Grow the vector to a specific length. LEN must be as long or longer than | ||||
1332 | the current length. The new elements are initialized to zero. */ | ||||
1333 | |||||
1334 | template<typename T, typename A> | ||||
1335 | inline void | ||||
1336 | vec<T, A, vl_embed>::quick_grow_cleared (unsigned len) | ||||
1337 | { | ||||
1338 | unsigned oldlen = length (); | ||||
1339 | size_t growby = len - oldlen; | ||||
1340 | quick_grow (len); | ||||
1341 | if (growby != 0) | ||||
1342 | vec_default_construct (address () + oldlen, growby); | ||||
1343 | } | ||||
1344 | |||||
1345 | /* Garbage collection support for vec<T, A, vl_embed>. */ | ||||
1346 | |||||
1347 | template<typename T> | ||||
1348 | void | ||||
1349 | gt_ggc_mx (vec<T, va_gc> *v) | ||||
1350 | { | ||||
1351 | extern void gt_ggc_mx (T &); | ||||
1352 | for (unsigned i = 0; i < v->length (); i++) | ||||
1353 | gt_ggc_mx ((*v)[i]); | ||||
1354 | } | ||||
1355 | |||||
1356 | template<typename T> | ||||
1357 | void | ||||
1358 | gt_ggc_mx (vec<T, va_gc_atomic, vl_embed> *v ATTRIBUTE_UNUSED__attribute__ ((__unused__))) | ||||
1359 | { | ||||
1360 | /* Nothing to do. Vectors of atomic types wrt GC do not need to | ||||
1361 | be traversed. */ | ||||
1362 | } | ||||
1363 | |||||
1364 | |||||
1365 | /* PCH support for vec<T, A, vl_embed>. */ | ||||
1366 | |||||
1367 | template<typename T, typename A> | ||||
1368 | void | ||||
1369 | gt_pch_nx (vec<T, A, vl_embed> *v) | ||||
1370 | { | ||||
1371 | extern void gt_pch_nx (T &); | ||||
1372 | for (unsigned i = 0; i < v->length (); i++) | ||||
1373 | gt_pch_nx ((*v)[i]); | ||||
1374 | } | ||||
1375 | |||||
1376 | template<typename T, typename A> | ||||
1377 | void | ||||
1378 | gt_pch_nx (vec<T *, A, vl_embed> *v, gt_pointer_operator op, void *cookie) | ||||
1379 | { | ||||
1380 | for (unsigned i = 0; i < v->length (); i++) | ||||
1381 | op (&((*v)[i]), cookie); | ||||
1382 | } | ||||
1383 | |||||
1384 | template<typename T, typename A> | ||||
1385 | void | ||||
1386 | gt_pch_nx (vec<T, A, vl_embed> *v, gt_pointer_operator op, void *cookie) | ||||
1387 | { | ||||
1388 | extern void gt_pch_nx (T *, gt_pointer_operator, void *); | ||||
1389 | for (unsigned i = 0; i < v->length (); i++) | ||||
1390 | gt_pch_nx (&((*v)[i]), op, cookie); | ||||
1391 | } | ||||
1392 | |||||
1393 | |||||
1394 | /* Space efficient vector. These vectors can grow dynamically and are | ||||
1395 | allocated together with their control data. They are suited to be | ||||
1396 | included in data structures. Prior to initial allocation, they | ||||
1397 | only take a single word of storage. | ||||
1398 | |||||
1399 | These vectors are implemented as a pointer to an embeddable vector. | ||||
1400 | The semantics allow for this pointer to be NULL to represent empty | ||||
1401 | vectors. This way, empty vectors occupy minimal space in the | ||||
1402 | structure containing them. | ||||
1403 | |||||
1404 | Properties: | ||||
1405 | |||||
1406 | - The whole vector and control data are allocated in a single | ||||
1407 | contiguous block. | ||||
1408 | - The whole vector may be re-allocated. | ||||
1409 | - Vector data may grow and shrink. | ||||
1410 | - Access and manipulation requires a pointer test and | ||||
1411 | indirection. | ||||
1412 | - It requires 1 word of storage (prior to vector allocation). | ||||
1413 | |||||
1414 | |||||
1415 | Limitations: | ||||
1416 | |||||
1417 | These vectors must be PODs because they are stored in unions. | ||||
1418 | (http://en.wikipedia.org/wiki/Plain_old_data_structures). | ||||
1419 | As long as we use C++03, we cannot have constructors nor | ||||
1420 | destructors in classes that are stored in unions. */ | ||||
1421 | |||||
1422 | template<typename T> | ||||
1423 | struct vec<T, va_heap, vl_ptr> | ||||
1424 | { | ||||
1425 | public: | ||||
1426 | /* Memory allocation and deallocation for the embedded vector. | ||||
1427 | Needed because we cannot have proper ctors/dtors defined. */ | ||||
1428 | void create (unsigned nelems CXX_MEM_STAT_INFO); | ||||
1429 | void release (void); | ||||
1430 | |||||
1431 | /* Vector operations. */ | ||||
1432 | bool exists (void) const | ||||
1433 | { return m_vec != NULLnullptr; } | ||||
1434 | |||||
1435 | bool is_empty (void) const | ||||
1436 | { return m_vec ? m_vec->is_empty () : true; } | ||||
1437 | |||||
1438 | unsigned length (void) const | ||||
1439 | { return m_vec ? m_vec->length () : 0; } | ||||
1440 | |||||
1441 | T *address (void) | ||||
1442 | { return m_vec ? m_vec->m_vecdata : NULLnullptr; } | ||||
1443 | |||||
1444 | const T *address (void) const | ||||
1445 | { return m_vec ? m_vec->m_vecdata : NULLnullptr; } | ||||
1446 | |||||
1447 | T *begin () { return address (); } | ||||
1448 | const T *begin () const { return address (); } | ||||
1449 | T *end () { return begin () + length (); } | ||||
1450 | const T *end () const { return begin () + length (); } | ||||
1451 | const T &operator[] (unsigned ix) const | ||||
1452 | { return (*m_vec)[ix]; } | ||||
1453 | |||||
1454 | bool operator!=(const vec &other) const | ||||
1455 | { return !(*this == other); } | ||||
1456 | |||||
1457 | bool operator==(const vec &other) const | ||||
1458 | { return address () == other.address (); } | ||||
1459 | |||||
1460 | T &operator[] (unsigned ix) | ||||
1461 | { return (*m_vec)[ix]; } | ||||
1462 | |||||
1463 | T &last (void) | ||||
1464 | { return m_vec->last (); } | ||||
1465 | |||||
1466 | bool space (int nelems) const | ||||
1467 | { return m_vec ? m_vec->space (nelems) : nelems == 0; } | ||||
1468 | |||||
1469 | bool iterate (unsigned ix, T *p) const; | ||||
1470 | bool iterate (unsigned ix, T **p) const; | ||||
1471 | vec copy (ALONE_CXX_MEM_STAT_INFO) const; | ||||
1472 | bool reserve (unsigned, bool = false CXX_MEM_STAT_INFO); | ||||
1473 | bool reserve_exact (unsigned CXX_MEM_STAT_INFO); | ||||
1474 | void splice (const vec &); | ||||
1475 | void safe_splice (const vec & CXX_MEM_STAT_INFO); | ||||
1476 | T *quick_push (const T &); | ||||
1477 | T *safe_push (const T &CXX_MEM_STAT_INFO); | ||||
1478 | T &pop (void); | ||||
1479 | void truncate (unsigned); | ||||
1480 | void safe_grow (unsigned, bool = false CXX_MEM_STAT_INFO); | ||||
1481 | void safe_grow_cleared (unsigned, bool = false CXX_MEM_STAT_INFO); | ||||
1482 | void quick_grow (unsigned); | ||||
1483 | void quick_grow_cleared (unsigned); | ||||
1484 | void quick_insert (unsigned, const T &); | ||||
1485 | void safe_insert (unsigned, const T & CXX_MEM_STAT_INFO); | ||||
1486 | void ordered_remove (unsigned); | ||||
1487 | void unordered_remove (unsigned); | ||||
1488 | void block_remove (unsigned, unsigned); | ||||
1489 | void qsort (int (*) (const void *, const void *))qsort (int (*) (const void *, const void *)); | ||||
1490 | void sort (int (*) (const void *, const void *, void *), void *); | ||||
1491 | T *bsearch (const void *key, int (*compar)(const void *, const void *)); | ||||
1492 | T *bsearch (const void *key, | ||||
1493 | int (*compar)(const void *, const void *, void *), void *); | ||||
1494 | unsigned lower_bound (T, bool (*)(const T &, const T &)) const; | ||||
1495 | bool contains (const T &search) const; | ||||
1496 | void reverse (void); | ||||
1497 | |||||
1498 | bool using_auto_storage () const; | ||||
1499 | |||||
1500 | /* FIXME - This field should be private, but we need to cater to | ||||
1501 | compilers that have stricter notions of PODness for types. */ | ||||
1502 | vec<T, va_heap, vl_embed> *m_vec; | ||||
1503 | }; | ||||
1504 | |||||
1505 | |||||
1506 | /* auto_vec is a subclass of vec that automatically manages creating and | ||||
1507 | releasing the internal vector. If N is non zero then it has N elements of | ||||
1508 | internal storage. The default is no internal storage, and you probably only | ||||
1509 | want to ask for internal storage for vectors on the stack because if the | ||||
1510 | size of the vector is larger than the internal storage that space is wasted. | ||||
1511 | */ | ||||
1512 | template<typename T, size_t N = 0> | ||||
1513 | class auto_vec : public vec<T, va_heap> | ||||
1514 | { | ||||
1515 | public: | ||||
1516 | auto_vec () | ||||
1517 | { | ||||
1518 | m_auto.embedded_init (MAX (N, 2)((N) > (2) ? (N) : (2)), 0, 1); | ||||
1519 | this->m_vec = &m_auto; | ||||
1520 | } | ||||
1521 | |||||
1522 | auto_vec (size_t s) | ||||
1523 | { | ||||
1524 | if (s > N) | ||||
1525 | { | ||||
1526 | this->create (s); | ||||
1527 | return; | ||||
1528 | } | ||||
1529 | |||||
1530 | m_auto.embedded_init (MAX (N, 2)((N) > (2) ? (N) : (2)), 0, 1); | ||||
1531 | this->m_vec = &m_auto; | ||||
1532 | } | ||||
1533 | |||||
1534 | ~auto_vec () | ||||
1535 | { | ||||
1536 | this->release (); | ||||
1537 | } | ||||
1538 | |||||
1539 | private: | ||||
1540 | vec<T, va_heap, vl_embed> m_auto; | ||||
1541 | T m_data[MAX (N - 1, 1)((N - 1) > (1) ? (N - 1) : (1))]; | ||||
1542 | }; | ||||
1543 | |||||
1544 | /* auto_vec is a sub class of vec whose storage is released when it is | ||||
1545 | destroyed. */ | ||||
1546 | template<typename T> | ||||
1547 | class auto_vec<T, 0> : public vec<T, va_heap> | ||||
1548 | { | ||||
1549 | public: | ||||
1550 | auto_vec () { this->m_vec = NULLnullptr; } | ||||
1551 | auto_vec (size_t n) { this->create (n); } | ||||
1552 | ~auto_vec () { this->release (); } | ||||
1553 | |||||
1554 | auto_vec (vec<T, va_heap>&& r) | ||||
1555 | { | ||||
1556 | gcc_assert (!r.using_auto_storage ())((void)(!(!r.using_auto_storage ()) ? fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/vec.h" , 1556, __FUNCTION__), 0 : 0)); | ||||
1557 | this->m_vec = r.m_vec; | ||||
1558 | r.m_vec = NULLnullptr; | ||||
1559 | } | ||||
1560 | auto_vec& operator= (vec<T, va_heap>&& r) | ||||
1561 | { | ||||
1562 | gcc_assert (!r.using_auto_storage ())((void)(!(!r.using_auto_storage ()) ? fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/vec.h" , 1562, __FUNCTION__), 0 : 0)); | ||||
1563 | this->release (); | ||||
1564 | this->m_vec = r.m_vec; | ||||
1565 | r.m_vec = NULLnullptr; | ||||
1566 | return *this; | ||||
1567 | } | ||||
1568 | }; | ||||
1569 | |||||
1570 | |||||
1571 | /* Allocate heap memory for pointer V and create the internal vector | ||||
1572 | with space for NELEMS elements. If NELEMS is 0, the internal | ||||
1573 | vector is initialized to empty. */ | ||||
1574 | |||||
1575 | template<typename T> | ||||
1576 | inline void | ||||
1577 | vec_alloc (vec<T> *&v, unsigned nelems CXX_MEM_STAT_INFO) | ||||
1578 | { | ||||
1579 | v = new vec<T>; | ||||
1580 | v->create (nelems PASS_MEM_STAT); | ||||
1581 | } | ||||
1582 | |||||
1583 | |||||
1584 | /* A subclass of auto_vec <char *> that frees all of its elements on | ||||
1585 | deletion. */ | ||||
1586 | |||||
1587 | class auto_string_vec : public auto_vec <char *> | ||||
1588 | { | ||||
1589 | public: | ||||
1590 | ~auto_string_vec (); | ||||
1591 | }; | ||||
1592 | |||||
1593 | /* A subclass of auto_vec <T *> that deletes all of its elements on | ||||
1594 | destruction. | ||||
1595 | |||||
1596 | This is a crude way for a vec to "own" the objects it points to | ||||
1597 | and clean up automatically. | ||||
1598 | |||||
1599 | For example, no attempt is made to delete elements when an item | ||||
1600 | within the vec is overwritten. | ||||
1601 | |||||
1602 | We can't rely on gnu::unique_ptr within a container, | ||||
1603 | since we can't rely on move semantics in C++98. */ | ||||
1604 | |||||
1605 | template <typename T> | ||||
1606 | class auto_delete_vec : public auto_vec <T *> | ||||
1607 | { | ||||
1608 | public: | ||||
1609 | auto_delete_vec () {} | ||||
1610 | auto_delete_vec (size_t s) : auto_vec <T *> (s) {} | ||||
1611 | |||||
1612 | ~auto_delete_vec (); | ||||
1613 | |||||
1614 | private: | ||||
1615 | DISABLE_COPY_AND_ASSIGN(auto_delete_vec)auto_delete_vec (const auto_delete_vec&) = delete; void operator = (const auto_delete_vec &) = delete; | ||||
1616 | }; | ||||
1617 | |||||
1618 | /* Conditionally allocate heap memory for VEC and its internal vector. */ | ||||
1619 | |||||
1620 | template<typename T> | ||||
1621 | inline void | ||||
1622 | vec_check_alloc (vec<T, va_heap> *&vec, unsigned nelems CXX_MEM_STAT_INFO) | ||||
1623 | { | ||||
1624 | if (!vec) | ||||
1625 | vec_alloc (vec, nelems PASS_MEM_STAT); | ||||
1626 | } | ||||
1627 | |||||
1628 | |||||
1629 | /* Free the heap memory allocated by vector V and set it to NULL. */ | ||||
1630 | |||||
1631 | template<typename T> | ||||
1632 | inline void | ||||
1633 | vec_free (vec<T> *&v) | ||||
1634 | { | ||||
1635 | if (v == NULLnullptr) | ||||
1636 | return; | ||||
1637 | |||||
1638 | v->release (); | ||||
1639 | delete v; | ||||
1640 | v = NULLnullptr; | ||||
1641 | } | ||||
1642 | |||||
1643 | |||||
1644 | /* Return iteration condition and update PTR to point to the IX'th | ||||
1645 | element of this vector. Use this to iterate over the elements of a | ||||
1646 | vector as follows, | ||||
1647 | |||||
1648 | for (ix = 0; v.iterate (ix, &ptr); ix++) | ||||
1649 | continue; */ | ||||
1650 | |||||
1651 | template<typename T> | ||||
1652 | inline bool | ||||
1653 | vec<T, va_heap, vl_ptr>::iterate (unsigned ix, T *ptr) const | ||||
1654 | { | ||||
1655 | if (m_vec) | ||||
1656 | return m_vec->iterate (ix, ptr); | ||||
1657 | else | ||||
1658 | { | ||||
1659 | *ptr = 0; | ||||
1660 | return false; | ||||
1661 | } | ||||
1662 | } | ||||
1663 | |||||
1664 | |||||
1665 | /* Return iteration condition and update *PTR to point to the | ||||
1666 | IX'th element of this vector. Use this to iterate over the | ||||
1667 | elements of a vector as follows, | ||||
1668 | |||||
1669 | for (ix = 0; v->iterate (ix, &ptr); ix++) | ||||
1670 | continue; | ||||
1671 | |||||
1672 | This variant is for vectors of objects. */ | ||||
1673 | |||||
1674 | template<typename T> | ||||
1675 | inline bool | ||||
1676 | vec<T, va_heap, vl_ptr>::iterate (unsigned ix, T **ptr) const | ||||
1677 | { | ||||
1678 | if (m_vec) | ||||
1679 | return m_vec->iterate (ix, ptr); | ||||
1680 | else | ||||
1681 | { | ||||
1682 | *ptr = 0; | ||||
1683 | return false; | ||||
1684 | } | ||||
1685 | } | ||||
1686 | |||||
1687 | |||||
1688 | /* Convenience macro for forward iteration. */ | ||||
1689 | #define FOR_EACH_VEC_ELT(V, I, P)for (I = 0; (V).iterate ((I), &(P)); ++(I)) \ | ||||
1690 | for (I = 0; (V).iterate ((I), &(P)); ++(I)) | ||||
1691 | |||||
1692 | #define FOR_EACH_VEC_SAFE_ELT(V, I, P)for (I = 0; vec_safe_iterate ((V), (I), &(P)); ++(I)) \ | ||||
1693 | for (I = 0; vec_safe_iterate ((V), (I), &(P)); ++(I)) | ||||
1694 | |||||
1695 | /* Likewise, but start from FROM rather than 0. */ | ||||
1696 | #define FOR_EACH_VEC_ELT_FROM(V, I, P, FROM)for (I = (FROM); (V).iterate ((I), &(P)); ++(I)) \ | ||||
1697 | for (I = (FROM); (V).iterate ((I), &(P)); ++(I)) | ||||
1698 | |||||
1699 | /* Convenience macro for reverse iteration. */ | ||||
1700 | #define FOR_EACH_VEC_ELT_REVERSE(V, I, P)for (I = (V).length () - 1; (V).iterate ((I), &(P)); (I)-- ) \ | ||||
1701 | for (I = (V).length () - 1; \ | ||||
1702 | (V).iterate ((I), &(P)); \ | ||||
1703 | (I)--) | ||||
1704 | |||||
1705 | #define FOR_EACH_VEC_SAFE_ELT_REVERSE(V, I, P)for (I = vec_safe_length (V) - 1; vec_safe_iterate ((V), (I), &(P)); (I)--) \ | ||||
1706 | for (I = vec_safe_length (V) - 1; \ | ||||
1707 | vec_safe_iterate ((V), (I), &(P)); \ | ||||
1708 | (I)--) | ||||
1709 | |||||
1710 | /* auto_string_vec's dtor, freeing all contained strings, automatically | ||||
1711 | chaining up to ~auto_vec <char *>, which frees the internal buffer. */ | ||||
1712 | |||||
1713 | inline | ||||
1714 | auto_string_vec::~auto_string_vec () | ||||
1715 | { | ||||
1716 | int i; | ||||
1717 | char *str; | ||||
1718 | FOR_EACH_VEC_ELT (*this, i, str)for (i = 0; (*this).iterate ((i), &(str)); ++(i)) | ||||
1719 | free (str); | ||||
1720 | } | ||||
1721 | |||||
1722 | /* auto_delete_vec's dtor, deleting all contained items, automatically | ||||
1723 | chaining up to ~auto_vec <T*>, which frees the internal buffer. */ | ||||
1724 | |||||
1725 | template <typename T> | ||||
1726 | inline | ||||
1727 | auto_delete_vec<T>::~auto_delete_vec () | ||||
1728 | { | ||||
1729 | int i; | ||||
1730 | T *item; | ||||
1731 | FOR_EACH_VEC_ELT (*this, i, item)for (i = 0; (*this).iterate ((i), &(item)); ++(i)) | ||||
1732 | delete item; | ||||
1733 | } | ||||
1734 | |||||
1735 | |||||
1736 | /* Return a copy of this vector. */ | ||||
1737 | |||||
1738 | template<typename T> | ||||
1739 | inline vec<T, va_heap, vl_ptr> | ||||
1740 | vec<T, va_heap, vl_ptr>::copy (ALONE_MEM_STAT_DECLvoid) const | ||||
1741 | { | ||||
1742 | vec<T, va_heap, vl_ptr> new_vec = vNULL; | ||||
1743 | if (length ()) | ||||
1744 | new_vec.m_vec = m_vec->copy (ALONE_PASS_MEM_STAT); | ||||
1745 | return new_vec; | ||||
1746 | } | ||||
1747 | |||||
1748 | |||||
1749 | /* Ensure that the vector has at least RESERVE slots available (if | ||||
1750 | EXACT is false), or exactly RESERVE slots available (if EXACT is | ||||
1751 | true). | ||||
1752 | |||||
1753 | This may create additional headroom if EXACT is false. | ||||
1754 | |||||
1755 | Note that this can cause the embedded vector to be reallocated. | ||||
1756 | Returns true iff reallocation actually occurred. */ | ||||
1757 | |||||
1758 | template<typename T> | ||||
1759 | inline bool | ||||
1760 | vec<T, va_heap, vl_ptr>::reserve (unsigned nelems, bool exact MEM_STAT_DECL) | ||||
1761 | { | ||||
1762 | if (space (nelems)) | ||||
1763 | return false; | ||||
1764 | |||||
1765 | /* For now play a game with va_heap::reserve to hide our auto storage if any, | ||||
1766 | this is necessary because it doesn't have enough information to know the | ||||
1767 | embedded vector is in auto storage, and so should not be freed. */ | ||||
1768 | vec<T, va_heap, vl_embed> *oldvec = m_vec; | ||||
1769 | unsigned int oldsize = 0; | ||||
1770 | bool handle_auto_vec = m_vec && using_auto_storage (); | ||||
1771 | if (handle_auto_vec) | ||||
1772 | { | ||||
1773 | m_vec = NULLnullptr; | ||||
1774 | oldsize = oldvec->length (); | ||||
1775 | nelems += oldsize; | ||||
1776 | } | ||||
1777 | |||||
1778 | va_heap::reserve (m_vec, nelems, exact PASS_MEM_STAT); | ||||
1779 | if (handle_auto_vec) | ||||
1780 | { | ||||
1781 | vec_copy_construct (m_vec->address (), oldvec->address (), oldsize); | ||||
1782 | m_vec->m_vecpfx.m_num = oldsize; | ||||
1783 | } | ||||
1784 | |||||
1785 | return true; | ||||
1786 | } | ||||
1787 | |||||
1788 | |||||
1789 | /* Ensure that this vector has exactly NELEMS slots available. This | ||||
1790 | will not create additional headroom. Note this can cause the | ||||
1791 | embedded vector to be reallocated. Returns true iff reallocation | ||||
1792 | actually occurred. */ | ||||
1793 | |||||
1794 | template<typename T> | ||||
1795 | inline bool | ||||
1796 | vec<T, va_heap, vl_ptr>::reserve_exact (unsigned nelems MEM_STAT_DECL) | ||||
1797 | { | ||||
1798 | return reserve (nelems, true PASS_MEM_STAT); | ||||
1799 | } | ||||
1800 | |||||
1801 | |||||
1802 | /* Create the internal vector and reserve NELEMS for it. This is | ||||
1803 | exactly like vec::reserve, but the internal vector is | ||||
1804 | unconditionally allocated from scratch. The old one, if it | ||||
1805 | existed, is lost. */ | ||||
1806 | |||||
1807 | template<typename T> | ||||
1808 | inline void | ||||
1809 | vec<T, va_heap, vl_ptr>::create (unsigned nelems MEM_STAT_DECL) | ||||
1810 | { | ||||
1811 | m_vec = NULLnullptr; | ||||
1812 | if (nelems > 0) | ||||
1813 | reserve_exact (nelems PASS_MEM_STAT); | ||||
1814 | } | ||||
1815 | |||||
1816 | |||||
1817 | /* Free the memory occupied by the embedded vector. */ | ||||
1818 | |||||
1819 | template<typename T> | ||||
1820 | inline void | ||||
1821 | vec<T, va_heap, vl_ptr>::release (void) | ||||
1822 | { | ||||
1823 | if (!m_vec) | ||||
1824 | return; | ||||
1825 | |||||
1826 | if (using_auto_storage ()) | ||||
1827 | { | ||||
1828 | m_vec->m_vecpfx.m_num = 0; | ||||
1829 | return; | ||||
1830 | } | ||||
1831 | |||||
1832 | va_heap::release (m_vec); | ||||
1833 | } | ||||
1834 | |||||
1835 | /* Copy the elements from SRC to the end of this vector as if by memcpy. | ||||
1836 | SRC and this vector must be allocated with the same memory | ||||
1837 | allocation mechanism. This vector is assumed to have sufficient | ||||
1838 | headroom available. */ | ||||
1839 | |||||
1840 | template<typename T> | ||||
1841 | inline void | ||||
1842 | vec<T, va_heap, vl_ptr>::splice (const vec<T, va_heap, vl_ptr> &src) | ||||
1843 | { | ||||
1844 | if (src.length ()) | ||||
1845 | m_vec->splice (*(src.m_vec)); | ||||
1846 | } | ||||
1847 | |||||
1848 | |||||
1849 | /* Copy the elements in SRC to the end of this vector as if by memcpy. | ||||
1850 | SRC and this vector must be allocated with the same mechanism. | ||||
1851 | If there is not enough headroom in this vector, it will be reallocated | ||||
1852 | as needed. */ | ||||
1853 | |||||
1854 | template<typename T> | ||||
1855 | inline void | ||||
1856 | vec<T, va_heap, vl_ptr>::safe_splice (const vec<T, va_heap, vl_ptr> &src | ||||
1857 | MEM_STAT_DECL) | ||||
1858 | { | ||||
1859 | if (src.length ()) | ||||
1860 | { | ||||
1861 | reserve_exact (src.length ()); | ||||
1862 | splice (src); | ||||
1863 | } | ||||
1864 | } | ||||
1865 | |||||
1866 | |||||
1867 | /* Push OBJ (a new element) onto the end of the vector. There must be | ||||
1868 | sufficient space in the vector. Return a pointer to the slot | ||||
1869 | where OBJ was inserted. */ | ||||
1870 | |||||
1871 | template<typename T> | ||||
1872 | inline T * | ||||
1873 | vec<T, va_heap, vl_ptr>::quick_push (const T &obj) | ||||
1874 | { | ||||
1875 | return m_vec->quick_push (obj); | ||||
1876 | } | ||||
1877 | |||||
1878 | |||||
1879 | /* Push a new element OBJ onto the end of this vector. Reallocates | ||||
1880 | the embedded vector, if needed. Return a pointer to the slot where | ||||
1881 | OBJ was inserted. */ | ||||
1882 | |||||
1883 | template<typename T> | ||||
1884 | inline T * | ||||
1885 | vec<T, va_heap, vl_ptr>::safe_push (const T &obj MEM_STAT_DECL) | ||||
1886 | { | ||||
1887 | reserve (1, false PASS_MEM_STAT); | ||||
1888 | return quick_push (obj); | ||||
1889 | } | ||||
1890 | |||||
1891 | |||||
1892 | /* Pop and return the last element off the end of the vector. */ | ||||
1893 | |||||
1894 | template<typename T> | ||||
1895 | inline T & | ||||
1896 | vec<T, va_heap, vl_ptr>::pop (void) | ||||
1897 | { | ||||
1898 | return m_vec->pop (); | ||||
1899 | } | ||||
1900 | |||||
1901 | |||||
1902 | /* Set the length of the vector to LEN. The new length must be less | ||||
1903 | than or equal to the current length. This is an O(1) operation. */ | ||||
1904 | |||||
1905 | template<typename T> | ||||
1906 | inline void | ||||
1907 | vec<T, va_heap, vl_ptr>::truncate (unsigned size) | ||||
1908 | { | ||||
1909 | if (m_vec) | ||||
1910 | m_vec->truncate (size); | ||||
1911 | else | ||||
1912 | gcc_checking_assert (size == 0)((void)(!(size == 0) ? fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/vec.h" , 1912, __FUNCTION__), 0 : 0)); | ||||
1913 | } | ||||
1914 | |||||
1915 | |||||
1916 | /* Grow the vector to a specific length. LEN must be as long or | ||||
1917 | longer than the current length. The new elements are | ||||
1918 | uninitialized. Reallocate the internal vector, if needed. */ | ||||
1919 | |||||
1920 | template<typename T> | ||||
1921 | inline void | ||||
1922 | vec<T, va_heap, vl_ptr>::safe_grow (unsigned len, bool exact MEM_STAT_DECL) | ||||
1923 | { | ||||
1924 | unsigned oldlen = length (); | ||||
1925 | gcc_checking_assert (oldlen <= len)((void)(!(oldlen <= len) ? fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/vec.h" , 1925, __FUNCTION__), 0 : 0)); | ||||
1926 | reserve (len - oldlen, exact PASS_MEM_STAT); | ||||
1927 | if (m_vec) | ||||
1928 | m_vec->quick_grow (len); | ||||
1929 | else | ||||
1930 | gcc_checking_assert (len == 0)((void)(!(len == 0) ? fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/vec.h" , 1930, __FUNCTION__), 0 : 0)); | ||||
1931 | } | ||||
1932 | |||||
1933 | |||||
1934 | /* Grow the embedded vector to a specific length. LEN must be as | ||||
1935 | long or longer than the current length. The new elements are | ||||
1936 | initialized to zero. Reallocate the internal vector, if needed. */ | ||||
1937 | |||||
1938 | template<typename T> | ||||
1939 | inline void | ||||
1940 | vec<T, va_heap, vl_ptr>::safe_grow_cleared (unsigned len, bool exact | ||||
1941 | MEM_STAT_DECL) | ||||
1942 | { | ||||
1943 | unsigned oldlen = length (); | ||||
1944 | size_t growby = len - oldlen; | ||||
1945 | safe_grow (len, exact PASS_MEM_STAT); | ||||
1946 | if (growby != 0) | ||||
1947 | vec_default_construct (address () + oldlen, growby); | ||||
1948 | } | ||||
1949 | |||||
1950 | |||||
1951 | /* Same as vec::safe_grow but without reallocation of the internal vector. | ||||
1952 | If the vector cannot be extended, a runtime assertion will be triggered. */ | ||||
1953 | |||||
1954 | template<typename T> | ||||
1955 | inline void | ||||
1956 | vec<T, va_heap, vl_ptr>::quick_grow (unsigned len) | ||||
1957 | { | ||||
1958 | gcc_checking_assert (m_vec)((void)(!(m_vec) ? fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/vec.h" , 1958, __FUNCTION__), 0 : 0)); | ||||
1959 | m_vec->quick_grow (len); | ||||
1960 | } | ||||
1961 | |||||
1962 | |||||
1963 | /* Same as vec::quick_grow_cleared but without reallocation of the | ||||
1964 | internal vector. If the vector cannot be extended, a runtime | ||||
1965 | assertion will be triggered. */ | ||||
1966 | |||||
1967 | template<typename T> | ||||
1968 | inline void | ||||
1969 | vec<T, va_heap, vl_ptr>::quick_grow_cleared (unsigned len) | ||||
1970 | { | ||||
1971 | gcc_checking_assert (m_vec)((void)(!(m_vec) ? fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/vec.h" , 1971, __FUNCTION__), 0 : 0)); | ||||
1972 | m_vec->quick_grow_cleared (len); | ||||
1973 | } | ||||
1974 | |||||
1975 | |||||
1976 | /* Insert an element, OBJ, at the IXth position of this vector. There | ||||
1977 | must be sufficient space. */ | ||||
1978 | |||||
1979 | template<typename T> | ||||
1980 | inline void | ||||
1981 | vec<T, va_heap, vl_ptr>::quick_insert (unsigned ix, const T &obj) | ||||
1982 | { | ||||
1983 | m_vec->quick_insert (ix, obj); | ||||
1984 | } | ||||
1985 | |||||
1986 | |||||
1987 | /* Insert an element, OBJ, at the IXth position of the vector. | ||||
1988 | Reallocate the embedded vector, if necessary. */ | ||||
1989 | |||||
1990 | template<typename T> | ||||
1991 | inline void | ||||
1992 | vec<T, va_heap, vl_ptr>::safe_insert (unsigned ix, const T &obj MEM_STAT_DECL) | ||||
1993 | { | ||||
1994 | reserve (1, false PASS_MEM_STAT); | ||||
1995 | quick_insert (ix, obj); | ||||
1996 | } | ||||
1997 | |||||
1998 | |||||
1999 | /* Remove an element from the IXth position of this vector. Ordering of | ||||
2000 | remaining elements is preserved. This is an O(N) operation due to | ||||
2001 | a memmove. */ | ||||
2002 | |||||
2003 | template<typename T> | ||||
2004 | inline void | ||||
2005 | vec<T, va_heap, vl_ptr>::ordered_remove (unsigned ix) | ||||
2006 | { | ||||
2007 | m_vec->ordered_remove (ix); | ||||
2008 | } | ||||
2009 | |||||
2010 | |||||
2011 | /* Remove an element from the IXth position of this vector. Ordering | ||||
2012 | of remaining elements is destroyed. This is an O(1) operation. */ | ||||
2013 | |||||
2014 | template<typename T> | ||||
2015 | inline void | ||||
2016 | vec<T, va_heap, vl_ptr>::unordered_remove (unsigned ix) | ||||
2017 | { | ||||
2018 | m_vec->unordered_remove (ix); | ||||
2019 | } | ||||
2020 | |||||
2021 | |||||
2022 | /* Remove LEN elements starting at the IXth. Ordering is retained. | ||||
2023 | This is an O(N) operation due to memmove. */ | ||||
2024 | |||||
2025 | template<typename T> | ||||
2026 | inline void | ||||
2027 | vec<T, va_heap, vl_ptr>::block_remove (unsigned ix, unsigned len) | ||||
2028 | { | ||||
2029 | m_vec->block_remove (ix, len); | ||||
2030 | } | ||||
2031 | |||||
2032 | |||||
2033 | /* Sort the contents of this vector with qsort. CMP is the comparison | ||||
2034 | function to pass to qsort. */ | ||||
2035 | |||||
2036 | template<typename T> | ||||
2037 | inline void | ||||
2038 | vec<T, va_heap, vl_ptr>::qsort (int (*cmp) (const void *, const void *))qsort (int (*cmp) (const void *, const void *)) | ||||
2039 | { | ||||
2040 | if (m_vec) | ||||
2041 | m_vec->qsort (cmp)qsort (cmp); | ||||
2042 | } | ||||
2043 | |||||
2044 | /* Sort the contents of this vector with qsort. CMP is the comparison | ||||
2045 | function to pass to qsort. */ | ||||
2046 | |||||
2047 | template<typename T> | ||||
2048 | inline void | ||||
2049 | vec<T, va_heap, vl_ptr>::sort (int (*cmp) (const void *, const void *, | ||||
2050 | void *), void *data) | ||||
2051 | { | ||||
2052 | if (m_vec) | ||||
2053 | m_vec->sort (cmp, data); | ||||
2054 | } | ||||
2055 | |||||
2056 | |||||
2057 | /* Search the contents of the sorted vector with a binary search. | ||||
2058 | CMP is the comparison function to pass to bsearch. */ | ||||
2059 | |||||
2060 | template<typename T> | ||||
2061 | inline T * | ||||
2062 | vec<T, va_heap, vl_ptr>::bsearch (const void *key, | ||||
2063 | int (*cmp) (const void *, const void *)) | ||||
2064 | { | ||||
2065 | if (m_vec) | ||||
2066 | return m_vec->bsearch (key, cmp); | ||||
2067 | return NULLnullptr; | ||||
2068 | } | ||||
2069 | |||||
2070 | /* Search the contents of the sorted vector with a binary search. | ||||
2071 | CMP is the comparison function to pass to bsearch. */ | ||||
2072 | |||||
2073 | template<typename T> | ||||
2074 | inline T * | ||||
2075 | vec<T, va_heap, vl_ptr>::bsearch (const void *key, | ||||
2076 | int (*cmp) (const void *, const void *, | ||||
2077 | void *), void *data) | ||||
2078 | { | ||||
2079 | if (m_vec) | ||||
2080 | return m_vec->bsearch (key, cmp, data); | ||||
2081 | return NULLnullptr; | ||||
2082 | } | ||||
2083 | |||||
2084 | |||||
2085 | /* Find and return the first position in which OBJ could be inserted | ||||
2086 | without changing the ordering of this vector. LESSTHAN is a | ||||
2087 | function that returns true if the first argument is strictly less | ||||
2088 | than the second. */ | ||||
2089 | |||||
2090 | template<typename T> | ||||
2091 | inline unsigned | ||||
2092 | vec<T, va_heap, vl_ptr>::lower_bound (T obj, | ||||
2093 | bool (*lessthan)(const T &, const T &)) | ||||
2094 | const | ||||
2095 | { | ||||
2096 | return m_vec ? m_vec->lower_bound (obj, lessthan) : 0; | ||||
2097 | } | ||||
2098 | |||||
2099 | /* Return true if SEARCH is an element of V. Note that this is O(N) in the | ||||
2100 | size of the vector and so should be used with care. */ | ||||
2101 | |||||
2102 | template<typename T> | ||||
2103 | inline bool | ||||
2104 | vec<T, va_heap, vl_ptr>::contains (const T &search) const | ||||
2105 | { | ||||
2106 | return m_vec ? m_vec->contains (search) : false; | ||||
2107 | } | ||||
2108 | |||||
2109 | /* Reverse content of the vector. */ | ||||
2110 | |||||
2111 | template<typename T> | ||||
2112 | inline void | ||||
2113 | vec<T, va_heap, vl_ptr>::reverse (void) | ||||
2114 | { | ||||
2115 | unsigned l = length (); | ||||
2116 | T *ptr = address (); | ||||
2117 | |||||
2118 | for (unsigned i = 0; i < l / 2; i++) | ||||
2119 | std::swap (ptr[i], ptr[l - i - 1]); | ||||
2120 | } | ||||
2121 | |||||
2122 | template<typename T> | ||||
2123 | inline bool | ||||
2124 | vec<T, va_heap, vl_ptr>::using_auto_storage () const | ||||
2125 | { | ||||
2126 | return m_vec->m_vecpfx.m_using_auto_storage; | ||||
2127 | } | ||||
2128 | |||||
2129 | /* Release VEC and call release of all element vectors. */ | ||||
2130 | |||||
2131 | template<typename T> | ||||
2132 | inline void | ||||
2133 | release_vec_vec (vec<vec<T> > &vec) | ||||
2134 | { | ||||
2135 | for (unsigned i = 0; i < vec.length (); i++) | ||||
2136 | vec[i].release (); | ||||
2137 | |||||
2138 | vec.release (); | ||||
2139 | } | ||||
2140 | |||||
2141 | // Provide a subset of the std::span functionality. (We can't use std::span | ||||
2142 | // itself because it's a C++20 feature.) | ||||
2143 | // | ||||
2144 | // In addition, provide an invalid value that is distinct from all valid | ||||
2145 | // sequences (including the empty sequence). This can be used to return | ||||
2146 | // failure without having to use std::optional. | ||||
2147 | // | ||||
2148 | // There is no operator bool because it would be ambiguous whether it is | ||||
2149 | // testing for a valid value or an empty sequence. | ||||
2150 | template<typename T> | ||||
2151 | class array_slice | ||||
2152 | { | ||||
2153 | template<typename OtherT> friend class array_slice; | ||||
2154 | |||||
2155 | public: | ||||
2156 | using value_type = T; | ||||
2157 | using iterator = T *; | ||||
2158 | using const_iterator = const T *; | ||||
2159 | |||||
2160 | array_slice () : m_base (nullptr), m_size (0) {} | ||||
2161 | |||||
2162 | template<typename OtherT> | ||||
2163 | array_slice (array_slice<OtherT> other) | ||||
2164 | : m_base (other.m_base), m_size (other.m_size) {} | ||||
2165 | |||||
2166 | array_slice (iterator base, unsigned int size) | ||||
2167 | : m_base (base), m_size (size) {} | ||||
2168 | |||||
2169 | template<size_t N> | ||||
2170 | array_slice (T (&array)[N]) : m_base (array), m_size (N) {} | ||||
2171 | |||||
2172 | template<typename OtherT> | ||||
2173 | array_slice (const vec<OtherT> &v) | ||||
2174 | : m_base (v.address ()), m_size (v.length ()) {} | ||||
2175 | |||||
2176 | iterator begin () { return m_base; } | ||||
2177 | iterator end () { return m_base + m_size; } | ||||
2178 | |||||
2179 | const_iterator begin () const { return m_base; } | ||||
2180 | const_iterator end () const { return m_base + m_size; } | ||||
2181 | |||||
2182 | value_type &front (); | ||||
2183 | value_type &back (); | ||||
2184 | value_type &operator[] (unsigned int i); | ||||
2185 | |||||
2186 | const value_type &front () const; | ||||
2187 | const value_type &back () const; | ||||
2188 | const value_type &operator[] (unsigned int i) const; | ||||
2189 | |||||
2190 | size_t size () const { return m_size; } | ||||
2191 | size_t size_bytes () const { return m_size * sizeof (T); } | ||||
2192 | bool empty () const { return m_size == 0; } | ||||
2193 | |||||
2194 | // An invalid array_slice that represents a failed operation. This is | ||||
2195 | // distinct from an empty slice, which is a valid result in some contexts. | ||||
2196 | static array_slice invalid () { return { nullptr, ~0U }; } | ||||
2197 | |||||
2198 | // True if the array is valid, false if it is an array like INVALID. | ||||
2199 | bool is_valid () const { return m_base || m_size == 0; } | ||||
2200 | |||||
2201 | private: | ||||
2202 | iterator m_base; | ||||
2203 | unsigned int m_size; | ||||
2204 | }; | ||||
2205 | |||||
2206 | template<typename T> | ||||
2207 | inline typename array_slice<T>::value_type & | ||||
2208 | array_slice<T>::front () | ||||
2209 | { | ||||
2210 | gcc_checking_assert (m_size)((void)(!(m_size) ? fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/vec.h" , 2210, __FUNCTION__), 0 : 0)); | ||||
2211 | return m_base[0]; | ||||
2212 | } | ||||
2213 | |||||
2214 | template<typename T> | ||||
2215 | inline const typename array_slice<T>::value_type & | ||||
2216 | array_slice<T>::front () const | ||||
2217 | { | ||||
2218 | gcc_checking_assert (m_size)((void)(!(m_size) ? fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/vec.h" , 2218, __FUNCTION__), 0 : 0)); | ||||
2219 | return m_base[0]; | ||||
2220 | } | ||||
2221 | |||||
2222 | template<typename T> | ||||
2223 | inline typename array_slice<T>::value_type & | ||||
2224 | array_slice<T>::back () | ||||
2225 | { | ||||
2226 | gcc_checking_assert (m_size)((void)(!(m_size) ? fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/vec.h" , 2226, __FUNCTION__), 0 : 0)); | ||||
2227 | return m_base[m_size - 1]; | ||||
2228 | } | ||||
2229 | |||||
2230 | template<typename T> | ||||
2231 | inline const typename array_slice<T>::value_type & | ||||
2232 | array_slice<T>::back () const | ||||
2233 | { | ||||
2234 | gcc_checking_assert (m_size)((void)(!(m_size) ? fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/vec.h" , 2234, __FUNCTION__), 0 : 0)); | ||||
2235 | return m_base[m_size - 1]; | ||||
2236 | } | ||||
2237 | |||||
2238 | template<typename T> | ||||
2239 | inline typename array_slice<T>::value_type & | ||||
2240 | array_slice<T>::operator[] (unsigned int i) | ||||
2241 | { | ||||
2242 | gcc_checking_assert (i < m_size)((void)(!(i < m_size) ? fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/vec.h" , 2242, __FUNCTION__), 0 : 0)); | ||||
2243 | return m_base[i]; | ||||
2244 | } | ||||
2245 | |||||
2246 | template<typename T> | ||||
2247 | inline const typename array_slice<T>::value_type & | ||||
2248 | array_slice<T>::operator[] (unsigned int i) const | ||||
2249 | { | ||||
2250 | gcc_checking_assert (i < m_size)((void)(!(i < m_size) ? fancy_abort ("/home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/vec.h" , 2250, __FUNCTION__), 0 : 0)); | ||||
2251 | return m_base[i]; | ||||
2252 | } | ||||
2253 | |||||
2254 | template<typename T> | ||||
2255 | array_slice<T> | ||||
2256 | make_array_slice (T *base, unsigned int size) | ||||
2257 | { | ||||
2258 | return array_slice<T> (base, size); | ||||
2259 | } | ||||
2260 | |||||
2261 | #if (GCC_VERSION(4 * 1000 + 2) >= 3000) | ||||
2262 | # pragma GCC poison m_vec m_vecpfx m_vecdata | ||||
2263 | #endif | ||||
2264 | |||||
2265 | #endif // GCC_VEC_H |