1 | /* Handle #pragma, system V.4 style. Supports #pragma weak and #pragma pack. |
2 | Copyright (C) 1992-2023 Free Software Foundation, Inc. |
3 | |
4 | This file is part of GCC. |
5 | |
6 | GCC is free software; you can redistribute it and/or modify it under |
7 | the terms of the GNU General Public License as published by the Free |
8 | Software Foundation; either version 3, or (at your option) any later |
9 | version. |
10 | |
11 | GCC is distributed in the hope that it will be useful, but WITHOUT ANY |
12 | WARRANTY; without even the implied warranty of MERCHANTABILITY or |
13 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
14 | for more details. |
15 | |
16 | You should have received a copy of the GNU General Public License |
17 | along with GCC; see the file COPYING3. If not see |
18 | <http://www.gnu.org/licenses/>. */ |
19 | |
20 | #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) \ |
39 | do { warning (OPT_Wpragmas, gmsgid); return; } while (0) |
40 | #define GCC_BAD2(gmsgid, arg) \ |
41 | do { warning (OPT_Wpragmas, gmsgid, arg); return; } while (0) |
42 | #define GCC_BAD_AT(loc, gmsgid) \ |
43 | do { warning_at (loc, OPT_Wpragmas, gmsgid); return; } while (0) |
44 | #define GCC_BAD2_AT(loc, gmsgid, arg) \ |
45 | do { warning_at (loc, OPT_Wpragmas, gmsgid, arg); return; } while (0) |
46 | |
47 | struct GTY(()) align_stack { |
48 | int alignment; |
49 | tree id; |
50 | struct align_stack * prev; |
51 | }; |
52 | |
53 | static GTY(()) struct align_stack * alignment_stack; |
54 | |
55 | static void handle_pragma_pack (cpp_reader *); |
56 | |
57 | /* If we have a "global" #pragma pack(<n>) in effect when the first |
58 | #pragma pack(push,<n>) is encountered, this stores the value of |
59 | maximum_field_alignment in effect. When the final pop_alignment() |
60 | happens, we restore the value to this, not to a value of 0 for |
61 | maximum_field_alignment. Value is in bits. */ |
62 | static int default_alignment; |
63 | #define SET_GLOBAL_ALIGNMENT(ALIGN) (maximum_field_alignment = *(alignment_stack == NULL \ |
64 | ? &default_alignment \ |
65 | : &alignment_stack->alignment) = (ALIGN)) |
66 | |
67 | static void push_alignment (int, tree); |
68 | static void pop_alignment (tree); |
69 | |
70 | /* Push an alignment value onto the stack. */ |
71 | static void |
72 | push_alignment (int alignment, tree id) |
73 | { |
74 | align_stack * entry = ggc_alloc<align_stack> (); |
75 | |
76 | entry->alignment = alignment; |
77 | entry->id = id; |
78 | entry->prev = alignment_stack; |
79 | |
80 | /* The current value of maximum_field_alignment is not necessarily |
81 | 0 since there may be a #pragma pack(<n>) in effect; remember it |
82 | so that we can restore it after the final #pragma pop(). */ |
83 | if (alignment_stack == NULL) |
84 | default_alignment = maximum_field_alignment; |
85 | |
86 | alignment_stack = entry; |
87 | |
88 | maximum_field_alignment = alignment; |
89 | } |
90 | |
91 | /* Undo a push of an alignment onto the stack. */ |
92 | static void |
93 | pop_alignment (tree id) |
94 | { |
95 | align_stack * entry; |
96 | |
97 | if (alignment_stack == NULL) |
98 | GCC_BAD ("%<#pragma pack (pop)%> encountered without matching " |
99 | "%<#pragma pack (push)%>" ); |
100 | |
101 | /* If we got an identifier, strip away everything above the target |
102 | entry so that the next step will restore the state just below it. */ |
103 | if (id) |
104 | { |
105 | for (entry = alignment_stack; entry; entry = entry->prev) |
106 | if (entry->id == id) |
107 | { |
108 | alignment_stack = entry; |
109 | break; |
110 | } |
111 | if (entry == NULL) |
112 | warning (OPT_Wpragmas, |
113 | "%<#pragma pack(pop, %E)%> encountered without matching " |
114 | "%<#pragma pack(push, %E)%>" |
115 | , id, id); |
116 | } |
117 | |
118 | entry = alignment_stack->prev; |
119 | |
120 | maximum_field_alignment = entry ? entry->alignment : default_alignment; |
121 | |
122 | alignment_stack = entry; |
123 | } |
124 | |
125 | /* #pragma pack () |
126 | #pragma pack (N) |
127 | |
128 | #pragma pack (push) |
129 | #pragma pack (push, N) |
130 | #pragma pack (push, ID) |
131 | #pragma pack (push, ID, N) |
132 | #pragma pack (pop) |
133 | #pragma pack (pop, ID) */ |
134 | static void |
135 | handle_pragma_pack (cpp_reader *) |
136 | { |
137 | location_t loc; |
138 | tree x, id = 0; |
139 | int align = -1; |
140 | enum cpp_ttype token; |
141 | enum { set, push, pop } action; |
142 | |
143 | if (pragma_lex (&x) != CPP_OPEN_PAREN) |
144 | GCC_BAD ("missing %<(%> after %<#pragma pack%> - ignored" ); |
145 | |
146 | token = pragma_lex (&x, loc: &loc); |
147 | if (token == CPP_CLOSE_PAREN) |
148 | { |
149 | action = set; |
150 | align = initial_max_fld_align; |
151 | } |
152 | else if (token == CPP_NUMBER) |
153 | { |
154 | if (TREE_CODE (x) != INTEGER_CST) |
155 | GCC_BAD_AT (loc, "invalid constant in %<#pragma pack%> - ignored" ); |
156 | align = TREE_INT_CST_LOW (x); |
157 | action = set; |
158 | if (pragma_lex (&x) != CPP_CLOSE_PAREN) |
159 | GCC_BAD ("malformed %<#pragma pack%> - ignored" ); |
160 | } |
161 | else if (token == CPP_NAME) |
162 | { |
163 | #define GCC_BAD_ACTION do { if (action != pop) \ |
164 | GCC_BAD ("malformed %<#pragma pack(push[, id][, <n>])%> - ignored"); \ |
165 | else \ |
166 | GCC_BAD ("malformed %<#pragma pack(pop[, id])%> - ignored"); \ |
167 | } while (0) |
168 | |
169 | const char *op = IDENTIFIER_POINTER (x); |
170 | if (!strcmp (s1: op, s2: "push" )) |
171 | action = push; |
172 | else if (!strcmp (s1: op, s2: "pop" )) |
173 | action = pop; |
174 | else |
175 | GCC_BAD2_AT (loc, "unknown action %qE for %<#pragma pack%> - ignored" , |
176 | x); |
177 | |
178 | while ((token = pragma_lex (&x)) == CPP_COMMA) |
179 | { |
180 | token = pragma_lex (&x, loc: &loc); |
181 | if (token == CPP_NAME && id == 0) |
182 | { |
183 | id = x; |
184 | } |
185 | else if (token == CPP_NUMBER && action == push && align == -1) |
186 | { |
187 | if (TREE_CODE (x) != INTEGER_CST) |
188 | GCC_BAD_AT (loc, |
189 | "invalid constant in %<#pragma pack%> - ignored" ); |
190 | align = TREE_INT_CST_LOW (x); |
191 | if (align == -1) |
192 | action = set; |
193 | } |
194 | else |
195 | GCC_BAD_ACTION; |
196 | } |
197 | |
198 | if (token != CPP_CLOSE_PAREN) |
199 | GCC_BAD_ACTION; |
200 | #undef GCC_BAD_ACTION |
201 | } |
202 | else |
203 | GCC_BAD ("malformed %<#pragma pack%> - ignored" ); |
204 | |
205 | if (pragma_lex (&x, loc: &loc) != CPP_EOF) |
206 | warning_at (loc, OPT_Wpragmas, "junk at end of %<#pragma pack%>" ); |
207 | |
208 | if (flag_pack_struct) |
209 | GCC_BAD ("%<#pragma pack%> has no effect with %<-fpack-struct%> - ignored" ); |
210 | |
211 | if (action != pop) |
212 | switch (align) |
213 | { |
214 | case 0: |
215 | case 1: |
216 | case 2: |
217 | case 4: |
218 | case 8: |
219 | case 16: |
220 | align *= BITS_PER_UNIT; |
221 | break; |
222 | case -1: |
223 | if (action == push) |
224 | { |
225 | align = maximum_field_alignment; |
226 | break; |
227 | } |
228 | /* FALLTHRU */ |
229 | default: |
230 | GCC_BAD2 ("alignment must be a small power of two, not %d" , align); |
231 | } |
232 | |
233 | switch (action) |
234 | { |
235 | case set: SET_GLOBAL_ALIGNMENT (align); break; |
236 | case push: push_alignment (alignment: align, id); break; |
237 | case pop: pop_alignment (id); break; |
238 | } |
239 | } |
240 | |
241 | struct GTY(()) pending_weak |
242 | { |
243 | tree name; |
244 | tree value; |
245 | }; |
246 | |
247 | |
248 | static GTY(()) vec<pending_weak, va_gc> *pending_weaks; |
249 | |
250 | static void apply_pragma_weak (tree, tree); |
251 | static void handle_pragma_weak (cpp_reader *); |
252 | |
253 | static void |
254 | apply_pragma_weak (tree decl, tree value) |
255 | { |
256 | if (value) |
257 | { |
258 | value = build_string (IDENTIFIER_LENGTH (value), |
259 | IDENTIFIER_POINTER (value)); |
260 | decl_attributes (&decl, build_tree_list (get_identifier ("alias" ), |
261 | build_tree_list (NULL, value)), |
262 | 0); |
263 | } |
264 | |
265 | if (SUPPORTS_WEAK && DECL_EXTERNAL (decl) && TREE_USED (decl) |
266 | && !DECL_WEAK (decl) /* Don't complain about a redundant #pragma. */ |
267 | && DECL_ASSEMBLER_NAME_SET_P (decl) |
268 | && TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl))) |
269 | warning (OPT_Wpragmas, "applying %<#pragma weak %+D%> after first use " |
270 | "results in unspecified behavior" , decl); |
271 | |
272 | declare_weak (decl); |
273 | } |
274 | |
275 | void |
276 | maybe_apply_pragma_weak (tree decl) |
277 | { |
278 | tree id; |
279 | int i; |
280 | pending_weak *pe; |
281 | |
282 | /* Avoid asking for DECL_ASSEMBLER_NAME when it's not needed. */ |
283 | |
284 | /* No weak symbols pending, take the short-cut. */ |
285 | if (vec_safe_is_empty (v: pending_weaks)) |
286 | return; |
287 | /* If it's not visible outside this file, it doesn't matter whether |
288 | it's weak. */ |
289 | if (!DECL_EXTERNAL (decl) && !TREE_PUBLIC (decl)) |
290 | return; |
291 | /* If it's not a function or a variable, it can't be weak. |
292 | FIXME: what kinds of things are visible outside this file but |
293 | aren't functions or variables? Should this be an assert instead? */ |
294 | if (!VAR_OR_FUNCTION_DECL_P (decl)) |
295 | return; |
296 | |
297 | if (DECL_ASSEMBLER_NAME_SET_P (decl)) |
298 | id = DECL_ASSEMBLER_NAME (decl); |
299 | else |
300 | { |
301 | id = DECL_ASSEMBLER_NAME (decl); |
302 | SET_DECL_ASSEMBLER_NAME (decl, NULL_TREE); |
303 | } |
304 | |
305 | FOR_EACH_VEC_ELT (*pending_weaks, i, pe) |
306 | if (id == pe->name) |
307 | { |
308 | apply_pragma_weak (decl, value: pe->value); |
309 | pending_weaks->unordered_remove (ix: i); |
310 | break; |
311 | } |
312 | } |
313 | |
314 | /* Process all "#pragma weak A = B" directives where we have not seen |
315 | a decl for A. */ |
316 | void |
317 | maybe_apply_pending_pragma_weaks (void) |
318 | { |
319 | tree alias_id, id, decl; |
320 | int i; |
321 | pending_weak *pe; |
322 | symtab_node *target; |
323 | |
324 | if (vec_safe_is_empty (v: pending_weaks)) |
325 | return; |
326 | |
327 | FOR_EACH_VEC_ELT (*pending_weaks, i, pe) |
328 | { |
329 | alias_id = pe->name; |
330 | id = pe->value; |
331 | |
332 | if (id == NULL) |
333 | continue; |
334 | |
335 | target = symtab_node::get_for_asmname (asmname: id); |
336 | decl = build_decl (UNKNOWN_LOCATION, |
337 | target ? TREE_CODE (target->decl) : FUNCTION_DECL, |
338 | alias_id, default_function_type); |
339 | |
340 | DECL_ARTIFICIAL (decl) = 1; |
341 | TREE_PUBLIC (decl) = 1; |
342 | DECL_WEAK (decl) = 1; |
343 | if (VAR_P (decl)) |
344 | TREE_STATIC (decl) = 1; |
345 | if (!target) |
346 | { |
347 | error ("%q+D aliased to undefined symbol %qE" , |
348 | decl, id); |
349 | continue; |
350 | } |
351 | |
352 | assemble_alias (decl, id); |
353 | } |
354 | } |
355 | |
356 | /* #pragma weak name [= value] */ |
357 | static void |
358 | handle_pragma_weak (cpp_reader *) |
359 | { |
360 | tree name, value, x, decl; |
361 | enum cpp_ttype t; |
362 | |
363 | value = 0; |
364 | |
365 | if (pragma_lex (&name) != CPP_NAME) |
366 | GCC_BAD ("malformed %<#pragma weak%>, ignored" ); |
367 | t = pragma_lex (&x); |
368 | if (t == CPP_EQ) |
369 | { |
370 | if (pragma_lex (&value) != CPP_NAME) |
371 | GCC_BAD ("malformed %<#pragma weak%>, ignored" ); |
372 | t = pragma_lex (&x); |
373 | } |
374 | if (t != CPP_EOF) |
375 | warning (OPT_Wpragmas, "junk at end of %<#pragma weak%>" ); |
376 | |
377 | decl = identifier_global_value (name); |
378 | if (decl && DECL_P (decl)) |
379 | { |
380 | if (!VAR_OR_FUNCTION_DECL_P (decl)) |
381 | GCC_BAD2 ("%<#pragma weak%> declaration of %q+D not allowed," |
382 | " ignored" , decl); |
383 | apply_pragma_weak (decl, value); |
384 | if (value) |
385 | { |
386 | DECL_EXTERNAL (decl) = 0; |
387 | if (VAR_P (decl)) |
388 | TREE_STATIC (decl) = 1; |
389 | assemble_alias (decl, value); |
390 | } |
391 | } |
392 | else |
393 | { |
394 | pending_weak pe = {.name: name, .value: value}; |
395 | vec_safe_push (v&: pending_weaks, obj: pe); |
396 | } |
397 | } |
398 | |
399 | static enum scalar_storage_order_kind global_sso; |
400 | |
401 | void |
402 | maybe_apply_pragma_scalar_storage_order (tree type) |
403 | { |
404 | if (global_sso == SSO_NATIVE) |
405 | return; |
406 | |
407 | gcc_assert (RECORD_OR_UNION_TYPE_P (type)); |
408 | |
409 | if (lookup_attribute (attr_name: "scalar_storage_order" , TYPE_ATTRIBUTES (type))) |
410 | return; |
411 | |
412 | if (global_sso == SSO_BIG_ENDIAN) |
413 | TYPE_REVERSE_STORAGE_ORDER (type) = !BYTES_BIG_ENDIAN; |
414 | else if (global_sso == SSO_LITTLE_ENDIAN) |
415 | TYPE_REVERSE_STORAGE_ORDER (type) = BYTES_BIG_ENDIAN; |
416 | else |
417 | gcc_unreachable (); |
418 | } |
419 | |
420 | static void |
421 | handle_pragma_scalar_storage_order (cpp_reader *) |
422 | { |
423 | const char *kind_string; |
424 | enum cpp_ttype token; |
425 | tree x; |
426 | |
427 | if (BYTES_BIG_ENDIAN != WORDS_BIG_ENDIAN) |
428 | { |
429 | error ("%<scalar_storage_order%> is not supported because endianness " |
430 | "is not uniform" ); |
431 | return; |
432 | } |
433 | |
434 | if (c_dialect_cxx ()) |
435 | { |
436 | if (warn_unknown_pragmas > in_system_header_at (loc: input_location)) |
437 | warning (OPT_Wunknown_pragmas, |
438 | "%<#pragma scalar_storage_order%> is not supported for C++" ); |
439 | return; |
440 | } |
441 | |
442 | token = pragma_lex (&x); |
443 | if (token != CPP_NAME) |
444 | GCC_BAD ("missing %<big-endian%>, %<little-endian%>, or %<default%> after " |
445 | "%<#pragma scalar_storage_order%>" ); |
446 | kind_string = IDENTIFIER_POINTER (x); |
447 | if (strcmp (s1: kind_string, s2: "default" ) == 0) |
448 | global_sso = default_sso; |
449 | else if (strcmp (s1: kind_string, s2: "big" ) == 0) |
450 | global_sso = SSO_BIG_ENDIAN; |
451 | else if (strcmp (s1: kind_string, s2: "little" ) == 0) |
452 | global_sso = SSO_LITTLE_ENDIAN; |
453 | else |
454 | GCC_BAD ("expected %<big-endian%>, %<little-endian%>, or %<default%> after " |
455 | "%<#pragma scalar_storage_order%>" ); |
456 | } |
457 | |
458 | /* GCC supports two #pragma directives for renaming the external |
459 | symbol associated with a declaration (DECL_ASSEMBLER_NAME), for |
460 | compatibility with the Solaris and VMS system headers. GCC also |
461 | has its own notation for this, __asm__("name") annotations. |
462 | |
463 | Corner cases of these features and their interaction: |
464 | |
465 | 1) Both pragmas silently apply only to declarations with external |
466 | linkage (that is, TREE_PUBLIC || DECL_EXTERNAL). Asm labels |
467 | do not have this restriction. |
468 | |
469 | 2) In C++, both #pragmas silently apply only to extern "C" declarations. |
470 | Asm labels do not have this restriction. |
471 | |
472 | 3) If any of the three ways of changing DECL_ASSEMBLER_NAME is |
473 | applied to a decl whose DECL_ASSEMBLER_NAME is already set, and the |
474 | new name is different, a warning issues and the name does not change. |
475 | |
476 | 4) The "source name" for #pragma redefine_extname is the DECL_NAME, |
477 | *not* the DECL_ASSEMBLER_NAME. |
478 | |
479 | 5) If #pragma extern_prefix is in effect and a declaration occurs |
480 | with an __asm__ name, the #pragma extern_prefix is silently |
481 | ignored for that declaration. |
482 | |
483 | 6) If #pragma extern_prefix and #pragma redefine_extname apply to |
484 | the same declaration, whichever triggered first wins, and a warning |
485 | is issued. (We would like to have #pragma redefine_extname always |
486 | win, but it can appear either before or after the declaration, and |
487 | if it appears afterward, we have no way of knowing whether a modified |
488 | DECL_ASSEMBLER_NAME is due to #pragma extern_prefix.) */ |
489 | |
490 | struct GTY(()) pending_redefinition { |
491 | tree oldname; |
492 | tree newname; |
493 | }; |
494 | |
495 | |
496 | static GTY(()) vec<pending_redefinition, va_gc> *pending_redefine_extname; |
497 | |
498 | static void handle_pragma_redefine_extname (cpp_reader *); |
499 | |
500 | /* #pragma redefine_extname oldname newname */ |
501 | static void |
502 | handle_pragma_redefine_extname (cpp_reader *) |
503 | { |
504 | tree oldname, newname, decls, x; |
505 | enum cpp_ttype t; |
506 | bool found; |
507 | |
508 | if (pragma_lex (&oldname) != CPP_NAME) |
509 | GCC_BAD ("malformed %<#pragma redefine_extname%>, ignored" ); |
510 | if (pragma_lex (&newname) != CPP_NAME) |
511 | GCC_BAD ("malformed %<#pragma redefine_extname%>, ignored" ); |
512 | t = pragma_lex (&x); |
513 | if (t != CPP_EOF) |
514 | warning (OPT_Wpragmas, "junk at end of %<#pragma redefine_extname%>" ); |
515 | |
516 | found = false; |
517 | for (decls = c_linkage_bindings (oldname); |
518 | decls; ) |
519 | { |
520 | tree decl; |
521 | if (TREE_CODE (decls) == TREE_LIST) |
522 | { |
523 | decl = TREE_VALUE (decls); |
524 | decls = TREE_CHAIN (decls); |
525 | } |
526 | else |
527 | { |
528 | decl = decls; |
529 | decls = NULL_TREE; |
530 | } |
531 | |
532 | if ((TREE_PUBLIC (decl) || DECL_EXTERNAL (decl)) |
533 | && VAR_OR_FUNCTION_DECL_P (decl)) |
534 | { |
535 | found = true; |
536 | if (DECL_ASSEMBLER_NAME_SET_P (decl)) |
537 | { |
538 | const char *name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)); |
539 | name = targetm.strip_name_encoding (name); |
540 | |
541 | if (!id_equal (id: newname, str: name)) |
542 | warning (OPT_Wpragmas, "%<#pragma redefine_extname%> " |
543 | "ignored due to conflict with previous rename" ); |
544 | } |
545 | else |
546 | symtab->change_decl_assembler_name (decl, name: newname); |
547 | } |
548 | } |
549 | |
550 | if (!found) |
551 | /* We have to add this to the rename list even if there's already |
552 | a global value that doesn't meet the above criteria, because in |
553 | C++ "struct foo {...};" puts "foo" in the current namespace but |
554 | does *not* conflict with a subsequent declaration of a function |
555 | or variable foo. See g++.dg/other/pragma-re-2.C. */ |
556 | add_to_renaming_pragma_list (oldname, newname); |
557 | } |
558 | |
559 | /* This is called from here and from ia64-c.cc. */ |
560 | void |
561 | add_to_renaming_pragma_list (tree oldname, tree newname) |
562 | { |
563 | unsigned ix; |
564 | pending_redefinition *p; |
565 | |
566 | FOR_EACH_VEC_SAFE_ELT (pending_redefine_extname, ix, p) |
567 | if (oldname == p->oldname) |
568 | { |
569 | if (p->newname != newname) |
570 | warning (OPT_Wpragmas, "%<#pragma redefine_extname%> ignored due to " |
571 | "conflict with previous %<#pragma redefine_extname%>" ); |
572 | return; |
573 | } |
574 | |
575 | pending_redefinition e = {.oldname: oldname, .newname: newname}; |
576 | vec_safe_push (v&: pending_redefine_extname, obj: e); |
577 | } |
578 | |
579 | /* The current prefix set by #pragma extern_prefix. */ |
580 | GTY(()) tree pragma_extern_prefix; |
581 | |
582 | /* Hook from the front ends to apply the results of one of the preceding |
583 | pragmas that rename variables. */ |
584 | |
585 | tree |
586 | maybe_apply_renaming_pragma (tree decl, tree asmname) |
587 | { |
588 | unsigned ix; |
589 | pending_redefinition *p; |
590 | |
591 | /* The renaming pragmas are only applied to declarations with |
592 | external linkage. */ |
593 | if (!VAR_OR_FUNCTION_DECL_P (decl) |
594 | || (!TREE_PUBLIC (decl) && !DECL_EXTERNAL (decl)) |
595 | || !has_c_linkage (decl)) |
596 | return asmname; |
597 | |
598 | /* If the DECL_ASSEMBLER_NAME is already set, it does not change, |
599 | but we may warn about a rename that conflicts. */ |
600 | if (DECL_ASSEMBLER_NAME_SET_P (decl)) |
601 | { |
602 | const char *oldname = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)); |
603 | oldname = targetm.strip_name_encoding (oldname); |
604 | |
605 | if (asmname && strcmp (TREE_STRING_POINTER (asmname), s2: oldname)) |
606 | warning (OPT_Wpragmas, "%<asm%> declaration ignored due to " |
607 | "conflict with previous rename" ); |
608 | |
609 | /* Take any pending redefine_extname off the list. */ |
610 | FOR_EACH_VEC_SAFE_ELT (pending_redefine_extname, ix, p) |
611 | if (DECL_NAME (decl) == p->oldname) |
612 | { |
613 | /* Only warn if there is a conflict. */ |
614 | if (!id_equal (id: p->newname, str: oldname)) |
615 | warning (OPT_Wpragmas, "%<#pragma redefine_extname%> ignored " |
616 | "due to conflict with previous rename" ); |
617 | |
618 | pending_redefine_extname->unordered_remove (ix); |
619 | break; |
620 | } |
621 | return NULL_TREE; |
622 | } |
623 | |
624 | /* Find out if we have a pending #pragma redefine_extname. */ |
625 | FOR_EACH_VEC_SAFE_ELT (pending_redefine_extname, ix, p) |
626 | if (DECL_NAME (decl) == p->oldname) |
627 | { |
628 | tree newname = p->newname; |
629 | pending_redefine_extname->unordered_remove (ix); |
630 | |
631 | /* If we already have an asmname, #pragma redefine_extname is |
632 | ignored (with a warning if it conflicts). */ |
633 | if (asmname) |
634 | { |
635 | if (strcmp (TREE_STRING_POINTER (asmname), |
636 | IDENTIFIER_POINTER (newname)) != 0) |
637 | warning (OPT_Wpragmas, "%<#pragma redefine_extname%> ignored " |
638 | "due to conflict with %<asm%> declaration" ); |
639 | return asmname; |
640 | } |
641 | |
642 | /* Otherwise we use what we've got; #pragma extern_prefix is |
643 | silently ignored. */ |
644 | return build_string (IDENTIFIER_LENGTH (newname), |
645 | IDENTIFIER_POINTER (newname)); |
646 | } |
647 | |
648 | /* If we've got an asmname, #pragma extern_prefix is silently ignored. */ |
649 | if (asmname) |
650 | return asmname; |
651 | |
652 | /* If #pragma extern_prefix is in effect, apply it. */ |
653 | if (pragma_extern_prefix) |
654 | { |
655 | const char *prefix = TREE_STRING_POINTER (pragma_extern_prefix); |
656 | size_t plen = TREE_STRING_LENGTH (pragma_extern_prefix) - 1; |
657 | |
658 | const char *id = IDENTIFIER_POINTER (DECL_NAME (decl)); |
659 | size_t ilen = IDENTIFIER_LENGTH (DECL_NAME (decl)); |
660 | |
661 | char *newname = (char *) alloca (plen + ilen + 1); |
662 | |
663 | memcpy (dest: newname, src: prefix, n: plen); |
664 | memcpy (dest: newname + plen, src: id, n: ilen + 1); |
665 | |
666 | return build_string (plen + ilen, newname); |
667 | } |
668 | |
669 | /* Nada. */ |
670 | return NULL_TREE; |
671 | } |
672 | |
673 | |
674 | static void handle_pragma_visibility (cpp_reader *); |
675 | |
676 | static vec<int> visstack; |
677 | |
678 | /* Push the visibility indicated by STR onto the top of the #pragma |
679 | visibility stack. KIND is 0 for #pragma GCC visibility, 1 for |
680 | C++ namespace with visibility attribute and 2 for C++ builtin |
681 | ABI namespace. push_visibility/pop_visibility calls must have |
682 | matching KIND, it is not allowed to push visibility using one |
683 | KIND and pop using a different one. */ |
684 | |
685 | void |
686 | push_visibility (const char *str, int kind) |
687 | { |
688 | visstack.safe_push (obj: ((int) default_visibility) | (kind << 8)); |
689 | if (!strcmp (s1: str, s2: "default" )) |
690 | default_visibility = VISIBILITY_DEFAULT; |
691 | else if (!strcmp (s1: str, s2: "internal" )) |
692 | default_visibility = VISIBILITY_INTERNAL; |
693 | else if (!strcmp (s1: str, s2: "hidden" )) |
694 | default_visibility = VISIBILITY_HIDDEN; |
695 | else if (!strcmp (s1: str, s2: "protected" )) |
696 | default_visibility = VISIBILITY_PROTECTED; |
697 | else |
698 | GCC_BAD ("%<#pragma GCC visibility push()%> must specify %<default%>, " |
699 | "%<internal%>, %<hidden%> or %<protected%>" ); |
700 | visibility_options.inpragma = 1; |
701 | } |
702 | |
703 | /* Pop a level of the #pragma visibility stack. Return true if |
704 | successful. */ |
705 | |
706 | bool |
707 | pop_visibility (int kind) |
708 | { |
709 | if (!visstack.length ()) |
710 | return false; |
711 | if ((visstack.last () >> 8) != kind) |
712 | return false; |
713 | default_visibility |
714 | = (enum symbol_visibility) (visstack.pop () & 0xff); |
715 | visibility_options.inpragma |
716 | = visstack.length () != 0; |
717 | return true; |
718 | } |
719 | |
720 | /* Sets the default visibility for symbols to something other than that |
721 | specified on the command line. */ |
722 | |
723 | static void |
724 | handle_pragma_visibility (cpp_reader *) |
725 | { |
726 | /* Form is #pragma GCC visibility push(hidden)|pop */ |
727 | tree x; |
728 | enum cpp_ttype token; |
729 | enum { bad, push, pop } action = bad; |
730 | |
731 | token = pragma_lex (&x); |
732 | if (token == CPP_NAME) |
733 | { |
734 | const char *op = IDENTIFIER_POINTER (x); |
735 | if (!strcmp (s1: op, s2: "push" )) |
736 | action = push; |
737 | else if (!strcmp (s1: op, s2: "pop" )) |
738 | action = pop; |
739 | } |
740 | if (bad == action) |
741 | GCC_BAD ("%<#pragma GCC visibility%> must be followed by %<push%> " |
742 | "or %<pop%>" ); |
743 | else |
744 | { |
745 | if (pop == action) |
746 | { |
747 | if (! pop_visibility (kind: 0)) |
748 | GCC_BAD ("no matching push for %<#pragma GCC visibility pop%>" ); |
749 | } |
750 | else |
751 | { |
752 | if (pragma_lex (&x) != CPP_OPEN_PAREN) |
753 | GCC_BAD ("missing %<(%> after %<#pragma GCC visibility push%> - ignored" ); |
754 | token = pragma_lex (&x); |
755 | if (token != CPP_NAME) |
756 | GCC_BAD ("malformed %<#pragma GCC visibility push%>" ); |
757 | else |
758 | push_visibility (IDENTIFIER_POINTER (x), kind: 0); |
759 | if (pragma_lex (&x) != CPP_CLOSE_PAREN) |
760 | GCC_BAD ("missing %<(%> after %<#pragma GCC visibility push%> - ignored" ); |
761 | } |
762 | } |
763 | if (pragma_lex (&x) != CPP_EOF) |
764 | warning (OPT_Wpragmas, "junk at end of %<#pragma GCC visibility%>" ); |
765 | } |
766 | |
767 | /* Helper routines for parsing #pragma GCC diagnostic. */ |
768 | class pragma_diagnostic_data |
769 | { |
770 | pragma_diagnostic_data (const pragma_diagnostic_data &) = delete; |
771 | pragma_diagnostic_data& operator= (const pragma_diagnostic_data &) = delete; |
772 | |
773 | public: |
774 | bool valid; |
775 | location_t loc_kind, loc_option; |
776 | enum pd_kind_t |
777 | { |
778 | PK_INVALID, |
779 | PK_PUSH, |
780 | PK_POP, |
781 | PK_IGNORED_ATTRIBUTES, |
782 | PK_DIAGNOSTIC, |
783 | } pd_kind; |
784 | diagnostic_t diagnostic_kind; |
785 | const char *kind_str; |
786 | const char *option_str; |
787 | bool own_option_str; |
788 | |
789 | pragma_diagnostic_data () { clear (); } |
790 | void clear () |
791 | { |
792 | valid = false; |
793 | loc_kind = loc_option = UNKNOWN_LOCATION; |
794 | pd_kind = PK_INVALID; |
795 | diagnostic_kind = DK_UNSPECIFIED; |
796 | kind_str = option_str = nullptr; |
797 | own_option_str = false; |
798 | } |
799 | |
800 | ~pragma_diagnostic_data () |
801 | { |
802 | if (own_option_str && option_str) |
803 | XDELETEVEC (const_cast<char *> (option_str)); |
804 | } |
805 | |
806 | void set_kind (const char *kind_string) |
807 | { |
808 | kind_str = kind_string; |
809 | |
810 | pd_kind = PK_INVALID; |
811 | diagnostic_kind = DK_UNSPECIFIED; |
812 | if (strcmp (s1: kind_str, s2: "push" ) == 0) |
813 | pd_kind = PK_PUSH; |
814 | else if (strcmp (s1: kind_str, s2: "pop" ) == 0) |
815 | pd_kind = PK_POP; |
816 | else if (strcmp (s1: kind_str, s2: "ignored_attributes" ) == 0) |
817 | pd_kind = PK_IGNORED_ATTRIBUTES; |
818 | else if (strcmp (s1: kind_str, s2: "error" ) == 0) |
819 | { |
820 | pd_kind = PK_DIAGNOSTIC; |
821 | diagnostic_kind = DK_ERROR; |
822 | } |
823 | else if (strcmp (s1: kind_str, s2: "warning" ) == 0) |
824 | { |
825 | pd_kind = PK_DIAGNOSTIC; |
826 | diagnostic_kind = DK_WARNING; |
827 | } |
828 | else if (strcmp (s1: kind_str, s2: "ignored" ) == 0) |
829 | { |
830 | pd_kind = PK_DIAGNOSTIC; |
831 | diagnostic_kind = DK_IGNORED; |
832 | } |
833 | } |
834 | |
835 | bool needs_option () const |
836 | { |
837 | return pd_kind == PK_IGNORED_ATTRIBUTES |
838 | || pd_kind == PK_DIAGNOSTIC; |
839 | } |
840 | |
841 | }; |
842 | |
843 | /* This will call into either the C or C++ frontends as appropriate to get |
844 | tokens from libcpp for the pragma. */ |
845 | |
846 | static void |
847 | pragma_diagnostic_lex (pragma_diagnostic_data *result) |
848 | { |
849 | result->clear (); |
850 | tree x; |
851 | auto ttype = pragma_lex (&x, loc: &result->loc_kind); |
852 | if (ttype != CPP_NAME) |
853 | return; |
854 | result->set_kind (IDENTIFIER_POINTER (x)); |
855 | if (result->pd_kind == pragma_diagnostic_data::PK_INVALID) |
856 | return; |
857 | |
858 | if (result->needs_option ()) |
859 | { |
860 | ttype = pragma_lex (&x, loc: &result->loc_option); |
861 | if (ttype != CPP_STRING) |
862 | return; |
863 | result->option_str = TREE_STRING_POINTER (x); |
864 | } |
865 | |
866 | result->valid = true; |
867 | } |
868 | |
869 | /* Handle #pragma GCC diagnostic. Early mode is used by frontends (such as C++) |
870 | that do not process the deferred pragma while they are consuming tokens; they |
871 | can use early mode to make sure diagnostics affecting the preprocessor itself |
872 | are correctly modified by the #pragma. */ |
873 | template<bool early, bool is_pp> static void |
874 | handle_pragma_diagnostic_impl () |
875 | { |
876 | static const bool want_diagnostics = (is_pp || !early); |
877 | |
878 | pragma_diagnostic_data data; |
879 | pragma_diagnostic_lex (result: &data); |
880 | |
881 | if (!data.kind_str) |
882 | { |
883 | if (want_diagnostics) |
884 | warning_at (data.loc_kind, OPT_Wpragmas, |
885 | "missing %<error%>, %<warning%>, %<ignored%>, %<push%>, " |
886 | "%<pop%>, or %<ignored_attributes%> after " |
887 | "%<#pragma GCC diagnostic%>" ); |
888 | return; |
889 | } |
890 | |
891 | switch (data.pd_kind) |
892 | { |
893 | |
894 | case pragma_diagnostic_data::PK_PUSH: |
895 | diagnostic_push_diagnostics (context: global_dc, where: input_location); |
896 | return; |
897 | |
898 | case pragma_diagnostic_data::PK_POP: |
899 | diagnostic_pop_diagnostics (context: global_dc, where: input_location); |
900 | return; |
901 | |
902 | case pragma_diagnostic_data::PK_IGNORED_ATTRIBUTES: |
903 | { |
904 | if (early) |
905 | return; |
906 | if (!data.option_str) |
907 | { |
908 | warning_at (data.loc_option, OPT_Wpragmas, |
909 | "missing attribute name after %<#pragma GCC diagnostic " |
910 | "ignored_attributes%>" ); |
911 | return; |
912 | } |
913 | char *args = xstrdup (data.option_str); |
914 | const size_t l = strlen (s: args); |
915 | if (l == 0) |
916 | { |
917 | warning_at (data.loc_option, OPT_Wpragmas, |
918 | "missing argument to %<#pragma GCC " |
919 | "diagnostic ignored_attributes%>" ); |
920 | free (ptr: args); |
921 | return; |
922 | } |
923 | else if (args[l - 1] == ',') |
924 | { |
925 | warning_at (data.loc_option, OPT_Wpragmas, |
926 | "trailing %<,%> in arguments for " |
927 | "%<#pragma GCC diagnostic ignored_attributes%>" ); |
928 | free (ptr: args); |
929 | return; |
930 | } |
931 | auto_vec<char *> v; |
932 | for (char *p = strtok (s: args, delim: "," ); p; p = strtok (NULL, delim: "," )) |
933 | v.safe_push (obj: p); |
934 | handle_ignored_attributes_option (&v); |
935 | free (ptr: args); |
936 | return; |
937 | } |
938 | |
939 | case pragma_diagnostic_data::PK_DIAGNOSTIC: |
940 | if (!data.option_str) |
941 | { |
942 | if (want_diagnostics) |
943 | warning_at (data.loc_option, OPT_Wpragmas, |
944 | "missing option after %<#pragma GCC diagnostic%> kind" ); |
945 | return; |
946 | } |
947 | break; |
948 | |
949 | default: |
950 | if (want_diagnostics) |
951 | warning_at (data.loc_kind, OPT_Wpragmas, |
952 | "expected %<error%>, %<warning%>, %<ignored%>, %<push%>, " |
953 | "%<pop%>, %<ignored_attributes%> after " |
954 | "%<#pragma GCC diagnostic%>" ); |
955 | return; |
956 | |
957 | } |
958 | |
959 | gcc_assert (data.pd_kind == pragma_diagnostic_data::PK_DIAGNOSTIC); |
960 | gcc_assert (data.valid); |
961 | |
962 | unsigned int lang_mask = c_common_option_lang_mask () | CL_COMMON; |
963 | /* option_string + 1 to skip the initial '-' */ |
964 | unsigned int option_index = find_opt (input: data.option_str + 1, lang_mask); |
965 | |
966 | if (early && !(c_option_is_from_cpp_diagnostics (option_index) |
967 | || option_index == OPT_Wunknown_pragmas)) |
968 | return; |
969 | |
970 | if (option_index == OPT_SPECIAL_unknown) |
971 | { |
972 | if (want_diagnostics) |
973 | { |
974 | auto_diagnostic_group d; |
975 | if (warning_at (data.loc_option, OPT_Wpragmas, |
976 | "unknown option after %<#pragma GCC diagnostic%> kind" )) |
977 | { |
978 | option_proposer op; |
979 | const char *hint = op.suggest_option (bad_opt: data.option_str + 1); |
980 | if (hint) |
981 | inform (data.loc_option, "did you mean %<-%s%>?" , hint); |
982 | } |
983 | } |
984 | return; |
985 | } |
986 | else if (!(cl_options[option_index].flags & CL_WARNING)) |
987 | { |
988 | if (want_diagnostics) |
989 | warning_at (data.loc_option, OPT_Wpragmas, |
990 | "%qs is not an option that controls warnings" , |
991 | data.option_str); |
992 | return; |
993 | } |
994 | else if (!(cl_options[option_index].flags & lang_mask)) |
995 | { |
996 | if (want_diagnostics) |
997 | { |
998 | char *ok_langs = write_langs (mask: cl_options[option_index].flags); |
999 | char *bad_lang = write_langs (mask: c_common_option_lang_mask ()); |
1000 | warning_at (data.loc_option, OPT_Wpragmas, |
1001 | "option %qs is valid for %s but not for %s" , |
1002 | data.option_str, ok_langs, bad_lang); |
1003 | free (ptr: ok_langs); |
1004 | free (ptr: bad_lang); |
1005 | } |
1006 | return; |
1007 | } |
1008 | |
1009 | const char *arg = NULL; |
1010 | if (cl_options[option_index].flags & CL_JOINED) |
1011 | arg = data.option_str + 1 + cl_options[option_index].opt_len; |
1012 | |
1013 | struct cl_option_handlers handlers; |
1014 | set_default_handlers (handlers: &handlers, NULL); |
1015 | /* FIXME: input_location isn't the best location here, but it is |
1016 | what we used to do here before and changing it breaks e.g. |
1017 | PR69543 and PR69558. */ |
1018 | control_warning_option (opt_index: option_index, kind: (int) data.diagnostic_kind, |
1019 | arg, imply: data.diagnostic_kind != DK_IGNORED, |
1020 | loc: input_location, lang_mask, handlers: &handlers, |
1021 | opts: &global_options, opts_set: &global_options_set, |
1022 | dc: global_dc); |
1023 | } |
1024 | |
1025 | static void |
1026 | handle_pragma_diagnostic (cpp_reader *) |
1027 | { |
1028 | handle_pragma_diagnostic_impl<false, false> (); |
1029 | } |
1030 | |
1031 | static void |
1032 | handle_pragma_diagnostic_early (cpp_reader *) |
1033 | { |
1034 | handle_pragma_diagnostic_impl<true, false> (); |
1035 | } |
1036 | |
1037 | static void |
1038 | handle_pragma_diagnostic_early_pp (cpp_reader *) |
1039 | { |
1040 | handle_pragma_diagnostic_impl<true, true> (); |
1041 | } |
1042 | |
1043 | /* Parse #pragma GCC target (xxx) to set target specific options. */ |
1044 | static void |
1045 | handle_pragma_target(cpp_reader *) |
1046 | { |
1047 | location_t loc; |
1048 | enum cpp_ttype token; |
1049 | tree x; |
1050 | bool close_paren_needed_p = false; |
1051 | |
1052 | if (cfun) |
1053 | { |
1054 | error ("%<#pragma GCC option%> is not allowed inside functions" ); |
1055 | return; |
1056 | } |
1057 | |
1058 | token = pragma_lex (&x, loc: &loc); |
1059 | if (token == CPP_OPEN_PAREN) |
1060 | { |
1061 | close_paren_needed_p = true; |
1062 | token = pragma_lex (&x, loc: &loc); |
1063 | } |
1064 | |
1065 | if (token != CPP_STRING) |
1066 | GCC_BAD_AT (loc, "%<#pragma GCC option%> is not a string" ); |
1067 | |
1068 | /* Strings are user options. */ |
1069 | else |
1070 | { |
1071 | tree args = NULL_TREE; |
1072 | |
1073 | do |
1074 | { |
1075 | /* Build up the strings now as a tree linked list. Skip empty |
1076 | strings. */ |
1077 | if (TREE_STRING_LENGTH (x) > 0) |
1078 | args = tree_cons (NULL_TREE, x, args); |
1079 | |
1080 | token = pragma_lex (&x); |
1081 | while (token == CPP_COMMA) |
1082 | token = pragma_lex (&x); |
1083 | } |
1084 | while (token == CPP_STRING); |
1085 | |
1086 | if (close_paren_needed_p) |
1087 | { |
1088 | if (token == CPP_CLOSE_PAREN) |
1089 | token = pragma_lex (&x); |
1090 | else |
1091 | GCC_BAD ("%<#pragma GCC target (string [,string]...)%> does " |
1092 | "not have a final %<)%>" ); |
1093 | } |
1094 | |
1095 | if (token != CPP_EOF) |
1096 | { |
1097 | error ("%<#pragma GCC target%> string is badly formed" ); |
1098 | return; |
1099 | } |
1100 | |
1101 | /* put arguments in the order the user typed them. */ |
1102 | args = nreverse (args); |
1103 | |
1104 | if (targetm.target_option.pragma_parse (args, NULL_TREE)) |
1105 | current_target_pragma = chainon (current_target_pragma, args); |
1106 | |
1107 | /* A target pragma can also influence optimization options. */ |
1108 | tree current_optimize |
1109 | = build_optimization_node (opts: &global_options, opts_set: &global_options_set); |
1110 | if (current_optimize != optimization_current_node) |
1111 | optimization_current_node = current_optimize; |
1112 | } |
1113 | } |
1114 | |
1115 | /* Handle #pragma GCC optimize to set optimization options. */ |
1116 | static void |
1117 | handle_pragma_optimize (cpp_reader *) |
1118 | { |
1119 | enum cpp_ttype token; |
1120 | tree x; |
1121 | bool close_paren_needed_p = false; |
1122 | tree optimization_previous_node = optimization_current_node; |
1123 | |
1124 | if (cfun) |
1125 | { |
1126 | error ("%<#pragma GCC optimize%> is not allowed inside functions" ); |
1127 | return; |
1128 | } |
1129 | |
1130 | token = pragma_lex (&x); |
1131 | if (token == CPP_OPEN_PAREN) |
1132 | { |
1133 | close_paren_needed_p = true; |
1134 | token = pragma_lex (&x); |
1135 | } |
1136 | |
1137 | if (token != CPP_STRING && token != CPP_NUMBER) |
1138 | GCC_BAD ("%<#pragma GCC optimize%> is not a string or number" ); |
1139 | |
1140 | /* Strings/numbers are user options. */ |
1141 | else |
1142 | { |
1143 | tree args = NULL_TREE; |
1144 | |
1145 | do |
1146 | { |
1147 | /* Build up the numbers/strings now as a list. */ |
1148 | if (token != CPP_STRING || TREE_STRING_LENGTH (x) > 0) |
1149 | args = tree_cons (NULL_TREE, x, args); |
1150 | |
1151 | token = pragma_lex (&x); |
1152 | while (token == CPP_COMMA) |
1153 | token = pragma_lex (&x); |
1154 | } |
1155 | while (token == CPP_STRING || token == CPP_NUMBER); |
1156 | |
1157 | if (close_paren_needed_p) |
1158 | { |
1159 | if (token == CPP_CLOSE_PAREN) |
1160 | token = pragma_lex (&x); |
1161 | else |
1162 | GCC_BAD ("%<#pragma GCC optimize (string [,string]...)%> does " |
1163 | "not have a final %<)%>" ); |
1164 | } |
1165 | |
1166 | if (token != CPP_EOF) |
1167 | { |
1168 | error ("%<#pragma GCC optimize%> string is badly formed" ); |
1169 | return; |
1170 | } |
1171 | |
1172 | /* put arguments in the order the user typed them. */ |
1173 | args = nreverse (args); |
1174 | |
1175 | parse_optimize_options (args, false); |
1176 | current_optimize_pragma = chainon (current_optimize_pragma, args); |
1177 | optimization_current_node |
1178 | = build_optimization_node (opts: &global_options, opts_set: &global_options_set); |
1179 | c_cpp_builtins_optimize_pragma (parse_in, |
1180 | optimization_previous_node, |
1181 | optimization_current_node); |
1182 | } |
1183 | } |
1184 | |
1185 | /* Stack of the #pragma GCC options created with #pragma GCC push_option. Save |
1186 | both the binary representation of the options and the TREE_LIST of |
1187 | strings that will be added to the function's attribute list. */ |
1188 | struct GTY(()) opt_stack { |
1189 | struct opt_stack *prev; |
1190 | tree target_binary; |
1191 | tree target_strings; |
1192 | tree optimize_binary; |
1193 | tree optimize_strings; |
1194 | gcc_options * GTY ((skip)) saved_global_options; |
1195 | }; |
1196 | |
1197 | static GTY(()) struct opt_stack * options_stack; |
1198 | |
1199 | /* Handle #pragma GCC push_options to save the current target and optimization |
1200 | options. */ |
1201 | |
1202 | static void |
1203 | handle_pragma_push_options (cpp_reader *) |
1204 | { |
1205 | enum cpp_ttype token; |
1206 | tree x = 0; |
1207 | |
1208 | token = pragma_lex (&x); |
1209 | if (token != CPP_EOF) |
1210 | { |
1211 | warning (OPT_Wpragmas, "junk at end of %<#pragma GCC push_options%>" ); |
1212 | return; |
1213 | } |
1214 | |
1215 | opt_stack *p = ggc_alloc<opt_stack> (); |
1216 | p->prev = options_stack; |
1217 | options_stack = p; |
1218 | |
1219 | /* Save optimization and target flags in binary format. */ |
1220 | if (flag_checking) |
1221 | { |
1222 | p->saved_global_options = XNEW (gcc_options); |
1223 | *p->saved_global_options = global_options; |
1224 | } |
1225 | p->optimize_binary = build_optimization_node (opts: &global_options, |
1226 | opts_set: &global_options_set); |
1227 | p->target_binary = build_target_option_node (opts: &global_options, |
1228 | opts_set: &global_options_set); |
1229 | |
1230 | /* Save optimization and target flags in string list format. */ |
1231 | p->optimize_strings = copy_list (current_optimize_pragma); |
1232 | p->target_strings = copy_list (current_target_pragma); |
1233 | } |
1234 | |
1235 | /* Handle #pragma GCC pop_options to restore the current target and |
1236 | optimization options from a previous push_options. */ |
1237 | |
1238 | static void |
1239 | handle_pragma_pop_options (cpp_reader *) |
1240 | { |
1241 | enum cpp_ttype token; |
1242 | tree x = 0; |
1243 | opt_stack *p; |
1244 | |
1245 | token = pragma_lex (&x); |
1246 | if (token != CPP_EOF) |
1247 | { |
1248 | warning (OPT_Wpragmas, "junk at end of %<#pragma GCC pop_options%>" ); |
1249 | return; |
1250 | } |
1251 | |
1252 | if (! options_stack) |
1253 | { |
1254 | warning (OPT_Wpragmas, |
1255 | "%<#pragma GCC pop_options%> without a corresponding " |
1256 | "%<#pragma GCC push_options%>" ); |
1257 | return; |
1258 | } |
1259 | |
1260 | p = options_stack; |
1261 | options_stack = p->prev; |
1262 | |
1263 | if (p->target_binary != target_option_current_node) |
1264 | { |
1265 | (void) targetm.target_option.pragma_parse (NULL_TREE, p->target_binary); |
1266 | target_option_current_node = p->target_binary; |
1267 | } |
1268 | |
1269 | /* Always restore optimization options as optimization_current_node is |
1270 | * overwritten by invoke_set_current_function_hook. */ |
1271 | cl_optimization_restore (&global_options, &global_options_set, |
1272 | TREE_OPTIMIZATION (p->optimize_binary)); |
1273 | cl_target_option_restore (&global_options, &global_options_set, |
1274 | TREE_TARGET_OPTION (p->target_binary)); |
1275 | |
1276 | if (p->optimize_binary != optimization_current_node) |
1277 | { |
1278 | c_cpp_builtins_optimize_pragma (parse_in, optimization_current_node, |
1279 | p->optimize_binary); |
1280 | optimization_current_node = p->optimize_binary; |
1281 | } |
1282 | if (flag_checking && !seen_error ()) |
1283 | { |
1284 | cl_optimization_compare (ptr1: p->saved_global_options, ptr2: &global_options); |
1285 | free (ptr: p->saved_global_options); |
1286 | } |
1287 | |
1288 | current_target_pragma = p->target_strings; |
1289 | current_optimize_pragma = p->optimize_strings; |
1290 | } |
1291 | |
1292 | /* This is mostly a helper for handle_pragma_reset_options () to do the actual |
1293 | work, but the C++ frontend, for example, needs an external interface to |
1294 | perform this operation, since it processes target pragmas twice. (Once for |
1295 | preprocessing purposes, and then again during compilation.) */ |
1296 | |
1297 | void |
1298 | c_reset_target_pragmas () |
1299 | { |
1300 | tree new_optimize = optimization_default_node; |
1301 | tree new_target = target_option_default_node; |
1302 | if (new_target != target_option_current_node) |
1303 | { |
1304 | (void) targetm.target_option.pragma_parse (NULL_TREE, new_target); |
1305 | target_option_current_node = new_target; |
1306 | } |
1307 | |
1308 | if (new_optimize != optimization_current_node) |
1309 | { |
1310 | tree old_optimize = optimization_current_node; |
1311 | cl_optimization_restore (&global_options, &global_options_set, |
1312 | TREE_OPTIMIZATION (new_optimize)); |
1313 | c_cpp_builtins_optimize_pragma (parse_in, old_optimize, new_optimize); |
1314 | optimization_current_node = new_optimize; |
1315 | } |
1316 | |
1317 | current_target_pragma = NULL_TREE; |
1318 | current_optimize_pragma = NULL_TREE; |
1319 | } |
1320 | |
1321 | /* Handle #pragma GCC reset_options to restore the current target and |
1322 | optimization options to the original options used on the command line. */ |
1323 | |
1324 | static void |
1325 | handle_pragma_reset_options (cpp_reader *) |
1326 | { |
1327 | tree x; |
1328 | if (pragma_lex (&x) != CPP_EOF) |
1329 | warning (OPT_Wpragmas, "junk at end of %<#pragma reset_options%>" ); |
1330 | else |
1331 | c_reset_target_pragmas (); |
1332 | } |
1333 | |
1334 | /* Print a plain user-specified message. */ |
1335 | |
1336 | static void |
1337 | handle_pragma_message (cpp_reader *) |
1338 | { |
1339 | location_t loc; |
1340 | enum cpp_ttype token; |
1341 | tree x, message = 0; |
1342 | |
1343 | token = pragma_lex (&x); |
1344 | if (token == CPP_OPEN_PAREN) |
1345 | { |
1346 | token = pragma_lex (&x); |
1347 | if (token == CPP_STRING) |
1348 | message = x; |
1349 | else |
1350 | GCC_BAD ("expected a string after %<#pragma message%>" ); |
1351 | if (pragma_lex (&x) != CPP_CLOSE_PAREN) |
1352 | GCC_BAD ("malformed %<#pragma message%>, ignored" ); |
1353 | } |
1354 | else if (token == CPP_STRING) |
1355 | message = x; |
1356 | else if (token == CPP_STRING_USERDEF) |
1357 | GCC_BAD ("string literal with user-defined suffix is invalid in this " |
1358 | "context" ); |
1359 | else |
1360 | GCC_BAD ("expected a string after %<#pragma message%>" ); |
1361 | |
1362 | gcc_assert (message); |
1363 | |
1364 | if (pragma_lex (&x, loc: &loc) != CPP_EOF) |
1365 | warning_at (loc, OPT_Wpragmas, "junk at end of %<#pragma message%>" ); |
1366 | |
1367 | if (TREE_STRING_LENGTH (message) > 1) |
1368 | inform (input_location, "%<#pragma message: %s%>" , |
1369 | TREE_STRING_POINTER (message)); |
1370 | } |
1371 | |
1372 | /* Ignore a no-op pragma that GCC recognizes, but which has no effect. */ |
1373 | static void |
1374 | handle_pragma_ignore (cpp_reader *) |
1375 | { |
1376 | } |
1377 | |
1378 | /* Mark whether the current location is valid for a STDC pragma. */ |
1379 | |
1380 | static bool valid_location_for_stdc_pragma; |
1381 | |
1382 | void |
1383 | mark_valid_location_for_stdc_pragma (bool flag) |
1384 | { |
1385 | valid_location_for_stdc_pragma = flag; |
1386 | } |
1387 | |
1388 | /* Return true if the current location is valid for a STDC pragma. */ |
1389 | |
1390 | bool |
1391 | valid_location_for_stdc_pragma_p (void) |
1392 | { |
1393 | return valid_location_for_stdc_pragma; |
1394 | } |
1395 | |
1396 | enum pragma_switch_t { PRAGMA_ON, PRAGMA_OFF, PRAGMA_DEFAULT, PRAGMA_BAD }; |
1397 | |
1398 | /* A STDC pragma must appear outside of external declarations or |
1399 | preceding all explicit declarations and statements inside a compound |
1400 | statement; its behavior is undefined if used in any other context. |
1401 | It takes a switch of ON, OFF, or DEFAULT. */ |
1402 | |
1403 | static enum pragma_switch_t |
1404 | handle_stdc_pragma (const char *pname) |
1405 | { |
1406 | const char *arg; |
1407 | tree t; |
1408 | enum pragma_switch_t ret; |
1409 | |
1410 | if (!valid_location_for_stdc_pragma_p ()) |
1411 | { |
1412 | warning (OPT_Wpragmas, "invalid location for %<pragma %s%>, ignored" , |
1413 | pname); |
1414 | return PRAGMA_BAD; |
1415 | } |
1416 | |
1417 | if (pragma_lex (&t) != CPP_NAME) |
1418 | { |
1419 | warning (OPT_Wpragmas, "malformed %<#pragma %s%>, ignored" , pname); |
1420 | return PRAGMA_BAD; |
1421 | } |
1422 | |
1423 | arg = IDENTIFIER_POINTER (t); |
1424 | |
1425 | if (!strcmp (s1: arg, s2: "ON" )) |
1426 | ret = PRAGMA_ON; |
1427 | else if (!strcmp (s1: arg, s2: "OFF" )) |
1428 | ret = PRAGMA_OFF; |
1429 | else if (!strcmp (s1: arg, s2: "DEFAULT" )) |
1430 | ret = PRAGMA_DEFAULT; |
1431 | else |
1432 | { |
1433 | warning (OPT_Wpragmas, "malformed %<#pragma %s%>, ignored" , pname); |
1434 | return PRAGMA_BAD; |
1435 | } |
1436 | |
1437 | if (pragma_lex (&t) != CPP_EOF) |
1438 | { |
1439 | warning (OPT_Wpragmas, "junk at end of %<#pragma %s%>" , pname); |
1440 | return PRAGMA_BAD; |
1441 | } |
1442 | |
1443 | return ret; |
1444 | } |
1445 | |
1446 | /* #pragma STDC FLOAT_CONST_DECIMAL64 ON |
1447 | #pragma STDC FLOAT_CONST_DECIMAL64 OFF |
1448 | #pragma STDC FLOAT_CONST_DECIMAL64 DEFAULT */ |
1449 | |
1450 | static void |
1451 | handle_pragma_float_const_decimal64 (cpp_reader *) |
1452 | { |
1453 | if (c_dialect_cxx ()) |
1454 | { |
1455 | if (warn_unknown_pragmas > in_system_header_at (loc: input_location)) |
1456 | warning (OPT_Wunknown_pragmas, |
1457 | "%<#pragma STDC FLOAT_CONST_DECIMAL64%> is not supported" |
1458 | " for C++" ); |
1459 | return; |
1460 | } |
1461 | |
1462 | if (!targetm.decimal_float_supported_p ()) |
1463 | { |
1464 | if (warn_unknown_pragmas > in_system_header_at (loc: input_location)) |
1465 | warning (OPT_Wunknown_pragmas, |
1466 | "%<#pragma STDC FLOAT_CONST_DECIMAL64%> is not supported" |
1467 | " on this target" ); |
1468 | return; |
1469 | } |
1470 | |
1471 | pedwarn (input_location, OPT_Wpedantic, |
1472 | "ISO C does not support %<#pragma STDC FLOAT_CONST_DECIMAL64%>" ); |
1473 | |
1474 | switch (handle_stdc_pragma (pname: "STDC FLOAT_CONST_DECIMAL64" )) |
1475 | { |
1476 | case PRAGMA_ON: |
1477 | set_float_const_decimal64 (); |
1478 | break; |
1479 | case PRAGMA_OFF: |
1480 | case PRAGMA_DEFAULT: |
1481 | clear_float_const_decimal64 (); |
1482 | break; |
1483 | case PRAGMA_BAD: |
1484 | break; |
1485 | } |
1486 | } |
1487 | |
1488 | /* A vector of registered pragma callbacks, which is never freed. */ |
1489 | |
1490 | static vec<internal_pragma_handler> registered_pragmas; |
1491 | |
1492 | struct pragma_pp_data |
1493 | { |
1494 | const char *space; |
1495 | const char *name; |
1496 | pragma_handler_1arg early_handler; |
1497 | }; |
1498 | |
1499 | |
1500 | static vec<pragma_pp_data> registered_pp_pragmas; |
1501 | |
1502 | struct omp_pragma_def { const char *name; unsigned int id; }; |
1503 | static const struct omp_pragma_def oacc_pragmas[] = { |
1504 | { .name: "atomic" , .id: PRAGMA_OACC_ATOMIC }, |
1505 | { .name: "cache" , .id: PRAGMA_OACC_CACHE }, |
1506 | { .name: "data" , .id: PRAGMA_OACC_DATA }, |
1507 | { .name: "declare" , .id: PRAGMA_OACC_DECLARE }, |
1508 | { .name: "enter" , .id: PRAGMA_OACC_ENTER_DATA }, |
1509 | { .name: "exit" , .id: PRAGMA_OACC_EXIT_DATA }, |
1510 | { .name: "host_data" , .id: PRAGMA_OACC_HOST_DATA }, |
1511 | { .name: "kernels" , .id: PRAGMA_OACC_KERNELS }, |
1512 | { .name: "loop" , .id: PRAGMA_OACC_LOOP }, |
1513 | { .name: "parallel" , .id: PRAGMA_OACC_PARALLEL }, |
1514 | { .name: "routine" , .id: PRAGMA_OACC_ROUTINE }, |
1515 | { .name: "serial" , .id: PRAGMA_OACC_SERIAL }, |
1516 | { .name: "update" , .id: PRAGMA_OACC_UPDATE }, |
1517 | { .name: "wait" , .id: PRAGMA_OACC_WAIT } |
1518 | }; |
1519 | static const struct omp_pragma_def omp_pragmas[] = { |
1520 | { .name: "allocate" , .id: PRAGMA_OMP_ALLOCATE }, |
1521 | { .name: "assumes" , .id: PRAGMA_OMP_ASSUMES }, |
1522 | { .name: "atomic" , .id: PRAGMA_OMP_ATOMIC }, |
1523 | { .name: "barrier" , .id: PRAGMA_OMP_BARRIER }, |
1524 | { .name: "begin" , .id: PRAGMA_OMP_BEGIN }, |
1525 | { .name: "cancel" , .id: PRAGMA_OMP_CANCEL }, |
1526 | { .name: "cancellation" , .id: PRAGMA_OMP_CANCELLATION_POINT }, |
1527 | { .name: "critical" , .id: PRAGMA_OMP_CRITICAL }, |
1528 | { .name: "depobj" , .id: PRAGMA_OMP_DEPOBJ }, |
1529 | { .name: "error" , .id: PRAGMA_OMP_ERROR }, |
1530 | { .name: "end" , .id: PRAGMA_OMP_END }, |
1531 | { .name: "flush" , .id: PRAGMA_OMP_FLUSH }, |
1532 | { .name: "nothing" , .id: PRAGMA_OMP_NOTHING }, |
1533 | { .name: "requires" , .id: PRAGMA_OMP_REQUIRES }, |
1534 | { .name: "scope" , .id: PRAGMA_OMP_SCOPE }, |
1535 | { .name: "section" , .id: PRAGMA_OMP_SECTION }, |
1536 | { .name: "sections" , .id: PRAGMA_OMP_SECTIONS }, |
1537 | { .name: "single" , .id: PRAGMA_OMP_SINGLE }, |
1538 | { .name: "task" , .id: PRAGMA_OMP_TASK }, |
1539 | { .name: "taskgroup" , .id: PRAGMA_OMP_TASKGROUP }, |
1540 | { .name: "taskwait" , .id: PRAGMA_OMP_TASKWAIT }, |
1541 | { .name: "taskyield" , .id: PRAGMA_OMP_TASKYIELD }, |
1542 | { .name: "threadprivate" , .id: PRAGMA_OMP_THREADPRIVATE } |
1543 | }; |
1544 | static const struct omp_pragma_def omp_pragmas_simd[] = { |
1545 | { .name: "assume" , .id: PRAGMA_OMP_ASSUME }, |
1546 | { .name: "declare" , .id: PRAGMA_OMP_DECLARE }, |
1547 | { .name: "distribute" , .id: PRAGMA_OMP_DISTRIBUTE }, |
1548 | { .name: "for" , .id: PRAGMA_OMP_FOR }, |
1549 | { .name: "loop" , .id: PRAGMA_OMP_LOOP }, |
1550 | { .name: "masked" , .id: PRAGMA_OMP_MASKED }, |
1551 | { .name: "master" , .id: PRAGMA_OMP_MASTER }, |
1552 | { .name: "ordered" , .id: PRAGMA_OMP_ORDERED }, |
1553 | { .name: "parallel" , .id: PRAGMA_OMP_PARALLEL }, |
1554 | { .name: "scan" , .id: PRAGMA_OMP_SCAN }, |
1555 | { .name: "simd" , .id: PRAGMA_OMP_SIMD }, |
1556 | { .name: "target" , .id: PRAGMA_OMP_TARGET }, |
1557 | { .name: "taskloop" , .id: PRAGMA_OMP_TASKLOOP }, |
1558 | { .name: "teams" , .id: PRAGMA_OMP_TEAMS }, |
1559 | }; |
1560 | |
1561 | void |
1562 | c_pp_lookup_pragma (unsigned int id, const char **space, const char **name) |
1563 | { |
1564 | const int n_oacc_pragmas = ARRAY_SIZE (oacc_pragmas); |
1565 | const int n_omp_pragmas = ARRAY_SIZE (omp_pragmas); |
1566 | const int n_omp_pragmas_simd = sizeof (omp_pragmas_simd) |
1567 | / sizeof (*omp_pragmas); |
1568 | int i; |
1569 | |
1570 | for (i = 0; i < n_oacc_pragmas; ++i) |
1571 | if (oacc_pragmas[i].id == id) |
1572 | { |
1573 | *space = "acc" ; |
1574 | *name = oacc_pragmas[i].name; |
1575 | return; |
1576 | } |
1577 | |
1578 | for (i = 0; i < n_omp_pragmas; ++i) |
1579 | if (omp_pragmas[i].id == id) |
1580 | { |
1581 | *space = "omp" ; |
1582 | *name = omp_pragmas[i].name; |
1583 | return; |
1584 | } |
1585 | |
1586 | for (i = 0; i < n_omp_pragmas_simd; ++i) |
1587 | if (omp_pragmas_simd[i].id == id) |
1588 | { |
1589 | *space = "omp" ; |
1590 | *name = omp_pragmas_simd[i].name; |
1591 | return; |
1592 | } |
1593 | |
1594 | if (id >= PRAGMA_FIRST_EXTERNAL |
1595 | && (id < PRAGMA_FIRST_EXTERNAL + registered_pp_pragmas.length ())) |
1596 | { |
1597 | *space = registered_pp_pragmas[id - PRAGMA_FIRST_EXTERNAL].space; |
1598 | *name = registered_pp_pragmas[id - PRAGMA_FIRST_EXTERNAL].name; |
1599 | return; |
1600 | } |
1601 | |
1602 | gcc_unreachable (); |
1603 | } |
1604 | |
1605 | /* Front-end wrappers for pragma registration to avoid dragging |
1606 | cpplib.h in almost everywhere. */ |
1607 | |
1608 | static void |
1609 | c_register_pragma_1 (const char *space, const char *name, |
1610 | internal_pragma_handler ihandler, bool allow_expansion) |
1611 | { |
1612 | unsigned id; |
1613 | |
1614 | if (flag_preprocess_only) |
1615 | { |
1616 | if (cpp_get_options (parse_in)->directives_only |
1617 | || !(allow_expansion || ihandler.early_handler.handler_1arg)) |
1618 | return; |
1619 | |
1620 | pragma_pp_data pp_data; |
1621 | pp_data.space = space; |
1622 | pp_data.name = name; |
1623 | pp_data.early_handler = ihandler.early_handler.handler_1arg; |
1624 | registered_pp_pragmas.safe_push (obj: pp_data); |
1625 | id = registered_pp_pragmas.length (); |
1626 | id += PRAGMA_FIRST_EXTERNAL - 1; |
1627 | } |
1628 | else |
1629 | { |
1630 | registered_pragmas.safe_push (obj: ihandler); |
1631 | id = registered_pragmas.length (); |
1632 | id += PRAGMA_FIRST_EXTERNAL - 1; |
1633 | |
1634 | /* The C front end allocates 8 bits in c_token. The C++ front end |
1635 | keeps the pragma kind in the form of INTEGER_CST, so no small |
1636 | limit applies. At present this is sufficient. */ |
1637 | gcc_assert (id < 256); |
1638 | } |
1639 | |
1640 | cpp_register_deferred_pragma (parse_in, space, name, id, |
1641 | allow_expansion, false); |
1642 | } |
1643 | |
1644 | /* Register a C pragma handler, using a space and a name. It disallows pragma |
1645 | expansion (if you want it, use c_register_pragma_with_expansion instead). */ |
1646 | void |
1647 | c_register_pragma (const char *space, const char *name, |
1648 | pragma_handler_1arg handler) |
1649 | { |
1650 | c_register_pragma_with_early_handler (space, name, handler, early_handler: nullptr); |
1651 | } |
1652 | void c_register_pragma_with_early_handler (const char *space, const char *name, |
1653 | pragma_handler_1arg handler, |
1654 | pragma_handler_1arg early_handler) |
1655 | { |
1656 | internal_pragma_handler ihandler; |
1657 | |
1658 | ihandler.handler.handler_1arg = handler; |
1659 | ihandler.early_handler.handler_1arg = early_handler; |
1660 | ihandler.extra_data = false; |
1661 | ihandler.data = NULL; |
1662 | c_register_pragma_1 (space, name, ihandler, allow_expansion: false); |
1663 | } |
1664 | |
1665 | /* Register a C pragma handler, using a space and a name, it also carries an |
1666 | extra data field which can be used by the handler. It disallows pragma |
1667 | expansion (if you want it, use c_register_pragma_with_expansion_and_data |
1668 | instead). */ |
1669 | void |
1670 | c_register_pragma_with_data (const char *space, const char *name, |
1671 | pragma_handler_2arg handler, void * data) |
1672 | { |
1673 | internal_pragma_handler ihandler; |
1674 | |
1675 | ihandler.handler.handler_2arg = handler; |
1676 | ihandler.early_handler.handler_2arg = nullptr; |
1677 | ihandler.extra_data = true; |
1678 | ihandler.data = data; |
1679 | c_register_pragma_1 (space, name, ihandler, allow_expansion: false); |
1680 | } |
1681 | |
1682 | /* Register a C pragma handler, using a space and a name. It allows pragma |
1683 | expansion as in the following example: |
1684 | |
1685 | #define NUMBER 10 |
1686 | #pragma count (NUMBER) |
1687 | |
1688 | Name expansion is still disallowed. */ |
1689 | void |
1690 | c_register_pragma_with_expansion (const char *space, const char *name, |
1691 | pragma_handler_1arg handler) |
1692 | { |
1693 | internal_pragma_handler ihandler; |
1694 | |
1695 | ihandler.handler.handler_1arg = handler; |
1696 | ihandler.early_handler.handler_1arg = nullptr; |
1697 | ihandler.extra_data = false; |
1698 | ihandler.data = NULL; |
1699 | c_register_pragma_1 (space, name, ihandler, allow_expansion: true); |
1700 | } |
1701 | |
1702 | /* Register a C pragma handler, using a space and a name, it also carries an |
1703 | extra data field which can be used by the handler. It allows pragma |
1704 | expansion as in the following example: |
1705 | |
1706 | #define NUMBER 10 |
1707 | #pragma count (NUMBER) |
1708 | |
1709 | Name expansion is still disallowed. */ |
1710 | void |
1711 | c_register_pragma_with_expansion_and_data (const char *space, const char *name, |
1712 | pragma_handler_2arg handler, |
1713 | void *data) |
1714 | { |
1715 | internal_pragma_handler ihandler; |
1716 | |
1717 | ihandler.handler.handler_2arg = handler; |
1718 | ihandler.early_handler.handler_2arg = nullptr; |
1719 | ihandler.extra_data = true; |
1720 | ihandler.data = data; |
1721 | c_register_pragma_1 (space, name, ihandler, allow_expansion: true); |
1722 | } |
1723 | |
1724 | void |
1725 | c_invoke_pragma_handler (unsigned int id) |
1726 | { |
1727 | internal_pragma_handler *ihandler; |
1728 | pragma_handler_1arg handler_1arg; |
1729 | pragma_handler_2arg handler_2arg; |
1730 | |
1731 | id -= PRAGMA_FIRST_EXTERNAL; |
1732 | ihandler = ®istered_pragmas[id]; |
1733 | if (ihandler->extra_data) |
1734 | { |
1735 | handler_2arg = ihandler->handler.handler_2arg; |
1736 | handler_2arg (parse_in, ihandler->data); |
1737 | } |
1738 | else |
1739 | { |
1740 | handler_1arg = ihandler->handler.handler_1arg; |
1741 | handler_1arg (parse_in); |
1742 | } |
1743 | } |
1744 | |
1745 | /* In contrast to the normal handler, the early handler is optional. */ |
1746 | void |
1747 | c_invoke_early_pragma_handler (unsigned int id) |
1748 | { |
1749 | internal_pragma_handler *ihandler; |
1750 | pragma_handler_1arg handler_1arg; |
1751 | pragma_handler_2arg handler_2arg; |
1752 | |
1753 | id -= PRAGMA_FIRST_EXTERNAL; |
1754 | ihandler = ®istered_pragmas[id]; |
1755 | if (ihandler->extra_data) |
1756 | { |
1757 | handler_2arg = ihandler->early_handler.handler_2arg; |
1758 | if (handler_2arg) |
1759 | handler_2arg (parse_in, ihandler->data); |
1760 | } |
1761 | else |
1762 | { |
1763 | handler_1arg = ihandler->early_handler.handler_1arg; |
1764 | if (handler_1arg) |
1765 | handler_1arg (parse_in); |
1766 | } |
1767 | } |
1768 | |
1769 | void |
1770 | c_pp_invoke_early_pragma_handler (unsigned int id) |
1771 | { |
1772 | const auto data = ®istered_pp_pragmas[id - PRAGMA_FIRST_EXTERNAL]; |
1773 | if (data->early_handler) |
1774 | { |
1775 | data->early_handler (parse_in); |
1776 | pragma_lex_discard_to_eol (); |
1777 | } |
1778 | } |
1779 | |
1780 | /* Set up front-end pragmas. */ |
1781 | void |
1782 | init_pragma (void) |
1783 | { |
1784 | |
1785 | if (!cpp_get_options (parse_in)->directives_only) |
1786 | { |
1787 | if (flag_openacc) |
1788 | { |
1789 | const int n_oacc_pragmas = ARRAY_SIZE (oacc_pragmas); |
1790 | int i; |
1791 | |
1792 | for (i = 0; i < n_oacc_pragmas; ++i) |
1793 | cpp_register_deferred_pragma (parse_in, "acc" , oacc_pragmas[i].name, |
1794 | oacc_pragmas[i].id, true, true); |
1795 | } |
1796 | |
1797 | if (flag_openmp) |
1798 | { |
1799 | const int n_omp_pragmas = ARRAY_SIZE (omp_pragmas); |
1800 | int i; |
1801 | |
1802 | for (i = 0; i < n_omp_pragmas; ++i) |
1803 | cpp_register_deferred_pragma (parse_in, "omp" , omp_pragmas[i].name, |
1804 | omp_pragmas[i].id, true, true); |
1805 | } |
1806 | if (flag_openmp || flag_openmp_simd) |
1807 | { |
1808 | const int n_omp_pragmas_simd |
1809 | = sizeof (omp_pragmas_simd) / sizeof (*omp_pragmas); |
1810 | int i; |
1811 | |
1812 | for (i = 0; i < n_omp_pragmas_simd; ++i) |
1813 | cpp_register_deferred_pragma (parse_in, "omp" , |
1814 | omp_pragmas_simd[i].name, |
1815 | omp_pragmas_simd[i].id, true, true); |
1816 | } |
1817 | } |
1818 | |
1819 | if (!flag_preprocess_only) |
1820 | cpp_register_deferred_pragma (parse_in, "GCC" , "pch_preprocess" , |
1821 | PRAGMA_GCC_PCH_PREPROCESS, false, false); |
1822 | |
1823 | if (!flag_preprocess_only) |
1824 | cpp_register_deferred_pragma (parse_in, "GCC" , "ivdep" , PRAGMA_IVDEP, false, |
1825 | false); |
1826 | |
1827 | if (!flag_preprocess_only) |
1828 | cpp_register_deferred_pragma (parse_in, "GCC" , "unroll" , PRAGMA_UNROLL, |
1829 | false, false); |
1830 | |
1831 | if (!flag_preprocess_only) |
1832 | cpp_register_deferred_pragma (parse_in, "GCC" , "novector" , PRAGMA_NOVECTOR, |
1833 | false, false); |
1834 | |
1835 | #ifdef HANDLE_PRAGMA_PACK_WITH_EXPANSION |
1836 | c_register_pragma_with_expansion (0, "pack" , handle_pragma_pack); |
1837 | #else |
1838 | c_register_pragma (space: 0, name: "pack" , handler: handle_pragma_pack); |
1839 | #endif |
1840 | c_register_pragma (space: 0, name: "weak" , handler: handle_pragma_weak); |
1841 | |
1842 | c_register_pragma (space: "GCC" , name: "visibility" , handler: handle_pragma_visibility); |
1843 | |
1844 | if (flag_preprocess_only) |
1845 | c_register_pragma_with_early_handler (space: "GCC" , name: "diagnostic" , |
1846 | handler: nullptr, |
1847 | early_handler: handle_pragma_diagnostic_early_pp); |
1848 | else |
1849 | c_register_pragma_with_early_handler (space: "GCC" , name: "diagnostic" , |
1850 | handler: handle_pragma_diagnostic, |
1851 | early_handler: handle_pragma_diagnostic_early); |
1852 | c_register_pragma_with_early_handler (space: "GCC" , name: "target" , |
1853 | handler: handle_pragma_target, |
1854 | early_handler: handle_pragma_target); |
1855 | c_register_pragma (space: "GCC" , name: "optimize" , handler: handle_pragma_optimize); |
1856 | c_register_pragma_with_early_handler (space: "GCC" , name: "push_options" , |
1857 | handler: handle_pragma_push_options, |
1858 | early_handler: handle_pragma_push_options); |
1859 | c_register_pragma_with_early_handler (space: "GCC" , name: "pop_options" , |
1860 | handler: handle_pragma_pop_options, |
1861 | early_handler: handle_pragma_pop_options); |
1862 | c_register_pragma_with_early_handler (space: "GCC" , name: "reset_options" , |
1863 | handler: handle_pragma_reset_options, |
1864 | early_handler: handle_pragma_reset_options); |
1865 | |
1866 | c_register_pragma (space: 0, name: "region" , handler: handle_pragma_ignore); |
1867 | c_register_pragma (space: 0, name: "endregion" , handler: handle_pragma_ignore); |
1868 | |
1869 | c_register_pragma (space: "STDC" , name: "FLOAT_CONST_DECIMAL64" , |
1870 | handler: handle_pragma_float_const_decimal64); |
1871 | |
1872 | c_register_pragma_with_expansion (space: 0, name: "redefine_extname" , |
1873 | handler: handle_pragma_redefine_extname); |
1874 | |
1875 | c_register_pragma_with_expansion (space: 0, name: "message" , handler: handle_pragma_message); |
1876 | |
1877 | #ifdef REGISTER_TARGET_PRAGMAS |
1878 | REGISTER_TARGET_PRAGMAS (); |
1879 | #endif |
1880 | |
1881 | global_sso = default_sso; |
1882 | c_register_pragma (space: 0, name: "scalar_storage_order" , |
1883 | handler: handle_pragma_scalar_storage_order); |
1884 | |
1885 | /* Allow plugins to register their own pragmas. */ |
1886 | invoke_plugin_callbacks (event: PLUGIN_PRAGMAS, NULL); |
1887 | } |
1888 | |
1889 | #include "gt-c-family-c-pragma.h" |
1890 | |