1 | /* Command line option handling. |
2 | Copyright (C) 2002-2023 Free Software Foundation, Inc. |
3 | Contributed by Neil Booth. |
4 | |
5 | This file is part of GCC. |
6 | |
7 | GCC is free software; you can redistribute it and/or modify it under |
8 | the terms of the GNU General Public License as published by the Free |
9 | Software Foundation; either version 3, or (at your option) any later |
10 | version. |
11 | |
12 | GCC is distributed in the hope that it will be useful, but WITHOUT ANY |
13 | WARRANTY; without even the implied warranty of MERCHANTABILITY or |
14 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
15 | for more details. |
16 | |
17 | You should have received a copy of the GNU General Public License |
18 | along with GCC; see the file COPYING3. If not see |
19 | <http://www.gnu.org/licenses/>. */ |
20 | |
21 | #include "config.h" |
22 | #include "system.h" |
23 | #include "intl.h" |
24 | #include "coretypes.h" |
25 | #include "opts.h" |
26 | #include "tm.h" |
27 | #include "flags.h" |
28 | #include "diagnostic.h" |
29 | #include "opts-diagnostic.h" |
30 | #include "insn-attr-common.h" |
31 | #include "common/common-target.h" |
32 | #include "spellcheck.h" |
33 | #include "opt-suggestions.h" |
34 | #include "diagnostic-color.h" |
35 | #include "version.h" |
36 | #include "selftest.h" |
37 | #include "file-prefix-map.h" |
38 | |
39 | /* In this file all option sets are explicit. */ |
40 | #undef OPTION_SET_P |
41 | |
42 | /* Set by -fcanon-prefix-map. */ |
43 | bool flag_canon_prefix_map; |
44 | |
45 | static void set_Wstrict_aliasing (struct gcc_options *opts, int onoff); |
46 | |
47 | /* Names of fundamental debug info formats indexed by enum |
48 | debug_info_type. */ |
49 | |
50 | const char *const debug_type_names[] = |
51 | { |
52 | "none" , "dwarf-2" , "vms" , "ctf" , "btf" |
53 | }; |
54 | |
55 | /* Bitmasks of fundamental debug info formats indexed by enum |
56 | debug_info_type. */ |
57 | |
58 | static uint32_t debug_type_masks[] = |
59 | { |
60 | NO_DEBUG, DWARF2_DEBUG, VMS_DEBUG, |
61 | CTF_DEBUG, BTF_DEBUG |
62 | }; |
63 | |
64 | /* Names of the set of debug formats requested by user. Updated and accessed |
65 | via debug_set_names. */ |
66 | |
67 | static char df_set_names[sizeof "none dwarf-2 vms ctf btf" ]; |
68 | |
69 | /* Get enum debug_info_type of the specified debug format, for error messages. |
70 | Can be used only for individual debug format types. */ |
71 | |
72 | enum debug_info_type |
73 | debug_set_to_format (uint32_t debug_info_set) |
74 | { |
75 | int idx = 0; |
76 | enum debug_info_type dinfo_type = DINFO_TYPE_NONE; |
77 | /* Find first set bit. */ |
78 | if (debug_info_set) |
79 | idx = exact_log2 (x: debug_info_set & - debug_info_set); |
80 | /* Check that only one bit is set, if at all. This function is meant to be |
81 | used only for vanilla debug_info_set bitmask values, i.e. for individual |
82 | debug format types upto DINFO_TYPE_MAX. */ |
83 | gcc_assert ((debug_info_set & (debug_info_set - 1)) == 0); |
84 | dinfo_type = (enum debug_info_type)idx; |
85 | gcc_assert (dinfo_type <= DINFO_TYPE_MAX); |
86 | return dinfo_type; |
87 | } |
88 | |
89 | /* Get the number of debug formats enabled for output. */ |
90 | |
91 | unsigned int |
92 | debug_set_count (uint32_t w_symbols) |
93 | { |
94 | unsigned int count = 0; |
95 | while (w_symbols) |
96 | { |
97 | ++ count; |
98 | w_symbols &= ~ (w_symbols & - w_symbols); |
99 | } |
100 | return count; |
101 | } |
102 | |
103 | /* Get the names of the debug formats enabled for output. */ |
104 | |
105 | const char * |
106 | debug_set_names (uint32_t w_symbols) |
107 | { |
108 | uint32_t df_mask = 0; |
109 | /* Reset the string to be returned. */ |
110 | memset (s: df_set_names, c: 0, n: sizeof (df_set_names)); |
111 | /* Get the popcount. */ |
112 | int num_set_df = debug_set_count (w_symbols); |
113 | /* Iterate over the debug formats. Add name string for those enabled. */ |
114 | for (int i = DINFO_TYPE_NONE; i <= DINFO_TYPE_MAX; i++) |
115 | { |
116 | df_mask = debug_type_masks[i]; |
117 | if (w_symbols & df_mask) |
118 | { |
119 | strcat (dest: df_set_names, src: debug_type_names[i]); |
120 | num_set_df--; |
121 | if (num_set_df) |
122 | strcat (dest: df_set_names, src: " " ); |
123 | else |
124 | break; |
125 | } |
126 | else if (!w_symbols) |
127 | { |
128 | /* No debug formats enabled. */ |
129 | gcc_assert (i == DINFO_TYPE_NONE); |
130 | strcat (dest: df_set_names, src: debug_type_names[i]); |
131 | break; |
132 | } |
133 | } |
134 | return df_set_names; |
135 | } |
136 | |
137 | /* Return TRUE iff BTF debug info is enabled. */ |
138 | |
139 | bool |
140 | btf_debuginfo_p () |
141 | { |
142 | return (write_symbols & BTF_DEBUG); |
143 | } |
144 | |
145 | /* Return TRUE iff BTF with CO-RE debug info is enabled. */ |
146 | |
147 | bool |
148 | btf_with_core_debuginfo_p () |
149 | { |
150 | return (write_symbols & BTF_WITH_CORE_DEBUG); |
151 | } |
152 | |
153 | /* Return TRUE iff CTF debug info is enabled. */ |
154 | |
155 | bool |
156 | ctf_debuginfo_p () |
157 | { |
158 | return (write_symbols & CTF_DEBUG); |
159 | } |
160 | |
161 | /* Return TRUE iff dwarf2 debug info is enabled. */ |
162 | |
163 | bool |
164 | dwarf_debuginfo_p (struct gcc_options *opts) |
165 | { |
166 | return (opts->x_write_symbols & DWARF2_DEBUG); |
167 | } |
168 | |
169 | /* Return true iff the debug info format is to be generated based on DWARF |
170 | DIEs (like CTF and BTF debug info formats). */ |
171 | |
172 | bool dwarf_based_debuginfo_p () |
173 | { |
174 | return ((write_symbols & CTF_DEBUG) |
175 | || (write_symbols & BTF_DEBUG)); |
176 | } |
177 | |
178 | /* All flag uses below need to explicitely reference the option sets |
179 | to operate on. */ |
180 | #define global_options DO_NOT_USE |
181 | #define global_options_set DO_NOT_USE |
182 | |
183 | /* Parse the -femit-struct-debug-detailed option value |
184 | and set the flag variables. */ |
185 | |
186 | #define MATCH( prefix, string ) \ |
187 | ((strncmp (prefix, string, sizeof prefix - 1) == 0) \ |
188 | ? ((string += sizeof prefix - 1), 1) : 0) |
189 | |
190 | void |
191 | set_struct_debug_option (struct gcc_options *opts, location_t loc, |
192 | const char *spec) |
193 | { |
194 | /* various labels for comparison */ |
195 | static const char dfn_lbl[] = "dfn:" , dir_lbl[] = "dir:" , ind_lbl[] = "ind:" ; |
196 | static const char ord_lbl[] = "ord:" , gen_lbl[] = "gen:" ; |
197 | static const char none_lbl[] = "none" , any_lbl[] = "any" ; |
198 | static const char base_lbl[] = "base" , sys_lbl[] = "sys" ; |
199 | |
200 | enum debug_struct_file files = DINFO_STRUCT_FILE_ANY; |
201 | /* Default is to apply to as much as possible. */ |
202 | enum debug_info_usage usage = DINFO_USAGE_NUM_ENUMS; |
203 | int ord = 1, gen = 1; |
204 | |
205 | /* What usage? */ |
206 | if (MATCH (dfn_lbl, spec)) |
207 | usage = DINFO_USAGE_DFN; |
208 | else if (MATCH (dir_lbl, spec)) |
209 | usage = DINFO_USAGE_DIR_USE; |
210 | else if (MATCH (ind_lbl, spec)) |
211 | usage = DINFO_USAGE_IND_USE; |
212 | |
213 | /* Generics or not? */ |
214 | if (MATCH (ord_lbl, spec)) |
215 | gen = 0; |
216 | else if (MATCH (gen_lbl, spec)) |
217 | ord = 0; |
218 | |
219 | /* What allowable environment? */ |
220 | if (MATCH (none_lbl, spec)) |
221 | files = DINFO_STRUCT_FILE_NONE; |
222 | else if (MATCH (any_lbl, spec)) |
223 | files = DINFO_STRUCT_FILE_ANY; |
224 | else if (MATCH (sys_lbl, spec)) |
225 | files = DINFO_STRUCT_FILE_SYS; |
226 | else if (MATCH (base_lbl, spec)) |
227 | files = DINFO_STRUCT_FILE_BASE; |
228 | else |
229 | error_at (loc, |
230 | "argument %qs to %<-femit-struct-debug-detailed%> " |
231 | "not recognized" , |
232 | spec); |
233 | |
234 | /* Effect the specification. */ |
235 | if (usage == DINFO_USAGE_NUM_ENUMS) |
236 | { |
237 | if (ord) |
238 | { |
239 | opts->x_debug_struct_ordinary[DINFO_USAGE_DFN] = files; |
240 | opts->x_debug_struct_ordinary[DINFO_USAGE_DIR_USE] = files; |
241 | opts->x_debug_struct_ordinary[DINFO_USAGE_IND_USE] = files; |
242 | } |
243 | if (gen) |
244 | { |
245 | opts->x_debug_struct_generic[DINFO_USAGE_DFN] = files; |
246 | opts->x_debug_struct_generic[DINFO_USAGE_DIR_USE] = files; |
247 | opts->x_debug_struct_generic[DINFO_USAGE_IND_USE] = files; |
248 | } |
249 | } |
250 | else |
251 | { |
252 | if (ord) |
253 | opts->x_debug_struct_ordinary[usage] = files; |
254 | if (gen) |
255 | opts->x_debug_struct_generic[usage] = files; |
256 | } |
257 | |
258 | if (*spec == ',') |
259 | set_struct_debug_option (opts, loc, spec: spec+1); |
260 | else |
261 | { |
262 | /* No more -femit-struct-debug-detailed specifications. |
263 | Do final checks. */ |
264 | if (*spec != '\0') |
265 | error_at (loc, |
266 | "argument %qs to %<-femit-struct-debug-detailed%> unknown" , |
267 | spec); |
268 | if (opts->x_debug_struct_ordinary[DINFO_USAGE_DIR_USE] |
269 | < opts->x_debug_struct_ordinary[DINFO_USAGE_IND_USE] |
270 | || opts->x_debug_struct_generic[DINFO_USAGE_DIR_USE] |
271 | < opts->x_debug_struct_generic[DINFO_USAGE_IND_USE]) |
272 | error_at (loc, |
273 | "%<-femit-struct-debug-detailed=dir:...%> must allow " |
274 | "at least as much as " |
275 | "%<-femit-struct-debug-detailed=ind:...%>" ); |
276 | } |
277 | } |
278 | |
279 | /* Strip off a legitimate source ending from the input string NAME of |
280 | length LEN. Rather than having to know the names used by all of |
281 | our front ends, we strip off an ending of a period followed by |
282 | up to fource characters. (C++ uses ".cpp".) */ |
283 | |
284 | void |
285 | strip_off_ending (char *name, int len) |
286 | { |
287 | int i; |
288 | for (i = 2; i < 5 && len > i; i++) |
289 | { |
290 | if (name[len - i] == '.') |
291 | { |
292 | name[len - i] = '\0'; |
293 | break; |
294 | } |
295 | } |
296 | } |
297 | |
298 | /* Find the base name of a path, stripping off both directories and |
299 | a single final extension. */ |
300 | int |
301 | base_of_path (const char *path, const char **base_out) |
302 | { |
303 | const char *base = path; |
304 | const char *dot = 0; |
305 | const char *p = path; |
306 | char c = *p; |
307 | while (c) |
308 | { |
309 | if (IS_DIR_SEPARATOR (c)) |
310 | { |
311 | base = p + 1; |
312 | dot = 0; |
313 | } |
314 | else if (c == '.') |
315 | dot = p; |
316 | c = *++p; |
317 | } |
318 | if (!dot) |
319 | dot = p; |
320 | *base_out = base; |
321 | return dot - base; |
322 | } |
323 | |
324 | /* What to print when a switch has no documentation. */ |
325 | static const char undocumented_msg[] = N_("This option lacks documentation." ); |
326 | static const char use_diagnosed_msg[] = N_("Uses of this option are diagnosed." ); |
327 | |
328 | typedef char *char_p; /* For DEF_VEC_P. */ |
329 | |
330 | static void set_debug_level (uint32_t dinfo, int extended, |
331 | const char *arg, struct gcc_options *opts, |
332 | struct gcc_options *opts_set, |
333 | location_t loc); |
334 | static void set_fast_math_flags (struct gcc_options *opts, int set); |
335 | static void decode_d_option (const char *arg, struct gcc_options *opts, |
336 | location_t loc, diagnostic_context *dc); |
337 | static void set_unsafe_math_optimizations_flags (struct gcc_options *opts, |
338 | int set); |
339 | static void enable_warning_as_error (const char *arg, int value, |
340 | unsigned int lang_mask, |
341 | const struct cl_option_handlers *handlers, |
342 | struct gcc_options *opts, |
343 | struct gcc_options *opts_set, |
344 | location_t loc, |
345 | diagnostic_context *dc); |
346 | |
347 | /* Handle a back-end option; arguments and return value as for |
348 | handle_option. */ |
349 | |
350 | bool |
351 | target_handle_option (struct gcc_options *opts, |
352 | struct gcc_options *opts_set, |
353 | const struct cl_decoded_option *decoded, |
354 | unsigned int lang_mask ATTRIBUTE_UNUSED, int kind, |
355 | location_t loc, |
356 | const struct cl_option_handlers *handlers ATTRIBUTE_UNUSED, |
357 | diagnostic_context *dc, void (*) (void)) |
358 | { |
359 | gcc_assert (dc == global_dc); |
360 | gcc_assert (kind == DK_UNSPECIFIED); |
361 | return targetm_common.handle_option (opts, opts_set, decoded, loc); |
362 | } |
363 | |
364 | /* Add comma-separated strings to a char_p vector. */ |
365 | |
366 | static void |
367 | add_comma_separated_to_vector (void **pvec, const char *arg) |
368 | { |
369 | char *tmp; |
370 | char *r; |
371 | char *w; |
372 | char *token_start; |
373 | vec<char_p> *v = (vec<char_p> *) *pvec; |
374 | |
375 | vec_check_alloc (vec&: v, nelems: 1); |
376 | |
377 | /* We never free this string. */ |
378 | tmp = xstrdup (arg); |
379 | |
380 | r = tmp; |
381 | w = tmp; |
382 | token_start = tmp; |
383 | |
384 | while (*r != '\0') |
385 | { |
386 | if (*r == ',') |
387 | { |
388 | *w++ = '\0'; |
389 | ++r; |
390 | v->safe_push (obj: token_start); |
391 | token_start = w; |
392 | } |
393 | if (*r == '\\' && r[1] == ',') |
394 | { |
395 | *w++ = ','; |
396 | r += 2; |
397 | } |
398 | else |
399 | *w++ = *r++; |
400 | } |
401 | |
402 | *w = '\0'; |
403 | if (*token_start != '\0') |
404 | v->safe_push (obj: token_start); |
405 | |
406 | *pvec = v; |
407 | } |
408 | |
409 | /* Initialize opts_obstack. */ |
410 | |
411 | void |
412 | init_opts_obstack (void) |
413 | { |
414 | gcc_obstack_init (&opts_obstack); |
415 | } |
416 | |
417 | /* Initialize OPTS and OPTS_SET before using them in parsing options. */ |
418 | |
419 | void |
420 | init_options_struct (struct gcc_options *opts, struct gcc_options *opts_set) |
421 | { |
422 | /* Ensure that opts_obstack has already been initialized by the time |
423 | that we initialize any gcc_options instances (PR jit/68446). */ |
424 | gcc_assert (opts_obstack.chunk_size > 0); |
425 | |
426 | *opts = global_options_init; |
427 | |
428 | if (opts_set) |
429 | memset (s: opts_set, c: 0, n: sizeof (*opts_set)); |
430 | |
431 | /* Initialize whether `char' is signed. */ |
432 | opts->x_flag_signed_char = DEFAULT_SIGNED_CHAR; |
433 | /* Set this to a special "uninitialized" value. The actual default |
434 | is set after target options have been processed. */ |
435 | opts->x_flag_short_enums = 2; |
436 | |
437 | /* Initialize target_flags before default_options_optimization |
438 | so the latter can modify it. */ |
439 | opts->x_target_flags = targetm_common.default_target_flags; |
440 | |
441 | /* Some targets have ABI-specified unwind tables. */ |
442 | opts->x_flag_unwind_tables = targetm_common.unwind_tables_default; |
443 | |
444 | /* Some targets have other target-specific initialization. */ |
445 | targetm_common.option_init_struct (opts); |
446 | } |
447 | |
448 | /* If indicated by the optimization level LEVEL (-Os if SIZE is set, |
449 | -Ofast if FAST is set, -Og if DEBUG is set), apply the option DEFAULT_OPT |
450 | to OPTS and OPTS_SET, diagnostic context DC, location LOC, with language |
451 | mask LANG_MASK and option handlers HANDLERS. */ |
452 | |
453 | static void |
454 | maybe_default_option (struct gcc_options *opts, |
455 | struct gcc_options *opts_set, |
456 | const struct default_options *default_opt, |
457 | int level, bool size, bool fast, bool debug, |
458 | unsigned int lang_mask, |
459 | const struct cl_option_handlers *handlers, |
460 | location_t loc, |
461 | diagnostic_context *dc) |
462 | { |
463 | const struct cl_option *option = &cl_options[default_opt->opt_index]; |
464 | bool enabled; |
465 | |
466 | if (size) |
467 | gcc_assert (level == 2); |
468 | if (fast) |
469 | gcc_assert (level == 3); |
470 | if (debug) |
471 | gcc_assert (level == 1); |
472 | |
473 | switch (default_opt->levels) |
474 | { |
475 | case OPT_LEVELS_ALL: |
476 | enabled = true; |
477 | break; |
478 | |
479 | case OPT_LEVELS_0_ONLY: |
480 | enabled = (level == 0); |
481 | break; |
482 | |
483 | case OPT_LEVELS_1_PLUS: |
484 | enabled = (level >= 1); |
485 | break; |
486 | |
487 | case OPT_LEVELS_1_PLUS_SPEED_ONLY: |
488 | enabled = (level >= 1 && !size && !debug); |
489 | break; |
490 | |
491 | case OPT_LEVELS_1_PLUS_NOT_DEBUG: |
492 | enabled = (level >= 1 && !debug); |
493 | break; |
494 | |
495 | case OPT_LEVELS_2_PLUS: |
496 | enabled = (level >= 2); |
497 | break; |
498 | |
499 | case OPT_LEVELS_2_PLUS_SPEED_ONLY: |
500 | enabled = (level >= 2 && !size && !debug); |
501 | break; |
502 | |
503 | case OPT_LEVELS_3_PLUS: |
504 | enabled = (level >= 3); |
505 | break; |
506 | |
507 | case OPT_LEVELS_3_PLUS_AND_SIZE: |
508 | enabled = (level >= 3 || size); |
509 | break; |
510 | |
511 | case OPT_LEVELS_SIZE: |
512 | enabled = size; |
513 | break; |
514 | |
515 | case OPT_LEVELS_FAST: |
516 | enabled = fast; |
517 | break; |
518 | |
519 | case OPT_LEVELS_NONE: |
520 | default: |
521 | gcc_unreachable (); |
522 | } |
523 | |
524 | if (enabled) |
525 | handle_generated_option (opts, opts_set, opt_index: default_opt->opt_index, |
526 | arg: default_opt->arg, value: default_opt->value, |
527 | lang_mask, kind: DK_UNSPECIFIED, loc, |
528 | handlers, generated_p: true, dc); |
529 | else if (default_opt->arg == NULL |
530 | && !option->cl_reject_negative |
531 | && !(option->flags & CL_PARAMS)) |
532 | handle_generated_option (opts, opts_set, opt_index: default_opt->opt_index, |
533 | arg: default_opt->arg, value: !default_opt->value, |
534 | lang_mask, kind: DK_UNSPECIFIED, loc, |
535 | handlers, generated_p: true, dc); |
536 | } |
537 | |
538 | /* As indicated by the optimization level LEVEL (-Os if SIZE is set, |
539 | -Ofast if FAST is set), apply the options in array DEFAULT_OPTS to |
540 | OPTS and OPTS_SET, diagnostic context DC, location LOC, with |
541 | language mask LANG_MASK and option handlers HANDLERS. */ |
542 | |
543 | static void |
544 | maybe_default_options (struct gcc_options *opts, |
545 | struct gcc_options *opts_set, |
546 | const struct default_options *default_opts, |
547 | int level, bool size, bool fast, bool debug, |
548 | unsigned int lang_mask, |
549 | const struct cl_option_handlers *handlers, |
550 | location_t loc, |
551 | diagnostic_context *dc) |
552 | { |
553 | size_t i; |
554 | |
555 | for (i = 0; default_opts[i].levels != OPT_LEVELS_NONE; i++) |
556 | maybe_default_option (opts, opts_set, default_opt: &default_opts[i], |
557 | level, size, fast, debug, |
558 | lang_mask, handlers, loc, dc); |
559 | } |
560 | |
561 | /* Table of options enabled by default at different levels. |
562 | Please keep this list sorted by level and alphabetized within |
563 | each level; this makes it easier to keep the documentation |
564 | in sync. */ |
565 | |
566 | static const struct default_options default_options_table[] = |
567 | { |
568 | /* -O1 and -Og optimizations. */ |
569 | { .levels: OPT_LEVELS_1_PLUS, .opt_index: OPT_fcombine_stack_adjustments, NULL, .value: 1 }, |
570 | { .levels: OPT_LEVELS_1_PLUS, .opt_index: OPT_fcompare_elim, NULL, .value: 1 }, |
571 | { .levels: OPT_LEVELS_1_PLUS, .opt_index: OPT_fcprop_registers, NULL, .value: 1 }, |
572 | { .levels: OPT_LEVELS_1_PLUS, .opt_index: OPT_fdefer_pop, NULL, .value: 1 }, |
573 | { .levels: OPT_LEVELS_1_PLUS, .opt_index: OPT_fforward_propagate, NULL, .value: 1 }, |
574 | { .levels: OPT_LEVELS_1_PLUS, .opt_index: OPT_fguess_branch_probability, NULL, .value: 1 }, |
575 | { .levels: OPT_LEVELS_1_PLUS, .opt_index: OPT_fipa_profile, NULL, .value: 1 }, |
576 | { .levels: OPT_LEVELS_1_PLUS, .opt_index: OPT_fipa_pure_const, NULL, .value: 1 }, |
577 | { .levels: OPT_LEVELS_1_PLUS, .opt_index: OPT_fipa_reference, NULL, .value: 1 }, |
578 | { .levels: OPT_LEVELS_1_PLUS, .opt_index: OPT_fipa_reference_addressable, NULL, .value: 1 }, |
579 | { .levels: OPT_LEVELS_1_PLUS, .opt_index: OPT_fmerge_constants, NULL, .value: 1 }, |
580 | { .levels: OPT_LEVELS_1_PLUS, .opt_index: OPT_fomit_frame_pointer, NULL, .value: 1 }, |
581 | { .levels: OPT_LEVELS_1_PLUS, .opt_index: OPT_freorder_blocks, NULL, .value: 1 }, |
582 | { .levels: OPT_LEVELS_1_PLUS, .opt_index: OPT_fshrink_wrap, NULL, .value: 1 }, |
583 | { .levels: OPT_LEVELS_1_PLUS, .opt_index: OPT_fsplit_wide_types, NULL, .value: 1 }, |
584 | { .levels: OPT_LEVELS_1_PLUS, .opt_index: OPT_fthread_jumps, NULL, .value: 1 }, |
585 | { .levels: OPT_LEVELS_1_PLUS, .opt_index: OPT_ftree_builtin_call_dce, NULL, .value: 1 }, |
586 | { .levels: OPT_LEVELS_1_PLUS, .opt_index: OPT_ftree_ccp, NULL, .value: 1 }, |
587 | { .levels: OPT_LEVELS_1_PLUS, .opt_index: OPT_ftree_ch, NULL, .value: 1 }, |
588 | { .levels: OPT_LEVELS_1_PLUS, .opt_index: OPT_ftree_coalesce_vars, NULL, .value: 1 }, |
589 | { .levels: OPT_LEVELS_1_PLUS, .opt_index: OPT_ftree_copy_prop, NULL, .value: 1 }, |
590 | { .levels: OPT_LEVELS_1_PLUS, .opt_index: OPT_ftree_dce, NULL, .value: 1 }, |
591 | { .levels: OPT_LEVELS_1_PLUS, .opt_index: OPT_ftree_dominator_opts, NULL, .value: 1 }, |
592 | { .levels: OPT_LEVELS_1_PLUS, .opt_index: OPT_ftree_fre, NULL, .value: 1 }, |
593 | { .levels: OPT_LEVELS_1_PLUS, .opt_index: OPT_ftree_sink, NULL, .value: 1 }, |
594 | { .levels: OPT_LEVELS_1_PLUS, .opt_index: OPT_ftree_slsr, NULL, .value: 1 }, |
595 | { .levels: OPT_LEVELS_1_PLUS, .opt_index: OPT_ftree_ter, NULL, .value: 1 }, |
596 | { .levels: OPT_LEVELS_1_PLUS, .opt_index: OPT_fvar_tracking, NULL, .value: 1 }, |
597 | |
598 | /* -O1 (and not -Og) optimizations. */ |
599 | { .levels: OPT_LEVELS_1_PLUS_NOT_DEBUG, .opt_index: OPT_fbranch_count_reg, NULL, .value: 1 }, |
600 | #if DELAY_SLOTS |
601 | { OPT_LEVELS_1_PLUS_NOT_DEBUG, OPT_fdelayed_branch, NULL, 1 }, |
602 | #endif |
603 | { .levels: OPT_LEVELS_1_PLUS_NOT_DEBUG, .opt_index: OPT_fdse, NULL, .value: 1 }, |
604 | { .levels: OPT_LEVELS_1_PLUS_NOT_DEBUG, .opt_index: OPT_fif_conversion, NULL, .value: 1 }, |
605 | { .levels: OPT_LEVELS_1_PLUS_NOT_DEBUG, .opt_index: OPT_fif_conversion2, NULL, .value: 1 }, |
606 | { .levels: OPT_LEVELS_1_PLUS_NOT_DEBUG, .opt_index: OPT_finline_functions_called_once, NULL, .value: 1 }, |
607 | { .levels: OPT_LEVELS_1_PLUS_NOT_DEBUG, .opt_index: OPT_fmove_loop_invariants, NULL, .value: 1 }, |
608 | { .levels: OPT_LEVELS_1_PLUS_NOT_DEBUG, .opt_index: OPT_fmove_loop_stores, NULL, .value: 1 }, |
609 | { .levels: OPT_LEVELS_1_PLUS_NOT_DEBUG, .opt_index: OPT_fssa_phiopt, NULL, .value: 1 }, |
610 | { .levels: OPT_LEVELS_1_PLUS_NOT_DEBUG, .opt_index: OPT_fipa_modref, NULL, .value: 1 }, |
611 | { .levels: OPT_LEVELS_1_PLUS_NOT_DEBUG, .opt_index: OPT_ftree_bit_ccp, NULL, .value: 1 }, |
612 | { .levels: OPT_LEVELS_1_PLUS_NOT_DEBUG, .opt_index: OPT_ftree_dse, NULL, .value: 1 }, |
613 | { .levels: OPT_LEVELS_1_PLUS_NOT_DEBUG, .opt_index: OPT_ftree_pta, NULL, .value: 1 }, |
614 | { .levels: OPT_LEVELS_1_PLUS_NOT_DEBUG, .opt_index: OPT_ftree_sra, NULL, .value: 1 }, |
615 | |
616 | /* -O2 and -Os optimizations. */ |
617 | { .levels: OPT_LEVELS_2_PLUS, .opt_index: OPT_fcaller_saves, NULL, .value: 1 }, |
618 | { .levels: OPT_LEVELS_2_PLUS, .opt_index: OPT_fcode_hoisting, NULL, .value: 1 }, |
619 | { .levels: OPT_LEVELS_2_PLUS, .opt_index: OPT_fcrossjumping, NULL, .value: 1 }, |
620 | { .levels: OPT_LEVELS_2_PLUS, .opt_index: OPT_fcse_follow_jumps, NULL, .value: 1 }, |
621 | { .levels: OPT_LEVELS_2_PLUS, .opt_index: OPT_fdevirtualize, NULL, .value: 1 }, |
622 | { .levels: OPT_LEVELS_2_PLUS, .opt_index: OPT_fdevirtualize_speculatively, NULL, .value: 1 }, |
623 | { .levels: OPT_LEVELS_2_PLUS, .opt_index: OPT_fexpensive_optimizations, NULL, .value: 1 }, |
624 | { .levels: OPT_LEVELS_2_PLUS, .opt_index: OPT_fgcse, NULL, .value: 1 }, |
625 | { .levels: OPT_LEVELS_2_PLUS, .opt_index: OPT_fhoist_adjacent_loads, NULL, .value: 1 }, |
626 | { .levels: OPT_LEVELS_2_PLUS, .opt_index: OPT_findirect_inlining, NULL, .value: 1 }, |
627 | { .levels: OPT_LEVELS_2_PLUS, .opt_index: OPT_finline_small_functions, NULL, .value: 1 }, |
628 | { .levels: OPT_LEVELS_2_PLUS, .opt_index: OPT_fipa_bit_cp, NULL, .value: 1 }, |
629 | { .levels: OPT_LEVELS_2_PLUS, .opt_index: OPT_fipa_cp, NULL, .value: 1 }, |
630 | { .levels: OPT_LEVELS_2_PLUS, .opt_index: OPT_fipa_icf, NULL, .value: 1 }, |
631 | { .levels: OPT_LEVELS_2_PLUS, .opt_index: OPT_fipa_ra, NULL, .value: 1 }, |
632 | { .levels: OPT_LEVELS_2_PLUS, .opt_index: OPT_fipa_sra, NULL, .value: 1 }, |
633 | { .levels: OPT_LEVELS_2_PLUS, .opt_index: OPT_fipa_vrp, NULL, .value: 1 }, |
634 | { .levels: OPT_LEVELS_2_PLUS, .opt_index: OPT_fisolate_erroneous_paths_dereference, NULL, .value: 1 }, |
635 | { .levels: OPT_LEVELS_2_PLUS, .opt_index: OPT_flra_remat, NULL, .value: 1 }, |
636 | { .levels: OPT_LEVELS_2_PLUS, .opt_index: OPT_foptimize_sibling_calls, NULL, .value: 1 }, |
637 | { .levels: OPT_LEVELS_2_PLUS, .opt_index: OPT_fpartial_inlining, NULL, .value: 1 }, |
638 | { .levels: OPT_LEVELS_2_PLUS, .opt_index: OPT_fpeephole2, NULL, .value: 1 }, |
639 | { .levels: OPT_LEVELS_2_PLUS, .opt_index: OPT_freorder_functions, NULL, .value: 1 }, |
640 | { .levels: OPT_LEVELS_2_PLUS, .opt_index: OPT_frerun_cse_after_loop, NULL, .value: 1 }, |
641 | #ifdef INSN_SCHEDULING |
642 | { .levels: OPT_LEVELS_2_PLUS, .opt_index: OPT_fschedule_insns2, NULL, .value: 1 }, |
643 | #endif |
644 | { .levels: OPT_LEVELS_2_PLUS, .opt_index: OPT_fstrict_aliasing, NULL, .value: 1 }, |
645 | { .levels: OPT_LEVELS_2_PLUS, .opt_index: OPT_fstore_merging, NULL, .value: 1 }, |
646 | { .levels: OPT_LEVELS_2_PLUS, .opt_index: OPT_ftree_pre, NULL, .value: 1 }, |
647 | { .levels: OPT_LEVELS_2_PLUS, .opt_index: OPT_ftree_switch_conversion, NULL, .value: 1 }, |
648 | { .levels: OPT_LEVELS_2_PLUS, .opt_index: OPT_ftree_tail_merge, NULL, .value: 1 }, |
649 | { .levels: OPT_LEVELS_2_PLUS, .opt_index: OPT_ftree_vrp, NULL, .value: 1 }, |
650 | { .levels: OPT_LEVELS_2_PLUS, .opt_index: OPT_fvect_cost_model_, NULL, |
651 | .value: VECT_COST_MODEL_VERY_CHEAP }, |
652 | { .levels: OPT_LEVELS_2_PLUS, .opt_index: OPT_finline_functions, NULL, .value: 1 }, |
653 | { .levels: OPT_LEVELS_2_PLUS, .opt_index: OPT_ftree_loop_distribute_patterns, NULL, .value: 1 }, |
654 | |
655 | /* -O2 and above optimizations, but not -Os or -Og. */ |
656 | { .levels: OPT_LEVELS_2_PLUS_SPEED_ONLY, .opt_index: OPT_falign_functions, NULL, .value: 1 }, |
657 | { .levels: OPT_LEVELS_2_PLUS_SPEED_ONLY, .opt_index: OPT_falign_jumps, NULL, .value: 1 }, |
658 | { .levels: OPT_LEVELS_2_PLUS_SPEED_ONLY, .opt_index: OPT_falign_labels, NULL, .value: 1 }, |
659 | { .levels: OPT_LEVELS_2_PLUS_SPEED_ONLY, .opt_index: OPT_falign_loops, NULL, .value: 1 }, |
660 | { .levels: OPT_LEVELS_2_PLUS_SPEED_ONLY, .opt_index: OPT_foptimize_strlen, NULL, .value: 1 }, |
661 | { .levels: OPT_LEVELS_2_PLUS_SPEED_ONLY, .opt_index: OPT_freorder_blocks_algorithm_, NULL, |
662 | .value: REORDER_BLOCKS_ALGORITHM_STC }, |
663 | { .levels: OPT_LEVELS_2_PLUS_SPEED_ONLY, .opt_index: OPT_ftree_loop_vectorize, NULL, .value: 1 }, |
664 | { .levels: OPT_LEVELS_2_PLUS_SPEED_ONLY, .opt_index: OPT_ftree_slp_vectorize, NULL, .value: 1 }, |
665 | { .levels: OPT_LEVELS_2_PLUS_SPEED_ONLY, .opt_index: OPT_fopenmp_target_simd_clone_, NULL, |
666 | .value: OMP_TARGET_SIMD_CLONE_NOHOST }, |
667 | #ifdef INSN_SCHEDULING |
668 | /* Only run the pre-regalloc scheduling pass if optimizing for speed. */ |
669 | { .levels: OPT_LEVELS_2_PLUS_SPEED_ONLY, .opt_index: OPT_fschedule_insns, NULL, .value: 1 }, |
670 | #endif |
671 | |
672 | /* -O3 and -Os optimizations. */ |
673 | |
674 | /* -O3 optimizations. */ |
675 | { .levels: OPT_LEVELS_3_PLUS, .opt_index: OPT_fgcse_after_reload, NULL, .value: 1 }, |
676 | { .levels: OPT_LEVELS_3_PLUS, .opt_index: OPT_fipa_cp_clone, NULL, .value: 1 }, |
677 | { .levels: OPT_LEVELS_3_PLUS, .opt_index: OPT_floop_interchange, NULL, .value: 1 }, |
678 | { .levels: OPT_LEVELS_3_PLUS, .opt_index: OPT_floop_unroll_and_jam, NULL, .value: 1 }, |
679 | { .levels: OPT_LEVELS_3_PLUS, .opt_index: OPT_fpeel_loops, NULL, .value: 1 }, |
680 | { .levels: OPT_LEVELS_3_PLUS, .opt_index: OPT_fpredictive_commoning, NULL, .value: 1 }, |
681 | { .levels: OPT_LEVELS_3_PLUS, .opt_index: OPT_fsplit_loops, NULL, .value: 1 }, |
682 | { .levels: OPT_LEVELS_3_PLUS, .opt_index: OPT_fsplit_paths, NULL, .value: 1 }, |
683 | { .levels: OPT_LEVELS_3_PLUS, .opt_index: OPT_ftree_loop_distribution, NULL, .value: 1 }, |
684 | { .levels: OPT_LEVELS_3_PLUS, .opt_index: OPT_ftree_partial_pre, NULL, .value: 1 }, |
685 | { .levels: OPT_LEVELS_3_PLUS, .opt_index: OPT_funswitch_loops, NULL, .value: 1 }, |
686 | { .levels: OPT_LEVELS_3_PLUS, .opt_index: OPT_fvect_cost_model_, NULL, .value: VECT_COST_MODEL_DYNAMIC }, |
687 | { .levels: OPT_LEVELS_3_PLUS, .opt_index: OPT_fversion_loops_for_strides, NULL, .value: 1 }, |
688 | |
689 | /* -O3 parameters. */ |
690 | { .levels: OPT_LEVELS_3_PLUS, .opt_index: OPT__param_max_inline_insns_auto_, NULL, .value: 30 }, |
691 | { .levels: OPT_LEVELS_3_PLUS, .opt_index: OPT__param_early_inlining_insns_, NULL, .value: 14 }, |
692 | { .levels: OPT_LEVELS_3_PLUS, .opt_index: OPT__param_inline_heuristics_hint_percent_, NULL, .value: 600 }, |
693 | { .levels: OPT_LEVELS_3_PLUS, .opt_index: OPT__param_inline_min_speedup_, NULL, .value: 15 }, |
694 | { .levels: OPT_LEVELS_3_PLUS, .opt_index: OPT__param_max_inline_insns_single_, NULL, .value: 200 }, |
695 | |
696 | /* -Ofast adds optimizations to -O3. */ |
697 | { .levels: OPT_LEVELS_FAST, .opt_index: OPT_ffast_math, NULL, .value: 1 }, |
698 | { .levels: OPT_LEVELS_FAST, .opt_index: OPT_fallow_store_data_races, NULL, .value: 1 }, |
699 | { .levels: OPT_LEVELS_FAST, .opt_index: OPT_fsemantic_interposition, NULL, .value: 0 }, |
700 | |
701 | { .levels: OPT_LEVELS_NONE, .opt_index: 0, NULL, .value: 0 } |
702 | }; |
703 | |
704 | /* Default the options in OPTS and OPTS_SET based on the optimization |
705 | settings in DECODED_OPTIONS and DECODED_OPTIONS_COUNT. */ |
706 | void |
707 | default_options_optimization (struct gcc_options *opts, |
708 | struct gcc_options *opts_set, |
709 | struct cl_decoded_option *decoded_options, |
710 | unsigned int decoded_options_count, |
711 | location_t loc, |
712 | unsigned int lang_mask, |
713 | const struct cl_option_handlers *handlers, |
714 | diagnostic_context *dc) |
715 | { |
716 | unsigned int i; |
717 | int opt2; |
718 | bool openacc_mode = false; |
719 | |
720 | /* Scan to see what optimization level has been specified. That will |
721 | determine the default value of many flags. */ |
722 | for (i = 1; i < decoded_options_count; i++) |
723 | { |
724 | struct cl_decoded_option *opt = &decoded_options[i]; |
725 | switch (opt->opt_index) |
726 | { |
727 | case OPT_O: |
728 | if (*opt->arg == '\0') |
729 | { |
730 | opts->x_optimize = 1; |
731 | opts->x_optimize_size = 0; |
732 | opts->x_optimize_fast = 0; |
733 | opts->x_optimize_debug = 0; |
734 | } |
735 | else |
736 | { |
737 | const int optimize_val = integral_argument (arg: opt->arg); |
738 | if (optimize_val == -1) |
739 | error_at (loc, "argument to %<-O%> should be a non-negative " |
740 | "integer, %<g%>, %<s%>, %<z%> or %<fast%>" ); |
741 | else |
742 | { |
743 | opts->x_optimize = optimize_val; |
744 | if ((unsigned int) opts->x_optimize > 255) |
745 | opts->x_optimize = 255; |
746 | opts->x_optimize_size = 0; |
747 | opts->x_optimize_fast = 0; |
748 | opts->x_optimize_debug = 0; |
749 | } |
750 | } |
751 | break; |
752 | |
753 | case OPT_Os: |
754 | opts->x_optimize_size = 1; |
755 | |
756 | /* Optimizing for size forces optimize to be 2. */ |
757 | opts->x_optimize = 2; |
758 | opts->x_optimize_fast = 0; |
759 | opts->x_optimize_debug = 0; |
760 | break; |
761 | |
762 | case OPT_Oz: |
763 | opts->x_optimize_size = 2; |
764 | |
765 | /* Optimizing for size forces optimize to be 2. */ |
766 | opts->x_optimize = 2; |
767 | opts->x_optimize_fast = 0; |
768 | opts->x_optimize_debug = 0; |
769 | break; |
770 | |
771 | case OPT_Ofast: |
772 | /* -Ofast only adds flags to -O3. */ |
773 | opts->x_optimize_size = 0; |
774 | opts->x_optimize = 3; |
775 | opts->x_optimize_fast = 1; |
776 | opts->x_optimize_debug = 0; |
777 | break; |
778 | |
779 | case OPT_Og: |
780 | /* -Og selects optimization level 1. */ |
781 | opts->x_optimize_size = 0; |
782 | opts->x_optimize = 1; |
783 | opts->x_optimize_fast = 0; |
784 | opts->x_optimize_debug = 1; |
785 | break; |
786 | |
787 | case OPT_fopenacc: |
788 | if (opt->value) |
789 | openacc_mode = true; |
790 | break; |
791 | |
792 | default: |
793 | /* Ignore other options in this prescan. */ |
794 | break; |
795 | } |
796 | } |
797 | |
798 | maybe_default_options (opts, opts_set, default_opts: default_options_table, |
799 | level: opts->x_optimize, size: opts->x_optimize_size, |
800 | fast: opts->x_optimize_fast, debug: opts->x_optimize_debug, |
801 | lang_mask, handlers, loc, dc); |
802 | |
803 | /* -O2 param settings. */ |
804 | opt2 = (opts->x_optimize >= 2); |
805 | |
806 | if (openacc_mode) |
807 | SET_OPTION_IF_UNSET (opts, opts_set, flag_ipa_pta, true); |
808 | |
809 | /* Track fields in field-sensitive alias analysis. */ |
810 | if (opt2) |
811 | SET_OPTION_IF_UNSET (opts, opts_set, param_max_fields_for_field_sensitive, |
812 | 100); |
813 | |
814 | if (opts->x_optimize_size) |
815 | /* We want to crossjump as much as possible. */ |
816 | SET_OPTION_IF_UNSET (opts, opts_set, param_min_crossjump_insns, 1); |
817 | |
818 | /* Restrict the amount of work combine does at -Og while retaining |
819 | most of its useful transforms. */ |
820 | if (opts->x_optimize_debug) |
821 | SET_OPTION_IF_UNSET (opts, opts_set, param_max_combine_insns, 2); |
822 | |
823 | /* Allow default optimizations to be specified on a per-machine basis. */ |
824 | maybe_default_options (opts, opts_set, |
825 | default_opts: targetm_common.option_optimization_table, |
826 | level: opts->x_optimize, size: opts->x_optimize_size, |
827 | fast: opts->x_optimize_fast, debug: opts->x_optimize_debug, |
828 | lang_mask, handlers, loc, dc); |
829 | } |
830 | |
831 | /* Control IPA optimizations based on different live patching LEVEL. */ |
832 | static void |
833 | control_options_for_live_patching (struct gcc_options *opts, |
834 | struct gcc_options *opts_set, |
835 | enum live_patching_level level, |
836 | location_t loc) |
837 | { |
838 | gcc_assert (level > LIVE_PATCHING_NONE); |
839 | |
840 | switch (level) |
841 | { |
842 | case LIVE_PATCHING_INLINE_ONLY_STATIC: |
843 | #define LIVE_PATCHING_OPTION "-flive-patching=inline-only-static" |
844 | if (opts_set->x_flag_ipa_cp_clone && opts->x_flag_ipa_cp_clone) |
845 | error_at (loc, "%qs is incompatible with %qs" , |
846 | "-fipa-cp-clone" , LIVE_PATCHING_OPTION); |
847 | else |
848 | opts->x_flag_ipa_cp_clone = 0; |
849 | |
850 | if (opts_set->x_flag_ipa_sra && opts->x_flag_ipa_sra) |
851 | error_at (loc, "%qs is incompatible with %qs" , |
852 | "-fipa-sra" , LIVE_PATCHING_OPTION); |
853 | else |
854 | opts->x_flag_ipa_sra = 0; |
855 | |
856 | if (opts_set->x_flag_partial_inlining && opts->x_flag_partial_inlining) |
857 | error_at (loc, "%qs is incompatible with %qs" , |
858 | "-fpartial-inlining" , LIVE_PATCHING_OPTION); |
859 | else |
860 | opts->x_flag_partial_inlining = 0; |
861 | |
862 | if (opts_set->x_flag_ipa_cp && opts->x_flag_ipa_cp) |
863 | error_at (loc, "%qs is incompatible with %qs" , |
864 | "-fipa-cp" , LIVE_PATCHING_OPTION); |
865 | else |
866 | opts->x_flag_ipa_cp = 0; |
867 | |
868 | /* FALLTHROUGH. */ |
869 | case LIVE_PATCHING_INLINE_CLONE: |
870 | #undef LIVE_PATCHING_OPTION |
871 | #define LIVE_PATCHING_OPTION "-flive-patching=inline-only-static|inline-clone" |
872 | /* live patching should disable whole-program optimization. */ |
873 | if (opts_set->x_flag_whole_program && opts->x_flag_whole_program) |
874 | error_at (loc, "%qs is incompatible with %qs" , |
875 | "-fwhole-program" , LIVE_PATCHING_OPTION); |
876 | else |
877 | opts->x_flag_whole_program = 0; |
878 | |
879 | /* visibility change should be excluded by !flag_whole_program |
880 | && !in_lto_p && !flag_ipa_cp_clone && !flag_ipa_sra |
881 | && !flag_partial_inlining. */ |
882 | |
883 | if (opts_set->x_flag_ipa_pta && opts->x_flag_ipa_pta) |
884 | error_at (loc, "%qs is incompatible with %qs" , |
885 | "-fipa-pta" , LIVE_PATCHING_OPTION); |
886 | else |
887 | opts->x_flag_ipa_pta = 0; |
888 | |
889 | if (opts_set->x_flag_ipa_reference && opts->x_flag_ipa_reference) |
890 | error_at (loc, "%qs is incompatible with %qs" , |
891 | "-fipa-reference" , LIVE_PATCHING_OPTION); |
892 | else |
893 | opts->x_flag_ipa_reference = 0; |
894 | |
895 | if (opts_set->x_flag_ipa_ra && opts->x_flag_ipa_ra) |
896 | error_at (loc, "%qs is incompatible with %qs" , |
897 | "-fipa-ra" , LIVE_PATCHING_OPTION); |
898 | else |
899 | opts->x_flag_ipa_ra = 0; |
900 | |
901 | if (opts_set->x_flag_ipa_icf && opts->x_flag_ipa_icf) |
902 | error_at (loc, "%qs is incompatible with %qs" , |
903 | "-fipa-icf" , LIVE_PATCHING_OPTION); |
904 | else |
905 | opts->x_flag_ipa_icf = 0; |
906 | |
907 | if (opts_set->x_flag_ipa_icf_functions && opts->x_flag_ipa_icf_functions) |
908 | error_at (loc, "%qs is incompatible with %qs" , |
909 | "-fipa-icf-functions" , LIVE_PATCHING_OPTION); |
910 | else |
911 | opts->x_flag_ipa_icf_functions = 0; |
912 | |
913 | if (opts_set->x_flag_ipa_icf_variables && opts->x_flag_ipa_icf_variables) |
914 | error_at (loc, "%qs is incompatible with %qs" , |
915 | "-fipa-icf-variables" , LIVE_PATCHING_OPTION); |
916 | else |
917 | opts->x_flag_ipa_icf_variables = 0; |
918 | |
919 | if (opts_set->x_flag_ipa_bit_cp && opts->x_flag_ipa_bit_cp) |
920 | error_at (loc, "%qs is incompatible with %qs" , |
921 | "-fipa-bit-cp" , LIVE_PATCHING_OPTION); |
922 | else |
923 | opts->x_flag_ipa_bit_cp = 0; |
924 | |
925 | if (opts_set->x_flag_ipa_vrp && opts->x_flag_ipa_vrp) |
926 | error_at (loc, "%qs is incompatible with %qs" , |
927 | "-fipa-vrp" , LIVE_PATCHING_OPTION); |
928 | else |
929 | opts->x_flag_ipa_vrp = 0; |
930 | |
931 | if (opts_set->x_flag_ipa_pure_const && opts->x_flag_ipa_pure_const) |
932 | error_at (loc, "%qs is incompatible with %qs" , |
933 | "-fipa-pure-const" , LIVE_PATCHING_OPTION); |
934 | else |
935 | opts->x_flag_ipa_pure_const = 0; |
936 | |
937 | if (opts_set->x_flag_ipa_modref && opts->x_flag_ipa_modref) |
938 | error_at (loc, |
939 | "%<-fipa-modref%> is incompatible with %qs" , |
940 | LIVE_PATCHING_OPTION); |
941 | else |
942 | opts->x_flag_ipa_modref = 0; |
943 | |
944 | /* FIXME: disable unreachable code removal. */ |
945 | |
946 | /* discovery of functions/variables with no address taken. */ |
947 | if (opts_set->x_flag_ipa_reference_addressable |
948 | && opts->x_flag_ipa_reference_addressable) |
949 | error_at (loc, "%qs is incompatible with %qs" , |
950 | "-fipa-reference-addressable" , LIVE_PATCHING_OPTION); |
951 | else |
952 | opts->x_flag_ipa_reference_addressable = 0; |
953 | |
954 | /* ipa stack alignment propagation. */ |
955 | if (opts_set->x_flag_ipa_stack_alignment |
956 | && opts->x_flag_ipa_stack_alignment) |
957 | error_at (loc, "%qs is incompatible with %qs" , |
958 | "-fipa-stack-alignment" , LIVE_PATCHING_OPTION); |
959 | else |
960 | opts->x_flag_ipa_stack_alignment = 0; |
961 | break; |
962 | default: |
963 | gcc_unreachable (); |
964 | } |
965 | |
966 | #undef LIVE_PATCHING_OPTION |
967 | } |
968 | |
969 | /* --help option argument if set. */ |
970 | vec<const char *> help_option_arguments; |
971 | |
972 | /* Return the string name describing a sanitizer argument which has been |
973 | provided on the command line and has set this particular flag. */ |
974 | const char * |
975 | find_sanitizer_argument (struct gcc_options *opts, unsigned int flags) |
976 | { |
977 | for (int i = 0; sanitizer_opts[i].name != NULL; ++i) |
978 | { |
979 | /* Need to find the sanitizer_opts element which: |
980 | a) Could have set the flags requested. |
981 | b) Has been set on the command line. |
982 | |
983 | Can have (a) without (b) if the flag requested is e.g. |
984 | SANITIZE_ADDRESS, since both -fsanitize=address and |
985 | -fsanitize=kernel-address set this flag. |
986 | |
987 | Can have (b) without (a) by requesting more than one sanitizer on the |
988 | command line. */ |
989 | if ((sanitizer_opts[i].flag & opts->x_flag_sanitize) |
990 | != sanitizer_opts[i].flag) |
991 | continue; |
992 | if ((sanitizer_opts[i].flag & flags) != flags) |
993 | continue; |
994 | return sanitizer_opts[i].name; |
995 | } |
996 | return NULL; |
997 | } |
998 | |
999 | |
1000 | /* Report an error to the user about sanitizer options they have requested |
1001 | which have set conflicting flags. |
1002 | |
1003 | LEFT and RIGHT indicate sanitizer flags which conflict with each other, this |
1004 | function reports an error if both have been set in OPTS->x_flag_sanitize and |
1005 | ensures the error identifies the requested command line options that have |
1006 | set these flags. */ |
1007 | static void |
1008 | report_conflicting_sanitizer_options (struct gcc_options *opts, location_t loc, |
1009 | unsigned int left, unsigned int right) |
1010 | { |
1011 | unsigned int left_seen = (opts->x_flag_sanitize & left); |
1012 | unsigned int right_seen = (opts->x_flag_sanitize & right); |
1013 | if (left_seen && right_seen) |
1014 | { |
1015 | const char* left_arg = find_sanitizer_argument (opts, flags: left_seen); |
1016 | const char* right_arg = find_sanitizer_argument (opts, flags: right_seen); |
1017 | gcc_assert (left_arg && right_arg); |
1018 | error_at (loc, |
1019 | "%<-fsanitize=%s%> is incompatible with %<-fsanitize=%s%>" , |
1020 | left_arg, right_arg); |
1021 | } |
1022 | } |
1023 | |
1024 | /* After all options at LOC have been read into OPTS and OPTS_SET, |
1025 | finalize settings of those options and diagnose incompatible |
1026 | combinations. */ |
1027 | void |
1028 | finish_options (struct gcc_options *opts, struct gcc_options *opts_set, |
1029 | location_t loc) |
1030 | { |
1031 | if (opts->x_dump_base_name |
1032 | && ! opts->x_dump_base_name_prefixed) |
1033 | { |
1034 | const char *sep = opts->x_dump_base_name; |
1035 | |
1036 | for (; *sep; sep++) |
1037 | if (IS_DIR_SEPARATOR (*sep)) |
1038 | break; |
1039 | |
1040 | if (*sep) |
1041 | /* If dump_base_path contains subdirectories, don't prepend |
1042 | anything. */; |
1043 | else if (opts->x_dump_dir_name) |
1044 | /* We have a DUMP_DIR_NAME, prepend that. */ |
1045 | opts->x_dump_base_name = opts_concat (first: opts->x_dump_dir_name, |
1046 | opts->x_dump_base_name, NULL); |
1047 | |
1048 | /* It is definitely prefixed now. */ |
1049 | opts->x_dump_base_name_prefixed = true; |
1050 | } |
1051 | |
1052 | /* Handle related options for unit-at-a-time, toplevel-reorder, and |
1053 | section-anchors. */ |
1054 | if (!opts->x_flag_unit_at_a_time) |
1055 | { |
1056 | if (opts->x_flag_section_anchors && opts_set->x_flag_section_anchors) |
1057 | error_at (loc, "section anchors must be disabled when unit-at-a-time " |
1058 | "is disabled" ); |
1059 | opts->x_flag_section_anchors = 0; |
1060 | if (opts->x_flag_toplevel_reorder == 1) |
1061 | error_at (loc, "toplevel reorder must be disabled when unit-at-a-time " |
1062 | "is disabled" ); |
1063 | opts->x_flag_toplevel_reorder = 0; |
1064 | } |
1065 | |
1066 | /* -fself-test depends on the state of the compiler prior to |
1067 | compiling anything. Ideally it should be run on an empty source |
1068 | file. However, in case we get run with actual source, assume |
1069 | -fsyntax-only which will inhibit any compiler initialization |
1070 | which may confuse the self tests. */ |
1071 | if (opts->x_flag_self_test) |
1072 | opts->x_flag_syntax_only = 1; |
1073 | |
1074 | if (opts->x_flag_tm && opts->x_flag_non_call_exceptions) |
1075 | sorry ("transactional memory is not supported with non-call exceptions" ); |
1076 | |
1077 | /* Unless the user has asked for section anchors, we disable toplevel |
1078 | reordering at -O0 to disable transformations that might be surprising |
1079 | to end users and to get -fno-toplevel-reorder tested. */ |
1080 | if (!opts->x_optimize |
1081 | && opts->x_flag_toplevel_reorder == 2 |
1082 | && !(opts->x_flag_section_anchors && opts_set->x_flag_section_anchors)) |
1083 | { |
1084 | opts->x_flag_toplevel_reorder = 0; |
1085 | opts->x_flag_section_anchors = 0; |
1086 | } |
1087 | if (!opts->x_flag_toplevel_reorder) |
1088 | { |
1089 | if (opts->x_flag_section_anchors && opts_set->x_flag_section_anchors) |
1090 | error_at (loc, "section anchors must be disabled when toplevel reorder" |
1091 | " is disabled" ); |
1092 | opts->x_flag_section_anchors = 0; |
1093 | } |
1094 | |
1095 | if (!opts->x_flag_opts_finished) |
1096 | { |
1097 | /* We initialize opts->x_flag_pie to -1 so that targets can set a |
1098 | default value. */ |
1099 | if (opts->x_flag_pie == -1) |
1100 | { |
1101 | /* We initialize opts->x_flag_pic to -1 so that we can tell if |
1102 | -fpic, -fPIC, -fno-pic or -fno-PIC is used. */ |
1103 | if (opts->x_flag_pic == -1) |
1104 | opts->x_flag_pie = DEFAULT_FLAG_PIE; |
1105 | else |
1106 | opts->x_flag_pie = 0; |
1107 | } |
1108 | /* If -fPIE or -fpie is used, turn on PIC. */ |
1109 | if (opts->x_flag_pie) |
1110 | opts->x_flag_pic = opts->x_flag_pie; |
1111 | else if (opts->x_flag_pic == -1) |
1112 | opts->x_flag_pic = 0; |
1113 | if (opts->x_flag_pic && !opts->x_flag_pie) |
1114 | opts->x_flag_shlib = 1; |
1115 | opts->x_flag_opts_finished = true; |
1116 | } |
1117 | |
1118 | /* We initialize opts->x_flag_stack_protect to -1 so that targets |
1119 | can set a default value. */ |
1120 | if (opts->x_flag_stack_protect == -1) |
1121 | opts->x_flag_stack_protect = DEFAULT_FLAG_SSP; |
1122 | |
1123 | if (opts->x_optimize == 0) |
1124 | { |
1125 | /* Inlining does not work if not optimizing, |
1126 | so force it not to be done. */ |
1127 | opts->x_warn_inline = 0; |
1128 | opts->x_flag_no_inline = 1; |
1129 | } |
1130 | |
1131 | /* At -O0 or -Og, turn __builtin_unreachable into a trap. */ |
1132 | if (!opts->x_optimize || opts->x_optimize_debug) |
1133 | SET_OPTION_IF_UNSET (opts, opts_set, flag_unreachable_traps, true); |
1134 | |
1135 | /* Pipelining of outer loops is only possible when general pipelining |
1136 | capabilities are requested. */ |
1137 | if (!opts->x_flag_sel_sched_pipelining) |
1138 | opts->x_flag_sel_sched_pipelining_outer_loops = 0; |
1139 | |
1140 | if (opts->x_flag_conserve_stack) |
1141 | { |
1142 | SET_OPTION_IF_UNSET (opts, opts_set, param_large_stack_frame, 100); |
1143 | SET_OPTION_IF_UNSET (opts, opts_set, param_stack_frame_growth, 40); |
1144 | } |
1145 | |
1146 | if (opts->x_flag_lto) |
1147 | { |
1148 | #ifdef ENABLE_LTO |
1149 | opts->x_flag_generate_lto = 1; |
1150 | |
1151 | /* When generating IL, do not operate in whole-program mode. |
1152 | Otherwise, symbols will be privatized too early, causing link |
1153 | errors later. */ |
1154 | opts->x_flag_whole_program = 0; |
1155 | #else |
1156 | error_at (loc, "LTO support has not been enabled in this configuration" ); |
1157 | #endif |
1158 | if (!opts->x_flag_fat_lto_objects |
1159 | && (!HAVE_LTO_PLUGIN |
1160 | || (opts_set->x_flag_use_linker_plugin |
1161 | && !opts->x_flag_use_linker_plugin))) |
1162 | { |
1163 | if (opts_set->x_flag_fat_lto_objects) |
1164 | error_at (loc, "%<-fno-fat-lto-objects%> are supported only with " |
1165 | "linker plugin" ); |
1166 | opts->x_flag_fat_lto_objects = 1; |
1167 | } |
1168 | |
1169 | /* -gsplit-dwarf isn't compatible with LTO, see PR88389. */ |
1170 | if (opts->x_dwarf_split_debug_info) |
1171 | { |
1172 | inform (loc, "%<-gsplit-dwarf%> is not supported with LTO," |
1173 | " disabling" ); |
1174 | opts->x_dwarf_split_debug_info = 0; |
1175 | } |
1176 | } |
1177 | |
1178 | /* We initialize opts->x_flag_split_stack to -1 so that targets can set a |
1179 | default value if they choose based on other options. */ |
1180 | if (opts->x_flag_split_stack == -1) |
1181 | opts->x_flag_split_stack = 0; |
1182 | else if (opts->x_flag_split_stack) |
1183 | { |
1184 | if (!targetm_common.supports_split_stack (true, opts)) |
1185 | { |
1186 | error_at (loc, "%<-fsplit-stack%> is not supported by " |
1187 | "this compiler configuration" ); |
1188 | opts->x_flag_split_stack = 0; |
1189 | } |
1190 | } |
1191 | |
1192 | /* If stack splitting is turned on, and the user did not explicitly |
1193 | request function partitioning, turn off partitioning, as it |
1194 | confuses the linker when trying to handle partitioned split-stack |
1195 | code that calls a non-split-stack functions. But if partitioning |
1196 | was turned on explicitly just hope for the best. */ |
1197 | if (opts->x_flag_split_stack |
1198 | && opts->x_flag_reorder_blocks_and_partition) |
1199 | SET_OPTION_IF_UNSET (opts, opts_set, flag_reorder_blocks_and_partition, 0); |
1200 | |
1201 | if (opts->x_flag_reorder_blocks_and_partition) |
1202 | SET_OPTION_IF_UNSET (opts, opts_set, flag_reorder_functions, 1); |
1203 | |
1204 | /* The -gsplit-dwarf option requires -ggnu-pubnames. */ |
1205 | if (opts->x_dwarf_split_debug_info) |
1206 | opts->x_debug_generate_pub_sections = 2; |
1207 | |
1208 | if ((opts->x_flag_sanitize |
1209 | & (SANITIZE_USER_ADDRESS | SANITIZE_KERNEL_ADDRESS)) == 0) |
1210 | { |
1211 | if (opts->x_flag_sanitize & SANITIZE_POINTER_COMPARE) |
1212 | error_at (loc, |
1213 | "%<-fsanitize=pointer-compare%> must be combined with " |
1214 | "%<-fsanitize=address%> or %<-fsanitize=kernel-address%>" ); |
1215 | if (opts->x_flag_sanitize & SANITIZE_POINTER_SUBTRACT) |
1216 | error_at (loc, |
1217 | "%<-fsanitize=pointer-subtract%> must be combined with " |
1218 | "%<-fsanitize=address%> or %<-fsanitize=kernel-address%>" ); |
1219 | } |
1220 | |
1221 | /* Address sanitizers conflict with the thread sanitizer. */ |
1222 | report_conflicting_sanitizer_options (opts, loc, left: SANITIZE_THREAD, |
1223 | right: SANITIZE_ADDRESS); |
1224 | report_conflicting_sanitizer_options (opts, loc, left: SANITIZE_THREAD, |
1225 | right: SANITIZE_HWADDRESS); |
1226 | /* The leak sanitizer conflicts with the thread sanitizer. */ |
1227 | report_conflicting_sanitizer_options (opts, loc, left: SANITIZE_LEAK, |
1228 | right: SANITIZE_THREAD); |
1229 | |
1230 | /* No combination of HWASAN and ASAN work together. */ |
1231 | report_conflicting_sanitizer_options (opts, loc, |
1232 | left: SANITIZE_HWADDRESS, right: SANITIZE_ADDRESS); |
1233 | |
1234 | /* The userspace and kernel address sanitizers conflict with each other. */ |
1235 | report_conflicting_sanitizer_options (opts, loc, left: SANITIZE_USER_HWADDRESS, |
1236 | right: SANITIZE_KERNEL_HWADDRESS); |
1237 | report_conflicting_sanitizer_options (opts, loc, left: SANITIZE_USER_ADDRESS, |
1238 | right: SANITIZE_KERNEL_ADDRESS); |
1239 | |
1240 | /* Check error recovery for -fsanitize-recover option. */ |
1241 | for (int i = 0; sanitizer_opts[i].name != NULL; ++i) |
1242 | if ((opts->x_flag_sanitize_recover & sanitizer_opts[i].flag) |
1243 | && !sanitizer_opts[i].can_recover) |
1244 | error_at (loc, "%<-fsanitize-recover=%s%> is not supported" , |
1245 | sanitizer_opts[i].name); |
1246 | |
1247 | /* Check -fsanitize-trap option. */ |
1248 | for (int i = 0; sanitizer_opts[i].name != NULL; ++i) |
1249 | if ((opts->x_flag_sanitize_trap & sanitizer_opts[i].flag) |
1250 | && !sanitizer_opts[i].can_trap |
1251 | /* Allow -fsanitize-trap=all or -fsanitize-trap=undefined |
1252 | to set flag_sanitize_trap & SANITIZE_VPTR bit which will |
1253 | effectively disable -fsanitize=vptr, just disallow |
1254 | explicit -fsanitize-trap=vptr. */ |
1255 | && sanitizer_opts[i].flag != SANITIZE_VPTR) |
1256 | error_at (loc, "%<-fsanitize-trap=%s%> is not supported" , |
1257 | sanitizer_opts[i].name); |
1258 | |
1259 | /* When instrumenting the pointers, we don't want to remove |
1260 | the null pointer checks. */ |
1261 | if (opts->x_flag_sanitize & (SANITIZE_NULL | SANITIZE_NONNULL_ATTRIBUTE |
1262 | | SANITIZE_RETURNS_NONNULL_ATTRIBUTE)) |
1263 | opts->x_flag_delete_null_pointer_checks = 0; |
1264 | |
1265 | /* Aggressive compiler optimizations may cause false negatives. */ |
1266 | if (opts->x_flag_sanitize & ~(SANITIZE_LEAK | SANITIZE_UNREACHABLE)) |
1267 | opts->x_flag_aggressive_loop_optimizations = 0; |
1268 | |
1269 | /* Enable -fsanitize-address-use-after-scope if either address sanitizer is |
1270 | enabled. */ |
1271 | if (opts->x_flag_sanitize |
1272 | & (SANITIZE_USER_ADDRESS | SANITIZE_USER_HWADDRESS)) |
1273 | SET_OPTION_IF_UNSET (opts, opts_set, flag_sanitize_address_use_after_scope, |
1274 | true); |
1275 | |
1276 | /* Force -fstack-reuse=none in case -fsanitize-address-use-after-scope |
1277 | is enabled. */ |
1278 | if (opts->x_flag_sanitize_address_use_after_scope) |
1279 | { |
1280 | if (opts->x_flag_stack_reuse != SR_NONE |
1281 | && opts_set->x_flag_stack_reuse != SR_NONE) |
1282 | error_at (loc, |
1283 | "%<-fsanitize-address-use-after-scope%> requires " |
1284 | "%<-fstack-reuse=none%> option" ); |
1285 | |
1286 | opts->x_flag_stack_reuse = SR_NONE; |
1287 | } |
1288 | |
1289 | if ((opts->x_flag_sanitize & SANITIZE_USER_ADDRESS) && opts->x_flag_tm) |
1290 | sorry ("transactional memory is not supported with %<-fsanitize=address%>" ); |
1291 | |
1292 | if ((opts->x_flag_sanitize & SANITIZE_KERNEL_ADDRESS) && opts->x_flag_tm) |
1293 | sorry ("transactional memory is not supported with " |
1294 | "%<-fsanitize=kernel-address%>" ); |
1295 | |
1296 | /* Currently live patching is not support for LTO. */ |
1297 | if (opts->x_flag_live_patching == LIVE_PATCHING_INLINE_ONLY_STATIC && opts->x_flag_lto) |
1298 | sorry ("live patching (with %qs) is not supported with LTO" , |
1299 | "inline-only-static" ); |
1300 | |
1301 | /* Currently vtable verification is not supported for LTO */ |
1302 | if (opts->x_flag_vtable_verify && opts->x_flag_lto) |
1303 | sorry ("vtable verification is not supported with LTO" ); |
1304 | |
1305 | /* Control IPA optimizations based on different -flive-patching level. */ |
1306 | if (opts->x_flag_live_patching) |
1307 | control_options_for_live_patching (opts, opts_set, |
1308 | level: opts->x_flag_live_patching, |
1309 | loc); |
1310 | |
1311 | /* Allow cunroll to grow size accordingly. */ |
1312 | if (!opts_set->x_flag_cunroll_grow_size) |
1313 | opts->x_flag_cunroll_grow_size |
1314 | = (opts->x_flag_unroll_loops |
1315 | || opts->x_flag_peel_loops |
1316 | || opts->x_optimize >= 3); |
1317 | |
1318 | /* With -fcx-limited-range, we do cheap and quick complex arithmetic. */ |
1319 | if (opts->x_flag_cx_limited_range) |
1320 | opts->x_flag_complex_method = 0; |
1321 | else if (opts_set->x_flag_cx_limited_range) |
1322 | opts->x_flag_complex_method = opts->x_flag_default_complex_method; |
1323 | |
1324 | /* With -fcx-fortran-rules, we do something in-between cheap and C99. */ |
1325 | if (opts->x_flag_cx_fortran_rules) |
1326 | opts->x_flag_complex_method = 1; |
1327 | else if (opts_set->x_flag_cx_fortran_rules) |
1328 | opts->x_flag_complex_method = opts->x_flag_default_complex_method; |
1329 | |
1330 | /* Use -fvect-cost-model=cheap instead of -fvect-cost-mode=very-cheap |
1331 | by default with explicit -ftree-{loop,slp}-vectorize. */ |
1332 | if (opts->x_optimize == 2 |
1333 | && (opts_set->x_flag_tree_loop_vectorize |
1334 | || opts_set->x_flag_tree_vectorize)) |
1335 | SET_OPTION_IF_UNSET (opts, opts_set, flag_vect_cost_model, |
1336 | VECT_COST_MODEL_CHEAP); |
1337 | |
1338 | if (opts->x_flag_gtoggle) |
1339 | { |
1340 | /* Make sure to process -gtoggle only once. */ |
1341 | opts->x_flag_gtoggle = false; |
1342 | if (opts->x_debug_info_level == DINFO_LEVEL_NONE) |
1343 | { |
1344 | opts->x_debug_info_level = DINFO_LEVEL_NORMAL; |
1345 | |
1346 | if (opts->x_write_symbols == NO_DEBUG) |
1347 | opts->x_write_symbols = PREFERRED_DEBUGGING_TYPE; |
1348 | } |
1349 | else |
1350 | opts->x_debug_info_level = DINFO_LEVEL_NONE; |
1351 | } |
1352 | |
1353 | if (!opts_set->x_debug_nonbind_markers_p) |
1354 | opts->x_debug_nonbind_markers_p |
1355 | = (opts->x_optimize |
1356 | && opts->x_debug_info_level >= DINFO_LEVEL_NORMAL |
1357 | && dwarf_debuginfo_p (opts) |
1358 | && !(opts->x_flag_selective_scheduling |
1359 | || opts->x_flag_selective_scheduling2)); |
1360 | |
1361 | /* We know which debug output will be used so we can set flag_var_tracking |
1362 | and flag_var_tracking_uninit if the user has not specified them. */ |
1363 | if (opts->x_debug_info_level < DINFO_LEVEL_NORMAL |
1364 | || !dwarf_debuginfo_p (opts) |
1365 | /* We have not yet initialized debug hooks so match that to check |
1366 | whether we're only doing DWARF2_LINENO_DEBUGGING_INFO. */ |
1367 | #ifndef DWARF2_DEBUGGING_INFO |
1368 | || true |
1369 | #endif |
1370 | ) |
1371 | { |
1372 | if ((opts_set->x_flag_var_tracking && opts->x_flag_var_tracking == 1) |
1373 | || (opts_set->x_flag_var_tracking_uninit |
1374 | && opts->x_flag_var_tracking_uninit == 1)) |
1375 | { |
1376 | if (opts->x_debug_info_level < DINFO_LEVEL_NORMAL) |
1377 | warning_at (UNKNOWN_LOCATION, 0, |
1378 | "variable tracking requested, but useless unless " |
1379 | "producing debug info" ); |
1380 | else |
1381 | warning_at (UNKNOWN_LOCATION, 0, |
1382 | "variable tracking requested, but not supported " |
1383 | "by this debug format" ); |
1384 | } |
1385 | opts->x_flag_var_tracking = 0; |
1386 | opts->x_flag_var_tracking_uninit = 0; |
1387 | opts->x_flag_var_tracking_assignments = 0; |
1388 | } |
1389 | |
1390 | /* One could use EnabledBy, but it would lead to a circular dependency. */ |
1391 | if (!opts_set->x_flag_var_tracking_uninit) |
1392 | opts->x_flag_var_tracking_uninit = opts->x_flag_var_tracking; |
1393 | |
1394 | if (!opts_set->x_flag_var_tracking_assignments) |
1395 | opts->x_flag_var_tracking_assignments |
1396 | = (opts->x_flag_var_tracking |
1397 | && !(opts->x_flag_selective_scheduling |
1398 | || opts->x_flag_selective_scheduling2)); |
1399 | |
1400 | if (opts->x_flag_var_tracking_assignments_toggle) |
1401 | opts->x_flag_var_tracking_assignments |
1402 | = !opts->x_flag_var_tracking_assignments; |
1403 | |
1404 | if (opts->x_flag_var_tracking_assignments && !opts->x_flag_var_tracking) |
1405 | opts->x_flag_var_tracking = opts->x_flag_var_tracking_assignments = -1; |
1406 | |
1407 | if (opts->x_flag_var_tracking_assignments |
1408 | && (opts->x_flag_selective_scheduling |
1409 | || opts->x_flag_selective_scheduling2)) |
1410 | warning_at (loc, 0, |
1411 | "var-tracking-assignments changes selective scheduling" ); |
1412 | |
1413 | if (opts->x_flag_syntax_only) |
1414 | { |
1415 | opts->x_write_symbols = NO_DEBUG; |
1416 | opts->x_profile_flag = 0; |
1417 | } |
1418 | |
1419 | if (opts->x_warn_strict_flex_arrays) |
1420 | if (opts->x_flag_strict_flex_arrays == 0) |
1421 | { |
1422 | opts->x_warn_strict_flex_arrays = 0; |
1423 | warning_at (UNKNOWN_LOCATION, 0, |
1424 | "%<-Wstrict-flex-arrays%> is ignored when" |
1425 | " %<-fstrict-flex-arrays%> is not present" ); |
1426 | } |
1427 | |
1428 | diagnose_options (opts, opts_set, loc); |
1429 | } |
1430 | |
1431 | /* The function diagnoses incompatible combinations for provided options |
1432 | (OPTS and OPTS_SET) at a given LOCation. The function is called both |
1433 | when command line is parsed (after the target optimization hook) and |
1434 | when an optimize/target attribute (or pragma) is used. */ |
1435 | |
1436 | void diagnose_options (gcc_options *opts, gcc_options *opts_set, |
1437 | location_t loc) |
1438 | { |
1439 | /* The optimization to partition hot and cold basic blocks into separate |
1440 | sections of the .o and executable files does not work (currently) |
1441 | with exception handling. This is because there is no support for |
1442 | generating unwind info. If opts->x_flag_exceptions is turned on |
1443 | we need to turn off the partitioning optimization. */ |
1444 | |
1445 | enum unwind_info_type ui_except |
1446 | = targetm_common.except_unwind_info (opts); |
1447 | |
1448 | if (opts->x_flag_exceptions |
1449 | && opts->x_flag_reorder_blocks_and_partition |
1450 | && (ui_except == UI_SJLJ || ui_except >= UI_TARGET)) |
1451 | { |
1452 | if (opts_set->x_flag_reorder_blocks_and_partition) |
1453 | inform (loc, |
1454 | "%<-freorder-blocks-and-partition%> does not work " |
1455 | "with exceptions on this architecture" ); |
1456 | opts->x_flag_reorder_blocks_and_partition = 0; |
1457 | opts->x_flag_reorder_blocks = 1; |
1458 | } |
1459 | |
1460 | /* If user requested unwind info, then turn off the partitioning |
1461 | optimization. */ |
1462 | |
1463 | if (opts->x_flag_unwind_tables |
1464 | && !targetm_common.unwind_tables_default |
1465 | && opts->x_flag_reorder_blocks_and_partition |
1466 | && (ui_except == UI_SJLJ || ui_except >= UI_TARGET)) |
1467 | { |
1468 | if (opts_set->x_flag_reorder_blocks_and_partition) |
1469 | inform (loc, |
1470 | "%<-freorder-blocks-and-partition%> does not support " |
1471 | "unwind info on this architecture" ); |
1472 | opts->x_flag_reorder_blocks_and_partition = 0; |
1473 | opts->x_flag_reorder_blocks = 1; |
1474 | } |
1475 | |
1476 | /* If the target requested unwind info, then turn off the partitioning |
1477 | optimization with a different message. Likewise, if the target does not |
1478 | support named sections. */ |
1479 | |
1480 | if (opts->x_flag_reorder_blocks_and_partition |
1481 | && (!targetm_common.have_named_sections |
1482 | || (opts->x_flag_unwind_tables |
1483 | && targetm_common.unwind_tables_default |
1484 | && (ui_except == UI_SJLJ || ui_except >= UI_TARGET)))) |
1485 | { |
1486 | if (opts_set->x_flag_reorder_blocks_and_partition) |
1487 | inform (loc, |
1488 | "%<-freorder-blocks-and-partition%> does not work " |
1489 | "on this architecture" ); |
1490 | opts->x_flag_reorder_blocks_and_partition = 0; |
1491 | opts->x_flag_reorder_blocks = 1; |
1492 | } |
1493 | |
1494 | |
1495 | } |
1496 | |
1497 | #define LEFT_COLUMN 27 |
1498 | |
1499 | /* Output ITEM, of length ITEM_WIDTH, in the left column, |
1500 | followed by word-wrapped HELP in a second column. */ |
1501 | static void |
1502 | wrap_help (const char *help, |
1503 | const char *item, |
1504 | unsigned int item_width, |
1505 | unsigned int columns) |
1506 | { |
1507 | unsigned int col_width = LEFT_COLUMN; |
1508 | unsigned int remaining, room, len; |
1509 | |
1510 | remaining = strlen (s: help); |
1511 | |
1512 | do |
1513 | { |
1514 | room = columns - 3 - MAX (col_width, item_width); |
1515 | if (room > columns) |
1516 | room = 0; |
1517 | len = remaining; |
1518 | |
1519 | if (room < len) |
1520 | { |
1521 | unsigned int i; |
1522 | |
1523 | for (i = 0; help[i]; i++) |
1524 | { |
1525 | if (i >= room && len != remaining) |
1526 | break; |
1527 | if (help[i] == ' ') |
1528 | len = i; |
1529 | else if ((help[i] == '-' || help[i] == '/') |
1530 | && help[i + 1] != ' ' |
1531 | && i > 0 && ISALPHA (help[i - 1])) |
1532 | len = i + 1; |
1533 | } |
1534 | } |
1535 | |
1536 | printf (format: " %-*.*s %.*s\n" , col_width, item_width, item, len, help); |
1537 | item_width = 0; |
1538 | while (help[len] == ' ') |
1539 | len++; |
1540 | help += len; |
1541 | remaining -= len; |
1542 | } |
1543 | while (remaining); |
1544 | } |
1545 | |
1546 | /* Data structure used to print list of valid option values. */ |
1547 | |
1548 | class option_help_tuple |
1549 | { |
1550 | public: |
1551 | option_help_tuple (int code, vec<const char *> values): |
1552 | m_code (code), m_values (values) |
1553 | {} |
1554 | |
1555 | /* Code of an option. */ |
1556 | int m_code; |
1557 | |
1558 | /* List of possible values. */ |
1559 | vec<const char *> m_values; |
1560 | }; |
1561 | |
1562 | /* Print help for a specific front-end, etc. */ |
1563 | static void |
1564 | print_filtered_help (unsigned int include_flags, |
1565 | unsigned int exclude_flags, |
1566 | unsigned int any_flags, |
1567 | unsigned int columns, |
1568 | struct gcc_options *opts, |
1569 | unsigned int lang_mask) |
1570 | { |
1571 | unsigned int i; |
1572 | const char *help; |
1573 | bool found = false; |
1574 | bool displayed = false; |
1575 | char new_help[256]; |
1576 | |
1577 | if (!opts->x_help_printed) |
1578 | opts->x_help_printed = XCNEWVAR (char, cl_options_count); |
1579 | |
1580 | if (!opts->x_help_enum_printed) |
1581 | opts->x_help_enum_printed = XCNEWVAR (char, cl_enums_count); |
1582 | |
1583 | auto_vec<option_help_tuple> help_tuples; |
1584 | |
1585 | for (i = 0; i < cl_options_count; i++) |
1586 | { |
1587 | const struct cl_option *option = cl_options + i; |
1588 | unsigned int len; |
1589 | const char *opt; |
1590 | const char *tab; |
1591 | |
1592 | if (include_flags == 0 |
1593 | || ((option->flags & include_flags) != include_flags)) |
1594 | { |
1595 | if ((option->flags & any_flags) == 0) |
1596 | continue; |
1597 | } |
1598 | |
1599 | /* Skip unwanted switches. */ |
1600 | if ((option->flags & exclude_flags) != 0) |
1601 | continue; |
1602 | |
1603 | /* The driver currently prints its own help text. */ |
1604 | if ((option->flags & CL_DRIVER) != 0 |
1605 | && (option->flags & (((1U << cl_lang_count) - 1) |
1606 | | CL_COMMON | CL_TARGET)) == 0) |
1607 | continue; |
1608 | |
1609 | /* If an option contains a language specification, |
1610 | exclude it from common unless all languages are present. */ |
1611 | if ((include_flags & CL_COMMON) |
1612 | && !(option->flags & CL_DRIVER) |
1613 | && (option->flags & CL_LANG_ALL) |
1614 | && (option->flags & CL_LANG_ALL) != CL_LANG_ALL) |
1615 | continue; |
1616 | |
1617 | found = true; |
1618 | /* Skip switches that have already been printed. */ |
1619 | if (opts->x_help_printed[i]) |
1620 | continue; |
1621 | |
1622 | opts->x_help_printed[i] = true; |
1623 | |
1624 | help = option->help; |
1625 | if (help == NULL) |
1626 | { |
1627 | if (exclude_flags & CL_UNDOCUMENTED) |
1628 | continue; |
1629 | |
1630 | help = undocumented_msg; |
1631 | } |
1632 | |
1633 | /* Get the translation. */ |
1634 | help = _(help); |
1635 | |
1636 | if (option->alias_target < N_OPTS |
1637 | && cl_options [option->alias_target].help) |
1638 | { |
1639 | const struct cl_option *target = cl_options + option->alias_target; |
1640 | if (option->help == NULL) |
1641 | { |
1642 | /* The option is undocumented but is an alias for an option that |
1643 | is documented. If the option has alias arguments, then its |
1644 | purpose is to provide certain arguments to the other option, so |
1645 | inform the reader of this. Otherwise, point the reader to the |
1646 | other option in preference to the former. */ |
1647 | |
1648 | if (option->alias_arg) |
1649 | { |
1650 | if (option->neg_alias_arg) |
1651 | snprintf (s: new_help, maxlen: sizeof new_help, |
1652 | _("Same as %s%s (or, in negated form, %s%s)." ), |
1653 | target->opt_text, option->alias_arg, |
1654 | target->opt_text, option->neg_alias_arg); |
1655 | else |
1656 | snprintf (s: new_help, maxlen: sizeof new_help, |
1657 | _("Same as %s%s." ), |
1658 | target->opt_text, option->alias_arg); |
1659 | } |
1660 | else |
1661 | snprintf (s: new_help, maxlen: sizeof new_help, |
1662 | _("Same as %s." ), |
1663 | target->opt_text); |
1664 | } |
1665 | else |
1666 | { |
1667 | /* For documented options with aliases, mention the aliased |
1668 | option's name for reference. */ |
1669 | snprintf (s: new_help, maxlen: sizeof new_help, |
1670 | _("%s Same as %s." ), |
1671 | help, cl_options [option->alias_target].opt_text); |
1672 | } |
1673 | |
1674 | help = new_help; |
1675 | } |
1676 | |
1677 | if (option->warn_message) |
1678 | { |
1679 | /* Mention that the use of the option will trigger a warning. */ |
1680 | if (help == new_help) |
1681 | snprintf (s: new_help + strlen (s: new_help), |
1682 | maxlen: sizeof new_help - strlen (s: new_help), |
1683 | format: " %s" , _(use_diagnosed_msg)); |
1684 | else |
1685 | snprintf (s: new_help, maxlen: sizeof new_help, |
1686 | format: "%s %s" , help, _(use_diagnosed_msg)); |
1687 | |
1688 | help = new_help; |
1689 | } |
1690 | |
1691 | /* Find the gap between the name of the |
1692 | option and its descriptive text. */ |
1693 | tab = strchr (s: help, c: '\t'); |
1694 | if (tab) |
1695 | { |
1696 | len = tab - help; |
1697 | opt = help; |
1698 | help = tab + 1; |
1699 | } |
1700 | else |
1701 | { |
1702 | opt = option->opt_text; |
1703 | len = strlen (s: opt); |
1704 | } |
1705 | |
1706 | /* With the -Q option enabled we change the descriptive text associated |
1707 | with an option to be an indication of its current setting. */ |
1708 | if (!opts->x_quiet_flag) |
1709 | { |
1710 | void *flag_var = option_flag_var (opt_index: i, opts); |
1711 | |
1712 | if (len < (LEFT_COLUMN + 2)) |
1713 | strcpy (dest: new_help, src: "\t\t" ); |
1714 | else |
1715 | strcpy (dest: new_help, src: "\t" ); |
1716 | |
1717 | /* Set to print whether the option is enabled or disabled, |
1718 | or, if it's an alias for another option, the name of |
1719 | the aliased option. */ |
1720 | bool print_state = false; |
1721 | |
1722 | if (flag_var != NULL |
1723 | && option->var_type != CLVC_DEFER) |
1724 | { |
1725 | /* If OPTION is only available for a specific subset |
1726 | of languages other than this one, mention them. */ |
1727 | bool avail_for_lang = true; |
1728 | if (unsigned langset = option->flags & CL_LANG_ALL) |
1729 | { |
1730 | if (!(langset & lang_mask)) |
1731 | { |
1732 | avail_for_lang = false; |
1733 | strcat (dest: new_help, _("[available in " )); |
1734 | for (unsigned i = 0, n = 0; (1U << i) < CL_LANG_ALL; ++i) |
1735 | if (langset & (1U << i)) |
1736 | { |
1737 | if (n++) |
1738 | strcat (dest: new_help, src: ", " ); |
1739 | strcat (dest: new_help, src: lang_names[i]); |
1740 | } |
1741 | strcat (dest: new_help, src: "]" ); |
1742 | } |
1743 | } |
1744 | if (!avail_for_lang) |
1745 | ; /* Print nothing else if the option is not available |
1746 | in the current language. */ |
1747 | else if (option->flags & CL_JOINED) |
1748 | { |
1749 | if (option->var_type == CLVC_STRING) |
1750 | { |
1751 | if (* (const char **) flag_var != NULL) |
1752 | snprintf (s: new_help + strlen (s: new_help), |
1753 | maxlen: sizeof (new_help) - strlen (s: new_help), |
1754 | format: "%s" , * (const char **) flag_var); |
1755 | } |
1756 | else if (option->var_type == CLVC_ENUM) |
1757 | { |
1758 | const struct cl_enum *e = &cl_enums[option->var_enum]; |
1759 | int value; |
1760 | const char *arg = NULL; |
1761 | |
1762 | value = e->get (flag_var); |
1763 | enum_value_to_arg (enum_args: e->values, argp: &arg, value, lang_mask); |
1764 | if (arg == NULL) |
1765 | arg = _("[default]" ); |
1766 | snprintf (s: new_help + strlen (s: new_help), |
1767 | maxlen: sizeof (new_help) - strlen (s: new_help), |
1768 | format: "%s" , arg); |
1769 | } |
1770 | else |
1771 | { |
1772 | if (option->cl_host_wide_int) |
1773 | sprintf (s: new_help + strlen (s: new_help), |
1774 | _("%llu bytes" ), (unsigned long long) |
1775 | *(unsigned HOST_WIDE_INT *) flag_var); |
1776 | else |
1777 | sprintf (s: new_help + strlen (s: new_help), |
1778 | format: "%i" , * (int *) flag_var); |
1779 | } |
1780 | } |
1781 | else |
1782 | print_state = true; |
1783 | } |
1784 | else |
1785 | /* When there is no argument, print the option state only |
1786 | if the option takes no argument. */ |
1787 | print_state = !(option->flags & CL_JOINED); |
1788 | |
1789 | if (print_state) |
1790 | { |
1791 | if (option->alias_target < N_OPTS |
1792 | && option->alias_target != OPT_SPECIAL_warn_removed |
1793 | && option->alias_target != OPT_SPECIAL_ignore |
1794 | && option->alias_target != OPT_SPECIAL_input_file |
1795 | && option->alias_target != OPT_SPECIAL_program_name |
1796 | && option->alias_target != OPT_SPECIAL_unknown) |
1797 | { |
1798 | const struct cl_option *target |
1799 | = &cl_options[option->alias_target]; |
1800 | sprintf (s: new_help + strlen (s: new_help), format: "%s%s" , |
1801 | target->opt_text, |
1802 | option->alias_arg ? option->alias_arg : "" ); |
1803 | } |
1804 | else if (option->alias_target == OPT_SPECIAL_ignore) |
1805 | strcat (dest: new_help, src: ("[ignored]" )); |
1806 | else |
1807 | { |
1808 | /* Print the state for an on/off option. */ |
1809 | int ena = option_enabled (opt_idx: i, lang_mask, opts); |
1810 | if (ena > 0) |
1811 | strcat (dest: new_help, _("[enabled]" )); |
1812 | else if (ena == 0) |
1813 | strcat (dest: new_help, _("[disabled]" )); |
1814 | } |
1815 | } |
1816 | |
1817 | help = new_help; |
1818 | } |
1819 | |
1820 | if (option->range_max != -1 && tab == NULL) |
1821 | { |
1822 | char b[128]; |
1823 | snprintf (s: b, maxlen: sizeof (b), format: "<%d,%d>" , option->range_min, |
1824 | option->range_max); |
1825 | opt = concat (opt, b, NULL); |
1826 | len += strlen (s: b); |
1827 | } |
1828 | |
1829 | wrap_help (help, item: opt, item_width: len, columns); |
1830 | displayed = true; |
1831 | |
1832 | if (option->var_type == CLVC_ENUM |
1833 | && opts->x_help_enum_printed[option->var_enum] != 2) |
1834 | opts->x_help_enum_printed[option->var_enum] = 1; |
1835 | else |
1836 | { |
1837 | vec<const char *> option_values |
1838 | = targetm_common.get_valid_option_values (i, NULL); |
1839 | if (!option_values.is_empty ()) |
1840 | help_tuples.safe_push (obj: option_help_tuple (i, option_values)); |
1841 | } |
1842 | } |
1843 | |
1844 | if (! found) |
1845 | { |
1846 | unsigned int langs = include_flags & CL_LANG_ALL; |
1847 | |
1848 | if (langs == 0) |
1849 | printf (_(" No options with the desired characteristics were found\n" )); |
1850 | else |
1851 | { |
1852 | unsigned int i; |
1853 | |
1854 | /* PR 31349: Tell the user how to see all of the |
1855 | options supported by a specific front end. */ |
1856 | for (i = 0; (1U << i) < CL_LANG_ALL; i ++) |
1857 | if ((1U << i) & langs) |
1858 | printf (_(" None found. Use --help=%s to show *all* the options supported by the %s front-end.\n" ), |
1859 | lang_names[i], lang_names[i]); |
1860 | } |
1861 | |
1862 | } |
1863 | else if (! displayed) |
1864 | printf (_(" All options with the desired characteristics have already been displayed\n" )); |
1865 | |
1866 | putchar (c: '\n'); |
1867 | |
1868 | /* Print details of enumerated option arguments, if those |
1869 | enumerations have help text headings provided. If no help text |
1870 | is provided, presume that the possible values are listed in the |
1871 | help text for the relevant options. */ |
1872 | for (i = 0; i < cl_enums_count; i++) |
1873 | { |
1874 | unsigned int j, pos; |
1875 | |
1876 | if (opts->x_help_enum_printed[i] != 1) |
1877 | continue; |
1878 | if (cl_enums[i].help == NULL) |
1879 | continue; |
1880 | printf (format: " %s\n " , _(cl_enums[i].help)); |
1881 | pos = 4; |
1882 | for (j = 0; cl_enums[i].values[j].arg != NULL; j++) |
1883 | { |
1884 | unsigned int len = strlen (s: cl_enums[i].values[j].arg); |
1885 | |
1886 | if (pos > 4 && pos + 1 + len <= columns) |
1887 | { |
1888 | printf (format: " %s" , cl_enums[i].values[j].arg); |
1889 | pos += 1 + len; |
1890 | } |
1891 | else |
1892 | { |
1893 | if (pos > 4) |
1894 | { |
1895 | printf (format: "\n " ); |
1896 | pos = 4; |
1897 | } |
1898 | printf (format: "%s" , cl_enums[i].values[j].arg); |
1899 | pos += len; |
1900 | } |
1901 | } |
1902 | printf (format: "\n\n" ); |
1903 | opts->x_help_enum_printed[i] = 2; |
1904 | } |
1905 | |
1906 | for (unsigned i = 0; i < help_tuples.length (); i++) |
1907 | { |
1908 | const struct cl_option *option = cl_options + help_tuples[i].m_code; |
1909 | printf (_(" Known valid arguments for %s option:\n " ), |
1910 | option->opt_text); |
1911 | for (unsigned j = 0; j < help_tuples[i].m_values.length (); j++) |
1912 | printf (format: " %s" , help_tuples[i].m_values[j]); |
1913 | printf (format: "\n\n" ); |
1914 | } |
1915 | } |
1916 | |
1917 | /* Display help for a specified type of option. |
1918 | The options must have ALL of the INCLUDE_FLAGS set |
1919 | ANY of the flags in the ANY_FLAGS set |
1920 | and NONE of the EXCLUDE_FLAGS set. The current option state is in |
1921 | OPTS; LANG_MASK is used for interpreting enumerated option state. */ |
1922 | static void |
1923 | print_specific_help (unsigned int include_flags, |
1924 | unsigned int exclude_flags, |
1925 | unsigned int any_flags, |
1926 | struct gcc_options *opts, |
1927 | unsigned int lang_mask) |
1928 | { |
1929 | unsigned int all_langs_mask = (1U << cl_lang_count) - 1; |
1930 | const char * description = NULL; |
1931 | const char * = "" ; |
1932 | size_t i; |
1933 | unsigned int flag; |
1934 | |
1935 | /* Sanity check: Make sure that we do not have more |
1936 | languages than we have bits available to enumerate them. */ |
1937 | gcc_assert ((1U << cl_lang_count) <= CL_MIN_OPTION_CLASS); |
1938 | |
1939 | /* If we have not done so already, obtain |
1940 | the desired maximum width of the output. */ |
1941 | if (opts->x_help_columns == 0) |
1942 | { |
1943 | opts->x_help_columns = get_terminal_width (); |
1944 | if (opts->x_help_columns == INT_MAX) |
1945 | /* Use a reasonable default. */ |
1946 | opts->x_help_columns = 80; |
1947 | } |
1948 | |
1949 | /* Decide upon the title for the options that we are going to display. */ |
1950 | for (i = 0, flag = 1; flag <= CL_MAX_OPTION_CLASS; flag <<= 1, i ++) |
1951 | { |
1952 | switch (flag & include_flags) |
1953 | { |
1954 | case 0: |
1955 | case CL_DRIVER: |
1956 | break; |
1957 | |
1958 | case CL_TARGET: |
1959 | description = _("The following options are target specific" ); |
1960 | break; |
1961 | case CL_WARNING: |
1962 | description = _("The following options control compiler warning messages" ); |
1963 | break; |
1964 | case CL_OPTIMIZATION: |
1965 | description = _("The following options control optimizations" ); |
1966 | break; |
1967 | case CL_COMMON: |
1968 | description = _("The following options are language-independent" ); |
1969 | break; |
1970 | case CL_PARAMS: |
1971 | description = _("The following options control parameters" ); |
1972 | break; |
1973 | default: |
1974 | if (i >= cl_lang_count) |
1975 | break; |
1976 | if (exclude_flags & all_langs_mask) |
1977 | description = _("The following options are specific to just the language " ); |
1978 | else |
1979 | description = _("The following options are supported by the language " ); |
1980 | descrip_extra = lang_names [i]; |
1981 | break; |
1982 | } |
1983 | } |
1984 | |
1985 | if (description == NULL) |
1986 | { |
1987 | if (any_flags == 0) |
1988 | { |
1989 | if (include_flags & CL_UNDOCUMENTED) |
1990 | description = _("The following options are not documented" ); |
1991 | else if (include_flags & CL_SEPARATE) |
1992 | description = _("The following options take separate arguments" ); |
1993 | else if (include_flags & CL_JOINED) |
1994 | description = _("The following options take joined arguments" ); |
1995 | else |
1996 | { |
1997 | internal_error ("unrecognized %<include_flags 0x%x%> passed " |
1998 | "to %<print_specific_help%>" , |
1999 | include_flags); |
2000 | return; |
2001 | } |
2002 | } |
2003 | else |
2004 | { |
2005 | if (any_flags & all_langs_mask) |
2006 | description = _("The following options are language-related" ); |
2007 | else |
2008 | description = _("The following options are language-independent" ); |
2009 | } |
2010 | } |
2011 | |
2012 | printf (format: "%s%s:\n" , description, descrip_extra); |
2013 | print_filtered_help (include_flags, exclude_flags, any_flags, |
2014 | columns: opts->x_help_columns, opts, lang_mask); |
2015 | } |
2016 | |
2017 | /* Enable FDO-related flags. */ |
2018 | |
2019 | static void |
2020 | enable_fdo_optimizations (struct gcc_options *opts, |
2021 | struct gcc_options *opts_set, |
2022 | int value) |
2023 | { |
2024 | SET_OPTION_IF_UNSET (opts, opts_set, flag_branch_probabilities, value); |
2025 | SET_OPTION_IF_UNSET (opts, opts_set, flag_profile_values, value); |
2026 | SET_OPTION_IF_UNSET (opts, opts_set, flag_unroll_loops, value); |
2027 | SET_OPTION_IF_UNSET (opts, opts_set, flag_peel_loops, value); |
2028 | SET_OPTION_IF_UNSET (opts, opts_set, flag_tracer, value); |
2029 | SET_OPTION_IF_UNSET (opts, opts_set, flag_value_profile_transformations, |
2030 | value); |
2031 | SET_OPTION_IF_UNSET (opts, opts_set, flag_inline_functions, value); |
2032 | SET_OPTION_IF_UNSET (opts, opts_set, flag_ipa_cp, value); |
2033 | if (value) |
2034 | { |
2035 | SET_OPTION_IF_UNSET (opts, opts_set, flag_ipa_cp_clone, 1); |
2036 | SET_OPTION_IF_UNSET (opts, opts_set, flag_ipa_bit_cp, 1); |
2037 | } |
2038 | SET_OPTION_IF_UNSET (opts, opts_set, flag_predictive_commoning, value); |
2039 | SET_OPTION_IF_UNSET (opts, opts_set, flag_split_loops, value); |
2040 | SET_OPTION_IF_UNSET (opts, opts_set, flag_unswitch_loops, value); |
2041 | SET_OPTION_IF_UNSET (opts, opts_set, flag_gcse_after_reload, value); |
2042 | SET_OPTION_IF_UNSET (opts, opts_set, flag_tree_loop_vectorize, value); |
2043 | SET_OPTION_IF_UNSET (opts, opts_set, flag_tree_slp_vectorize, value); |
2044 | SET_OPTION_IF_UNSET (opts, opts_set, flag_version_loops_for_strides, value); |
2045 | SET_OPTION_IF_UNSET (opts, opts_set, flag_vect_cost_model, |
2046 | VECT_COST_MODEL_DYNAMIC); |
2047 | SET_OPTION_IF_UNSET (opts, opts_set, flag_tree_loop_distribute_patterns, |
2048 | value); |
2049 | SET_OPTION_IF_UNSET (opts, opts_set, flag_loop_interchange, value); |
2050 | SET_OPTION_IF_UNSET (opts, opts_set, flag_unroll_jam, value); |
2051 | SET_OPTION_IF_UNSET (opts, opts_set, flag_tree_loop_distribution, value); |
2052 | } |
2053 | |
2054 | /* -f{,no-}sanitize{,-recover}= suboptions. */ |
2055 | const struct sanitizer_opts_s sanitizer_opts[] = |
2056 | { |
2057 | #define SANITIZER_OPT(name, flags, recover, trap) \ |
2058 | { #name, flags, sizeof #name - 1, recover, trap } |
2059 | SANITIZER_OPT (address, (SANITIZE_ADDRESS | SANITIZE_USER_ADDRESS), true, |
2060 | false), |
2061 | SANITIZER_OPT (hwaddress, (SANITIZE_HWADDRESS | SANITIZE_USER_HWADDRESS), |
2062 | true, false), |
2063 | SANITIZER_OPT (kernel-address, (SANITIZE_ADDRESS | SANITIZE_KERNEL_ADDRESS), |
2064 | true, false), |
2065 | SANITIZER_OPT (kernel-hwaddress, |
2066 | (SANITIZE_HWADDRESS | SANITIZE_KERNEL_HWADDRESS), |
2067 | true, false), |
2068 | SANITIZER_OPT (pointer-compare, SANITIZE_POINTER_COMPARE, true, false), |
2069 | SANITIZER_OPT (pointer-subtract, SANITIZE_POINTER_SUBTRACT, true, false), |
2070 | SANITIZER_OPT (thread, SANITIZE_THREAD, false, false), |
2071 | SANITIZER_OPT (leak, SANITIZE_LEAK, false, false), |
2072 | SANITIZER_OPT (shift, SANITIZE_SHIFT, true, true), |
2073 | SANITIZER_OPT (shift-base, SANITIZE_SHIFT_BASE, true, true), |
2074 | SANITIZER_OPT (shift-exponent, SANITIZE_SHIFT_EXPONENT, true, true), |
2075 | SANITIZER_OPT (integer-divide-by-zero, SANITIZE_DIVIDE, true, true), |
2076 | SANITIZER_OPT (undefined, SANITIZE_UNDEFINED, true, true), |
2077 | SANITIZER_OPT (unreachable, SANITIZE_UNREACHABLE, false, true), |
2078 | SANITIZER_OPT (vla-bound, SANITIZE_VLA, true, true), |
2079 | SANITIZER_OPT (return, SANITIZE_RETURN, false, true), |
2080 | SANITIZER_OPT (null, SANITIZE_NULL, true, true), |
2081 | SANITIZER_OPT (signed-integer-overflow, SANITIZE_SI_OVERFLOW, true, true), |
2082 | SANITIZER_OPT (bool, SANITIZE_BOOL, true, true), |
2083 | SANITIZER_OPT (enum, SANITIZE_ENUM, true, true), |
2084 | SANITIZER_OPT (float-divide-by-zero, SANITIZE_FLOAT_DIVIDE, true, true), |
2085 | SANITIZER_OPT (float-cast-overflow, SANITIZE_FLOAT_CAST, true, true), |
2086 | SANITIZER_OPT (bounds, SANITIZE_BOUNDS, true, true), |
2087 | SANITIZER_OPT (bounds-strict, SANITIZE_BOUNDS | SANITIZE_BOUNDS_STRICT, true, |
2088 | true), |
2089 | SANITIZER_OPT (alignment, SANITIZE_ALIGNMENT, true, true), |
2090 | SANITIZER_OPT (nonnull-attribute, SANITIZE_NONNULL_ATTRIBUTE, true, true), |
2091 | SANITIZER_OPT (returns-nonnull-attribute, SANITIZE_RETURNS_NONNULL_ATTRIBUTE, |
2092 | true, true), |
2093 | SANITIZER_OPT (object-size, SANITIZE_OBJECT_SIZE, true, true), |
2094 | SANITIZER_OPT (vptr, SANITIZE_VPTR, true, false), |
2095 | SANITIZER_OPT (pointer-overflow, SANITIZE_POINTER_OVERFLOW, true, true), |
2096 | SANITIZER_OPT (builtin, SANITIZE_BUILTIN, true, true), |
2097 | SANITIZER_OPT (shadow-call-stack, SANITIZE_SHADOW_CALL_STACK, false, false), |
2098 | SANITIZER_OPT (all, ~0U, true, true), |
2099 | #undef SANITIZER_OPT |
2100 | { NULL, .flag: 0U, .len: 0UL, .can_recover: false, .can_trap: false } |
2101 | }; |
2102 | |
2103 | /* -fzero-call-used-regs= suboptions. */ |
2104 | const struct zero_call_used_regs_opts_s zero_call_used_regs_opts[] = |
2105 | { |
2106 | #define ZERO_CALL_USED_REGS_OPT(name, flags) \ |
2107 | { #name, flags } |
2108 | ZERO_CALL_USED_REGS_OPT (skip, zero_regs_flags::SKIP), |
2109 | ZERO_CALL_USED_REGS_OPT (used-gpr-arg, zero_regs_flags::USED_GPR_ARG), |
2110 | ZERO_CALL_USED_REGS_OPT (used-gpr, zero_regs_flags::USED_GPR), |
2111 | ZERO_CALL_USED_REGS_OPT (used-arg, zero_regs_flags::USED_ARG), |
2112 | ZERO_CALL_USED_REGS_OPT (used, zero_regs_flags::USED), |
2113 | ZERO_CALL_USED_REGS_OPT (all-gpr-arg, zero_regs_flags::ALL_GPR_ARG), |
2114 | ZERO_CALL_USED_REGS_OPT (all-gpr, zero_regs_flags::ALL_GPR), |
2115 | ZERO_CALL_USED_REGS_OPT (all-arg, zero_regs_flags::ALL_ARG), |
2116 | ZERO_CALL_USED_REGS_OPT (all, zero_regs_flags::ALL), |
2117 | ZERO_CALL_USED_REGS_OPT (leafy-gpr-arg, zero_regs_flags::LEAFY_GPR_ARG), |
2118 | ZERO_CALL_USED_REGS_OPT (leafy-gpr, zero_regs_flags::LEAFY_GPR), |
2119 | ZERO_CALL_USED_REGS_OPT (leafy-arg, zero_regs_flags::LEAFY_ARG), |
2120 | ZERO_CALL_USED_REGS_OPT (leafy, zero_regs_flags::LEAFY), |
2121 | #undef ZERO_CALL_USED_REGS_OPT |
2122 | {NULL, .flag: 0U} |
2123 | }; |
2124 | |
2125 | /* A struct for describing a run of chars within a string. */ |
2126 | |
2127 | class string_fragment |
2128 | { |
2129 | public: |
2130 | string_fragment (const char *start, size_t len) |
2131 | : m_start (start), m_len (len) {} |
2132 | |
2133 | const char *m_start; |
2134 | size_t m_len; |
2135 | }; |
2136 | |
2137 | /* Specialization of edit_distance_traits for string_fragment, |
2138 | for use by get_closest_sanitizer_option. */ |
2139 | |
2140 | template <> |
2141 | struct edit_distance_traits<const string_fragment &> |
2142 | { |
2143 | static size_t get_length (const string_fragment &fragment) |
2144 | { |
2145 | return fragment.m_len; |
2146 | } |
2147 | |
2148 | static const char *get_string (const string_fragment &fragment) |
2149 | { |
2150 | return fragment.m_start; |
2151 | } |
2152 | }; |
2153 | |
2154 | /* Given ARG, an unrecognized sanitizer option, return the best |
2155 | matching sanitizer option, or NULL if there isn't one. |
2156 | OPTS is array of candidate sanitizer options. |
2157 | CODE is OPT_fsanitize_, OPT_fsanitize_recover_ or OPT_fsanitize_trap_. |
2158 | VALUE is non-zero for the regular form of the option, zero |
2159 | for the "no-" form (e.g. "-fno-sanitize-recover="). */ |
2160 | |
2161 | static const char * |
2162 | get_closest_sanitizer_option (const string_fragment &arg, |
2163 | const struct sanitizer_opts_s *opts, |
2164 | enum opt_code code, int value) |
2165 | { |
2166 | best_match <const string_fragment &, const char*> bm (arg); |
2167 | for (int i = 0; opts[i].name != NULL; ++i) |
2168 | { |
2169 | /* -fsanitize=all is not valid, so don't offer it. */ |
2170 | if (code == OPT_fsanitize_ |
2171 | && opts[i].flag == ~0U |
2172 | && value) |
2173 | continue; |
2174 | |
2175 | /* For -fsanitize-recover= (and not -fno-sanitize-recover=), |
2176 | don't offer the non-recoverable options. */ |
2177 | if (code == OPT_fsanitize_recover_ |
2178 | && !opts[i].can_recover |
2179 | && value) |
2180 | continue; |
2181 | |
2182 | /* For -fsanitize-trap= (and not -fno-sanitize-trap=), |
2183 | don't offer the non-trapping options. */ |
2184 | if (code == OPT_fsanitize_trap_ |
2185 | && !opts[i].can_trap |
2186 | && value) |
2187 | continue; |
2188 | |
2189 | bm.consider (candidate: opts[i].name); |
2190 | } |
2191 | return bm.get_best_meaningful_candidate (); |
2192 | } |
2193 | |
2194 | /* Parse comma separated sanitizer suboptions from P for option SCODE, |
2195 | adjust previous FLAGS and return new ones. If COMPLAIN is false, |
2196 | don't issue diagnostics. */ |
2197 | |
2198 | unsigned int |
2199 | parse_sanitizer_options (const char *p, location_t loc, int scode, |
2200 | unsigned int flags, int value, bool complain) |
2201 | { |
2202 | enum opt_code code = (enum opt_code) scode; |
2203 | |
2204 | while (*p != 0) |
2205 | { |
2206 | size_t len, i; |
2207 | bool found = false; |
2208 | const char *comma = strchr (s: p, c: ','); |
2209 | |
2210 | if (comma == NULL) |
2211 | len = strlen (s: p); |
2212 | else |
2213 | len = comma - p; |
2214 | if (len == 0) |
2215 | { |
2216 | p = comma + 1; |
2217 | continue; |
2218 | } |
2219 | |
2220 | /* Check to see if the string matches an option class name. */ |
2221 | for (i = 0; sanitizer_opts[i].name != NULL; ++i) |
2222 | if (len == sanitizer_opts[i].len |
2223 | && memcmp (s1: p, s2: sanitizer_opts[i].name, n: len) == 0) |
2224 | { |
2225 | /* Handle both -fsanitize and -fno-sanitize cases. */ |
2226 | if (value && sanitizer_opts[i].flag == ~0U) |
2227 | { |
2228 | if (code == OPT_fsanitize_) |
2229 | { |
2230 | if (complain) |
2231 | error_at (loc, "%<-fsanitize=all%> option is not valid" ); |
2232 | } |
2233 | else if (code == OPT_fsanitize_recover_) |
2234 | flags |= ~(SANITIZE_THREAD | SANITIZE_LEAK |
2235 | | SANITIZE_UNREACHABLE | SANITIZE_RETURN |
2236 | | SANITIZE_SHADOW_CALL_STACK); |
2237 | else /* if (code == OPT_fsanitize_trap_) */ |
2238 | flags |= (SANITIZE_UNDEFINED |
2239 | | SANITIZE_UNDEFINED_NONDEFAULT); |
2240 | } |
2241 | else if (value) |
2242 | { |
2243 | /* Do not enable -fsanitize-recover=unreachable and |
2244 | -fsanitize-recover=return if -fsanitize-recover=undefined |
2245 | is selected. */ |
2246 | if (code == OPT_fsanitize_recover_ |
2247 | && sanitizer_opts[i].flag == SANITIZE_UNDEFINED) |
2248 | flags |= (SANITIZE_UNDEFINED |
2249 | & ~(SANITIZE_UNREACHABLE | SANITIZE_RETURN)); |
2250 | else if (code == OPT_fsanitize_trap_ |
2251 | && sanitizer_opts[i].flag == SANITIZE_VPTR) |
2252 | error_at (loc, "%<-fsanitize-trap=%s%> is not supported" , |
2253 | sanitizer_opts[i].name); |
2254 | else |
2255 | flags |= sanitizer_opts[i].flag; |
2256 | } |
2257 | else |
2258 | { |
2259 | flags &= ~sanitizer_opts[i].flag; |
2260 | /* Don't always clear SANITIZE_ADDRESS if it was previously |
2261 | set: -fsanitize=address -fno-sanitize=kernel-address should |
2262 | leave SANITIZE_ADDRESS set. */ |
2263 | if (flags & (SANITIZE_KERNEL_ADDRESS | SANITIZE_USER_ADDRESS)) |
2264 | flags |= SANITIZE_ADDRESS; |
2265 | } |
2266 | found = true; |
2267 | break; |
2268 | } |
2269 | |
2270 | if (! found && complain) |
2271 | { |
2272 | const char *hint |
2273 | = get_closest_sanitizer_option (arg: string_fragment (p, len), |
2274 | opts: sanitizer_opts, code, value); |
2275 | |
2276 | const char *suffix; |
2277 | if (code == OPT_fsanitize_recover_) |
2278 | suffix = "-recover" ; |
2279 | else if (code == OPT_fsanitize_trap_) |
2280 | suffix = "-trap" ; |
2281 | else |
2282 | suffix = "" ; |
2283 | |
2284 | if (hint) |
2285 | error_at (loc, |
2286 | "unrecognized argument to %<-f%ssanitize%s=%> " |
2287 | "option: %q.*s; did you mean %qs?" , |
2288 | value ? "" : "no-" , |
2289 | suffix, (int) len, p, hint); |
2290 | else |
2291 | error_at (loc, |
2292 | "unrecognized argument to %<-f%ssanitize%s=%> option: " |
2293 | "%q.*s" , value ? "" : "no-" , |
2294 | suffix, (int) len, p); |
2295 | } |
2296 | |
2297 | if (comma == NULL) |
2298 | break; |
2299 | p = comma + 1; |
2300 | } |
2301 | return flags; |
2302 | } |
2303 | |
2304 | /* Parse string values of no_sanitize attribute passed in VALUE. |
2305 | Values are separated with comma. */ |
2306 | |
2307 | unsigned int |
2308 | parse_no_sanitize_attribute (char *value) |
2309 | { |
2310 | unsigned int flags = 0; |
2311 | unsigned int i; |
2312 | char *q = strtok (s: value, delim: "," ); |
2313 | |
2314 | while (q != NULL) |
2315 | { |
2316 | for (i = 0; sanitizer_opts[i].name != NULL; ++i) |
2317 | if (strcmp (s1: sanitizer_opts[i].name, s2: q) == 0) |
2318 | { |
2319 | flags |= sanitizer_opts[i].flag; |
2320 | if (sanitizer_opts[i].flag == SANITIZE_UNDEFINED) |
2321 | flags |= SANITIZE_UNDEFINED_NONDEFAULT; |
2322 | break; |
2323 | } |
2324 | |
2325 | if (sanitizer_opts[i].name == NULL) |
2326 | warning (OPT_Wattributes, |
2327 | "%qs attribute directive ignored" , q); |
2328 | |
2329 | q = strtok (NULL, delim: "," ); |
2330 | } |
2331 | |
2332 | return flags; |
2333 | } |
2334 | |
2335 | /* Parse -fzero-call-used-regs suboptions from ARG, return the FLAGS. */ |
2336 | |
2337 | unsigned int |
2338 | parse_zero_call_used_regs_options (const char *arg) |
2339 | { |
2340 | unsigned int flags = 0; |
2341 | |
2342 | /* Check to see if the string matches a sub-option name. */ |
2343 | for (unsigned int i = 0; zero_call_used_regs_opts[i].name != NULL; ++i) |
2344 | if (strcmp (s1: arg, s2: zero_call_used_regs_opts[i].name) == 0) |
2345 | { |
2346 | flags = zero_call_used_regs_opts[i].flag; |
2347 | break; |
2348 | } |
2349 | |
2350 | if (!flags) |
2351 | error ("unrecognized argument to %<-fzero-call-used-regs=%>: %qs" , arg); |
2352 | |
2353 | return flags; |
2354 | } |
2355 | |
2356 | /* Parse -falign-NAME format for a FLAG value. Return individual |
2357 | parsed integer values into RESULT_VALUES array. If REPORT_ERROR is |
2358 | set, print error message at LOC location. */ |
2359 | |
2360 | bool |
2361 | parse_and_check_align_values (const char *flag, |
2362 | const char *name, |
2363 | auto_vec<unsigned> &result_values, |
2364 | bool report_error, |
2365 | location_t loc) |
2366 | { |
2367 | char *str = xstrdup (flag); |
2368 | for (char *p = strtok (s: str, delim: ":" ); p; p = strtok (NULL, delim: ":" )) |
2369 | { |
2370 | char *end; |
2371 | int v = strtol (nptr: p, endptr: &end, base: 10); |
2372 | if (*end != '\0' || v < 0) |
2373 | { |
2374 | if (report_error) |
2375 | error_at (loc, "invalid arguments for %<-falign-%s%> option: %qs" , |
2376 | name, flag); |
2377 | |
2378 | return false; |
2379 | } |
2380 | |
2381 | result_values.safe_push (obj: (unsigned)v); |
2382 | } |
2383 | |
2384 | free (ptr: str); |
2385 | |
2386 | /* Check that we have a correct number of values. */ |
2387 | if (result_values.is_empty () || result_values.length () > 4) |
2388 | { |
2389 | if (report_error) |
2390 | error_at (loc, "invalid number of arguments for %<-falign-%s%> " |
2391 | "option: %qs" , name, flag); |
2392 | return false; |
2393 | } |
2394 | |
2395 | for (unsigned i = 0; i < result_values.length (); i++) |
2396 | if (result_values[i] > MAX_CODE_ALIGN_VALUE) |
2397 | { |
2398 | if (report_error) |
2399 | error_at (loc, "%<-falign-%s%> is not between 0 and %d" , |
2400 | name, MAX_CODE_ALIGN_VALUE); |
2401 | return false; |
2402 | } |
2403 | |
2404 | return true; |
2405 | } |
2406 | |
2407 | /* Check that alignment value FLAG for -falign-NAME is valid at a given |
2408 | location LOC. OPT_STR points to the stored -falign-NAME=argument and |
2409 | OPT_FLAG points to the associated -falign-NAME on/off flag. */ |
2410 | |
2411 | static void |
2412 | check_alignment_argument (location_t loc, const char *flag, const char *name, |
2413 | int *opt_flag, const char **opt_str) |
2414 | { |
2415 | auto_vec<unsigned> align_result; |
2416 | parse_and_check_align_values (flag, name, result_values&: align_result, report_error: true, loc); |
2417 | |
2418 | if (align_result.length() >= 1 && align_result[0] == 0) |
2419 | { |
2420 | *opt_flag = 1; |
2421 | *opt_str = NULL; |
2422 | } |
2423 | } |
2424 | |
2425 | /* Parse argument of -fpatchable-function-entry option ARG and store |
2426 | corresponding values to PATCH_AREA_SIZE and PATCH_AREA_START. |
2427 | If REPORT_ERROR is set to true, generate error for a problematic |
2428 | option arguments. */ |
2429 | |
2430 | void |
2431 | parse_and_check_patch_area (const char *arg, bool report_error, |
2432 | HOST_WIDE_INT *patch_area_size, |
2433 | HOST_WIDE_INT *patch_area_start) |
2434 | { |
2435 | *patch_area_size = 0; |
2436 | *patch_area_start = 0; |
2437 | |
2438 | if (arg == NULL) |
2439 | return; |
2440 | |
2441 | char *patch_area_arg = xstrdup (arg); |
2442 | char *comma = strchr (s: patch_area_arg, c: ','); |
2443 | if (comma) |
2444 | { |
2445 | *comma = '\0'; |
2446 | *patch_area_size = integral_argument (arg: patch_area_arg); |
2447 | *patch_area_start = integral_argument (arg: comma + 1); |
2448 | } |
2449 | else |
2450 | *patch_area_size = integral_argument (arg: patch_area_arg); |
2451 | |
2452 | if (*patch_area_size < 0 |
2453 | || *patch_area_size > USHRT_MAX |
2454 | || *patch_area_start < 0 |
2455 | || *patch_area_start > USHRT_MAX |
2456 | || *patch_area_size < *patch_area_start) |
2457 | if (report_error) |
2458 | error ("invalid arguments for %<-fpatchable-function-entry%>" ); |
2459 | |
2460 | free (ptr: patch_area_arg); |
2461 | } |
2462 | |
2463 | /* Print help when OPT__help_ is set. */ |
2464 | |
2465 | void |
2466 | print_help (struct gcc_options *opts, unsigned int lang_mask, |
2467 | const char *help_option_argument) |
2468 | { |
2469 | const char *a = help_option_argument; |
2470 | unsigned int include_flags = 0; |
2471 | /* Note - by default we include undocumented options when listing |
2472 | specific classes. If you only want to see documented options |
2473 | then add ",^undocumented" to the --help= option. E.g.: |
2474 | |
2475 | --help=target,^undocumented */ |
2476 | unsigned int exclude_flags = 0; |
2477 | |
2478 | if (lang_mask == CL_DRIVER) |
2479 | return; |
2480 | |
2481 | /* Walk along the argument string, parsing each word in turn. |
2482 | The format is: |
2483 | arg = [^]{word}[,{arg}] |
2484 | word = {optimizers|target|warnings|undocumented| |
2485 | params|common|<language>} */ |
2486 | while (*a != 0) |
2487 | { |
2488 | static const struct |
2489 | { |
2490 | const char *string; |
2491 | unsigned int flag; |
2492 | } |
2493 | specifics[] = |
2494 | { |
2495 | { .string: "optimizers" , CL_OPTIMIZATION }, |
2496 | { .string: "target" , CL_TARGET }, |
2497 | { .string: "warnings" , CL_WARNING }, |
2498 | { .string: "undocumented" , CL_UNDOCUMENTED }, |
2499 | { .string: "params" , CL_PARAMS }, |
2500 | { .string: "joined" , CL_JOINED }, |
2501 | { .string: "separate" , CL_SEPARATE }, |
2502 | { .string: "common" , CL_COMMON }, |
2503 | { NULL, .flag: 0 } |
2504 | }; |
2505 | unsigned int *pflags; |
2506 | const char *comma; |
2507 | unsigned int lang_flag, specific_flag; |
2508 | unsigned int len; |
2509 | unsigned int i; |
2510 | |
2511 | if (*a == '^') |
2512 | { |
2513 | ++a; |
2514 | if (*a == '\0') |
2515 | { |
2516 | error ("missing argument to %qs" , "--help=^" ); |
2517 | break; |
2518 | } |
2519 | pflags = &exclude_flags; |
2520 | } |
2521 | else |
2522 | pflags = &include_flags; |
2523 | |
2524 | comma = strchr (s: a, c: ','); |
2525 | if (comma == NULL) |
2526 | len = strlen (s: a); |
2527 | else |
2528 | len = comma - a; |
2529 | if (len == 0) |
2530 | { |
2531 | a = comma + 1; |
2532 | continue; |
2533 | } |
2534 | |
2535 | /* Check to see if the string matches an option class name. */ |
2536 | for (i = 0, specific_flag = 0; specifics[i].string != NULL; i++) |
2537 | if (strncasecmp (s1: a, s2: specifics[i].string, n: len) == 0) |
2538 | { |
2539 | specific_flag = specifics[i].flag; |
2540 | break; |
2541 | } |
2542 | |
2543 | /* Check to see if the string matches a language name. |
2544 | Note - we rely upon the alpha-sorted nature of the entries in |
2545 | the lang_names array, specifically that shorter names appear |
2546 | before their longer variants. (i.e. C before C++). That way |
2547 | when we are attempting to match --help=c for example we will |
2548 | match with C first and not C++. */ |
2549 | for (i = 0, lang_flag = 0; i < cl_lang_count; i++) |
2550 | if (strncasecmp (s1: a, s2: lang_names[i], n: len) == 0) |
2551 | { |
2552 | lang_flag = 1U << i; |
2553 | break; |
2554 | } |
2555 | |
2556 | if (specific_flag != 0) |
2557 | { |
2558 | if (lang_flag == 0) |
2559 | *pflags |= specific_flag; |
2560 | else |
2561 | { |
2562 | /* The option's argument matches both the start of a |
2563 | language name and the start of an option class name. |
2564 | We have a special case for when the user has |
2565 | specified "--help=c", but otherwise we have to issue |
2566 | a warning. */ |
2567 | if (strncasecmp (s1: a, s2: "c" , n: len) == 0) |
2568 | *pflags |= lang_flag; |
2569 | else |
2570 | warning (0, |
2571 | "%<--help%> argument %q.*s is ambiguous, " |
2572 | "please be more specific" , |
2573 | len, a); |
2574 | } |
2575 | } |
2576 | else if (lang_flag != 0) |
2577 | *pflags |= lang_flag; |
2578 | else |
2579 | warning (0, |
2580 | "unrecognized argument to %<--help=%> option: %q.*s" , |
2581 | len, a); |
2582 | |
2583 | if (comma == NULL) |
2584 | break; |
2585 | a = comma + 1; |
2586 | } |
2587 | |
2588 | /* We started using PerFunction/Optimization for parameters and |
2589 | a warning. We should exclude these from optimization options. */ |
2590 | if (include_flags & CL_OPTIMIZATION) |
2591 | exclude_flags |= CL_WARNING; |
2592 | if (!(include_flags & CL_PARAMS)) |
2593 | exclude_flags |= CL_PARAMS; |
2594 | |
2595 | if (include_flags) |
2596 | print_specific_help (include_flags, exclude_flags, any_flags: 0, opts, |
2597 | lang_mask); |
2598 | } |
2599 | |
2600 | /* Handle target- and language-independent options. Return zero to |
2601 | generate an "unknown option" message. Only options that need |
2602 | extra handling need to be listed here; if you simply want |
2603 | DECODED->value assigned to a variable, it happens automatically. */ |
2604 | |
2605 | bool |
2606 | common_handle_option (struct gcc_options *opts, |
2607 | struct gcc_options *opts_set, |
2608 | const struct cl_decoded_option *decoded, |
2609 | unsigned int lang_mask, int kind ATTRIBUTE_UNUSED, |
2610 | location_t loc, |
2611 | const struct cl_option_handlers *handlers, |
2612 | diagnostic_context *dc, |
2613 | void (*target_option_override_hook) (void)) |
2614 | { |
2615 | size_t scode = decoded->opt_index; |
2616 | const char *arg = decoded->arg; |
2617 | HOST_WIDE_INT value = decoded->value; |
2618 | enum opt_code code = (enum opt_code) scode; |
2619 | |
2620 | gcc_assert (decoded->canonical_option_num_elements <= 2); |
2621 | |
2622 | switch (code) |
2623 | { |
2624 | case OPT__help: |
2625 | { |
2626 | unsigned int all_langs_mask = (1U << cl_lang_count) - 1; |
2627 | unsigned int undoc_mask; |
2628 | unsigned int i; |
2629 | |
2630 | if (lang_mask == CL_DRIVER) |
2631 | break; |
2632 | |
2633 | undoc_mask = ((opts->x_verbose_flag | opts->x_extra_warnings) |
2634 | ? 0 |
2635 | : CL_UNDOCUMENTED); |
2636 | target_option_override_hook (); |
2637 | /* First display any single language specific options. */ |
2638 | for (i = 0; i < cl_lang_count; i++) |
2639 | print_specific_help |
2640 | (include_flags: 1U << i, exclude_flags: (all_langs_mask & (~ (1U << i))) | undoc_mask, any_flags: 0, opts, |
2641 | lang_mask); |
2642 | /* Next display any multi language specific options. */ |
2643 | print_specific_help (include_flags: 0, exclude_flags: undoc_mask, any_flags: all_langs_mask, opts, lang_mask); |
2644 | /* Then display any remaining, non-language options. */ |
2645 | for (i = CL_MIN_OPTION_CLASS; i <= CL_MAX_OPTION_CLASS; i <<= 1) |
2646 | if (i != CL_DRIVER) |
2647 | print_specific_help (include_flags: i, exclude_flags: undoc_mask, any_flags: 0, opts, lang_mask); |
2648 | opts->x_exit_after_options = true; |
2649 | break; |
2650 | } |
2651 | |
2652 | case OPT__target_help: |
2653 | if (lang_mask == CL_DRIVER) |
2654 | break; |
2655 | |
2656 | target_option_override_hook (); |
2657 | print_specific_help (CL_TARGET, exclude_flags: 0, any_flags: 0, opts, lang_mask); |
2658 | opts->x_exit_after_options = true; |
2659 | break; |
2660 | |
2661 | case OPT__help_: |
2662 | { |
2663 | help_option_arguments.safe_push (obj: arg); |
2664 | opts->x_exit_after_options = true; |
2665 | break; |
2666 | } |
2667 | |
2668 | case OPT__version: |
2669 | if (lang_mask == CL_DRIVER) |
2670 | break; |
2671 | |
2672 | opts->x_exit_after_options = true; |
2673 | break; |
2674 | |
2675 | case OPT__completion_: |
2676 | break; |
2677 | |
2678 | case OPT_fsanitize_: |
2679 | opts_set->x_flag_sanitize = true; |
2680 | opts->x_flag_sanitize |
2681 | = parse_sanitizer_options (p: arg, loc, scode: code, |
2682 | flags: opts->x_flag_sanitize, value, complain: true); |
2683 | |
2684 | /* Kernel ASan implies normal ASan but does not yet support |
2685 | all features. */ |
2686 | if (opts->x_flag_sanitize & SANITIZE_KERNEL_ADDRESS) |
2687 | { |
2688 | SET_OPTION_IF_UNSET (opts, opts_set, |
2689 | param_asan_instrumentation_with_call_threshold, |
2690 | 0); |
2691 | SET_OPTION_IF_UNSET (opts, opts_set, param_asan_globals, 0); |
2692 | SET_OPTION_IF_UNSET (opts, opts_set, param_asan_stack, 0); |
2693 | SET_OPTION_IF_UNSET (opts, opts_set, param_asan_protect_allocas, 0); |
2694 | SET_OPTION_IF_UNSET (opts, opts_set, param_asan_use_after_return, 0); |
2695 | } |
2696 | if (opts->x_flag_sanitize & SANITIZE_KERNEL_HWADDRESS) |
2697 | { |
2698 | SET_OPTION_IF_UNSET (opts, opts_set, |
2699 | param_hwasan_instrument_stack, 0); |
2700 | SET_OPTION_IF_UNSET (opts, opts_set, |
2701 | param_hwasan_random_frame_tag, 0); |
2702 | SET_OPTION_IF_UNSET (opts, opts_set, |
2703 | param_hwasan_instrument_allocas, 0); |
2704 | } |
2705 | break; |
2706 | |
2707 | case OPT_fsanitize_recover_: |
2708 | opts->x_flag_sanitize_recover |
2709 | = parse_sanitizer_options (p: arg, loc, scode: code, |
2710 | flags: opts->x_flag_sanitize_recover, value, complain: true); |
2711 | break; |
2712 | |
2713 | case OPT_fsanitize_trap_: |
2714 | opts->x_flag_sanitize_trap |
2715 | = parse_sanitizer_options (p: arg, loc, scode: code, |
2716 | flags: opts->x_flag_sanitize_trap, value, complain: true); |
2717 | break; |
2718 | |
2719 | case OPT_fasan_shadow_offset_: |
2720 | /* Deferred. */ |
2721 | break; |
2722 | |
2723 | case OPT_fsanitize_address_use_after_scope: |
2724 | opts->x_flag_sanitize_address_use_after_scope = value; |
2725 | break; |
2726 | |
2727 | case OPT_fsanitize_recover: |
2728 | if (value) |
2729 | opts->x_flag_sanitize_recover |
2730 | |= (SANITIZE_UNDEFINED | SANITIZE_UNDEFINED_NONDEFAULT) |
2731 | & ~(SANITIZE_UNREACHABLE | SANITIZE_RETURN); |
2732 | else |
2733 | opts->x_flag_sanitize_recover |
2734 | &= ~(SANITIZE_UNDEFINED | SANITIZE_UNDEFINED_NONDEFAULT); |
2735 | break; |
2736 | |
2737 | case OPT_fsanitize_trap: |
2738 | if (value) |
2739 | opts->x_flag_sanitize_trap |
2740 | |= (SANITIZE_UNDEFINED | SANITIZE_UNDEFINED_NONDEFAULT); |
2741 | else |
2742 | opts->x_flag_sanitize_trap |
2743 | &= ~(SANITIZE_UNDEFINED | SANITIZE_UNDEFINED_NONDEFAULT); |
2744 | break; |
2745 | |
2746 | case OPT_O: |
2747 | case OPT_Os: |
2748 | case OPT_Ofast: |
2749 | case OPT_Og: |
2750 | case OPT_Oz: |
2751 | /* Currently handled in a prescan. */ |
2752 | break; |
2753 | |
2754 | case OPT_Wattributes_: |
2755 | if (lang_mask == CL_DRIVER) |
2756 | break; |
2757 | |
2758 | if (value) |
2759 | { |
2760 | error_at (loc, "arguments ignored for %<-Wattributes=%>; use " |
2761 | "%<-Wno-attributes=%> instead" ); |
2762 | break; |
2763 | } |
2764 | else if (arg[strlen (s: arg) - 1] == ',') |
2765 | { |
2766 | error_at (loc, "trailing %<,%> in arguments for " |
2767 | "%<-Wno-attributes=%>" ); |
2768 | break; |
2769 | } |
2770 | |
2771 | add_comma_separated_to_vector (pvec: &opts->x_flag_ignored_attributes, arg); |
2772 | break; |
2773 | |
2774 | case OPT_Werror: |
2775 | dc->set_warning_as_error_requested (value); |
2776 | break; |
2777 | |
2778 | case OPT_Werror_: |
2779 | if (lang_mask == CL_DRIVER) |
2780 | break; |
2781 | |
2782 | enable_warning_as_error (arg, value, lang_mask, handlers, |
2783 | opts, opts_set, loc, dc); |
2784 | break; |
2785 | |
2786 | case OPT_Wfatal_errors: |
2787 | dc->m_fatal_errors = value; |
2788 | break; |
2789 | |
2790 | case OPT_Wstack_usage_: |
2791 | opts->x_flag_stack_usage_info = value != -1; |
2792 | break; |
2793 | |
2794 | case OPT_Wstrict_aliasing: |
2795 | set_Wstrict_aliasing (opts, onoff: value); |
2796 | break; |
2797 | |
2798 | case OPT_Wstrict_overflow: |
2799 | opts->x_warn_strict_overflow = (value |
2800 | ? (int) WARN_STRICT_OVERFLOW_CONDITIONAL |
2801 | : 0); |
2802 | break; |
2803 | |
2804 | case OPT_Wsystem_headers: |
2805 | dc->m_warn_system_headers = value; |
2806 | break; |
2807 | |
2808 | case OPT_aux_info: |
2809 | opts->x_flag_gen_aux_info = 1; |
2810 | break; |
2811 | |
2812 | case OPT_d: |
2813 | decode_d_option (arg, opts, loc, dc); |
2814 | break; |
2815 | |
2816 | case OPT_fcall_used_: |
2817 | case OPT_fcall_saved_: |
2818 | /* Deferred. */ |
2819 | break; |
2820 | |
2821 | case OPT_fdbg_cnt_: |
2822 | /* Deferred. */ |
2823 | break; |
2824 | |
2825 | case OPT_fdebug_prefix_map_: |
2826 | case OPT_ffile_prefix_map_: |
2827 | case OPT_fprofile_prefix_map_: |
2828 | /* Deferred. */ |
2829 | break; |
2830 | |
2831 | case OPT_fcanon_prefix_map: |
2832 | flag_canon_prefix_map = value; |
2833 | break; |
2834 | |
2835 | case OPT_fcallgraph_info: |
2836 | opts->x_flag_callgraph_info = CALLGRAPH_INFO_NAKED; |
2837 | break; |
2838 | |
2839 | case OPT_fcallgraph_info_: |
2840 | { |
2841 | char *my_arg, *p; |
2842 | my_arg = xstrdup (arg); |
2843 | p = strtok (s: my_arg, delim: "," ); |
2844 | while (p) |
2845 | { |
2846 | if (strcmp (s1: p, s2: "su" ) == 0) |
2847 | { |
2848 | opts->x_flag_callgraph_info |= CALLGRAPH_INFO_STACK_USAGE; |
2849 | opts->x_flag_stack_usage_info = true; |
2850 | } |
2851 | else if (strcmp (s1: p, s2: "da" ) == 0) |
2852 | opts->x_flag_callgraph_info |= CALLGRAPH_INFO_DYNAMIC_ALLOC; |
2853 | else |
2854 | return 0; |
2855 | p = strtok (NULL, delim: "," ); |
2856 | } |
2857 | free (ptr: my_arg); |
2858 | } |
2859 | break; |
2860 | |
2861 | case OPT_fdiagnostics_show_location_: |
2862 | diagnostic_prefixing_rule (dc) = (diagnostic_prefixing_rule_t) value; |
2863 | break; |
2864 | |
2865 | case OPT_fdiagnostics_show_caret: |
2866 | dc->m_source_printing.enabled = value; |
2867 | break; |
2868 | |
2869 | case OPT_fdiagnostics_show_labels: |
2870 | dc->m_source_printing.show_labels_p = value; |
2871 | break; |
2872 | |
2873 | case OPT_fdiagnostics_show_line_numbers: |
2874 | dc->m_source_printing.show_line_numbers_p = value; |
2875 | break; |
2876 | |
2877 | case OPT_fdiagnostics_color_: |
2878 | diagnostic_color_init (context: dc, value); |
2879 | break; |
2880 | |
2881 | case OPT_fdiagnostics_urls_: |
2882 | diagnostic_urls_init (context: dc, value); |
2883 | break; |
2884 | |
2885 | case OPT_fdiagnostics_format_: |
2886 | { |
2887 | const char *basename = (opts->x_dump_base_name ? opts->x_dump_base_name |
2888 | : opts->x_main_input_basename); |
2889 | diagnostic_output_format_init (dc, base_file_name: basename, |
2890 | (enum diagnostics_output_format)value); |
2891 | break; |
2892 | } |
2893 | |
2894 | case OPT_fdiagnostics_text_art_charset_: |
2895 | dc->set_text_art_charset ((enum diagnostic_text_art_charset)value); |
2896 | break; |
2897 | |
2898 | case OPT_fdiagnostics_parseable_fixits: |
2899 | dc->set_extra_output_kind (value |
2900 | ? EXTRA_DIAGNOSTIC_OUTPUT_fixits_v1 |
2901 | : EXTRA_DIAGNOSTIC_OUTPUT_none); |
2902 | break; |
2903 | |
2904 | case OPT_fdiagnostics_column_unit_: |
2905 | dc->m_column_unit = (enum diagnostics_column_unit)value; |
2906 | break; |
2907 | |
2908 | case OPT_fdiagnostics_column_origin_: |
2909 | dc->m_column_origin = value; |
2910 | break; |
2911 | |
2912 | case OPT_fdiagnostics_escape_format_: |
2913 | dc->set_escape_format ((enum diagnostics_escape_format)value); |
2914 | break; |
2915 | |
2916 | case OPT_fdiagnostics_show_cwe: |
2917 | dc->set_show_cwe (value); |
2918 | break; |
2919 | |
2920 | case OPT_fdiagnostics_show_rules: |
2921 | dc->set_show_rules (value); |
2922 | break; |
2923 | |
2924 | case OPT_fdiagnostics_path_format_: |
2925 | dc->set_path_format ((enum diagnostic_path_format)value); |
2926 | break; |
2927 | |
2928 | case OPT_fdiagnostics_show_path_depths: |
2929 | dc->set_show_path_depths (value); |
2930 | break; |
2931 | |
2932 | case OPT_fdiagnostics_show_option: |
2933 | dc->set_show_option_requested (value); |
2934 | break; |
2935 | |
2936 | case OPT_fdiagnostics_minimum_margin_width_: |
2937 | dc->m_source_printing.min_margin_width = value; |
2938 | break; |
2939 | |
2940 | case OPT_fdump_: |
2941 | /* Deferred. */ |
2942 | break; |
2943 | |
2944 | case OPT_ffast_math: |
2945 | set_fast_math_flags (opts, set: value); |
2946 | break; |
2947 | |
2948 | case OPT_funsafe_math_optimizations: |
2949 | set_unsafe_math_optimizations_flags (opts, set: value); |
2950 | break; |
2951 | |
2952 | case OPT_ffixed_: |
2953 | /* Deferred. */ |
2954 | break; |
2955 | |
2956 | case OPT_finline_limit_: |
2957 | SET_OPTION_IF_UNSET (opts, opts_set, param_max_inline_insns_single, |
2958 | value / 2); |
2959 | SET_OPTION_IF_UNSET (opts, opts_set, param_max_inline_insns_auto, |
2960 | value / 2); |
2961 | break; |
2962 | |
2963 | case OPT_finstrument_functions_exclude_function_list_: |
2964 | add_comma_separated_to_vector |
2965 | (pvec: &opts->x_flag_instrument_functions_exclude_functions, arg); |
2966 | break; |
2967 | |
2968 | case OPT_finstrument_functions_exclude_file_list_: |
2969 | add_comma_separated_to_vector |
2970 | (pvec: &opts->x_flag_instrument_functions_exclude_files, arg); |
2971 | break; |
2972 | |
2973 | case OPT_fmessage_length_: |
2974 | pp_set_line_maximum_length (dc->printer, value); |
2975 | diagnostic_set_caret_max_width (context: dc, value); |
2976 | break; |
2977 | |
2978 | case OPT_fopt_info: |
2979 | case OPT_fopt_info_: |
2980 | /* Deferred. */ |
2981 | break; |
2982 | |
2983 | case OPT_foffload_options_: |
2984 | /* Deferred. */ |
2985 | break; |
2986 | |
2987 | case OPT_foffload_abi_: |
2988 | #ifdef ACCEL_COMPILER |
2989 | /* Handled in the 'mkoffload's. */ |
2990 | #else |
2991 | error_at (loc, "%<-foffload-abi%> option can be specified only for " |
2992 | "offload compiler" ); |
2993 | #endif |
2994 | break; |
2995 | |
2996 | case OPT_fpack_struct_: |
2997 | if (value <= 0 || (value & (value - 1)) || value > 16) |
2998 | error_at (loc, |
2999 | "structure alignment must be a small power of two, not %wu" , |
3000 | value); |
3001 | else |
3002 | opts->x_initial_max_fld_align = value; |
3003 | break; |
3004 | |
3005 | case OPT_fplugin_: |
3006 | case OPT_fplugin_arg_: |
3007 | /* Deferred. */ |
3008 | break; |
3009 | |
3010 | case OPT_fprofile_use_: |
3011 | opts->x_profile_data_prefix = xstrdup (arg); |
3012 | opts->x_flag_profile_use = true; |
3013 | value = true; |
3014 | /* No break here - do -fprofile-use processing. */ |
3015 | /* FALLTHRU */ |
3016 | case OPT_fprofile_use: |
3017 | enable_fdo_optimizations (opts, opts_set, value); |
3018 | SET_OPTION_IF_UNSET (opts, opts_set, flag_profile_reorder_functions, |
3019 | value); |
3020 | /* Indirect call profiling should do all useful transformations |
3021 | speculative devirtualization does. */ |
3022 | if (opts->x_flag_value_profile_transformations) |
3023 | SET_OPTION_IF_UNSET (opts, opts_set, flag_devirtualize_speculatively, |
3024 | false); |
3025 | break; |
3026 | |
3027 | case OPT_fauto_profile_: |
3028 | opts->x_auto_profile_file = xstrdup (arg); |
3029 | opts->x_flag_auto_profile = true; |
3030 | value = true; |
3031 | /* No break here - do -fauto-profile processing. */ |
3032 | /* FALLTHRU */ |
3033 | case OPT_fauto_profile: |
3034 | enable_fdo_optimizations (opts, opts_set, value); |
3035 | SET_OPTION_IF_UNSET (opts, opts_set, flag_profile_correction, value); |
3036 | break; |
3037 | |
3038 | case OPT_fprofile_generate_: |
3039 | opts->x_profile_data_prefix = xstrdup (arg); |
3040 | value = true; |
3041 | /* No break here - do -fprofile-generate processing. */ |
3042 | /* FALLTHRU */ |
3043 | case OPT_fprofile_generate: |
3044 | SET_OPTION_IF_UNSET (opts, opts_set, profile_arc_flag, value); |
3045 | SET_OPTION_IF_UNSET (opts, opts_set, flag_profile_values, value); |
3046 | SET_OPTION_IF_UNSET (opts, opts_set, flag_inline_functions, value); |
3047 | SET_OPTION_IF_UNSET (opts, opts_set, flag_ipa_bit_cp, value); |
3048 | break; |
3049 | |
3050 | case OPT_fprofile_info_section: |
3051 | opts->x_profile_info_section = ".gcov_info" ; |
3052 | break; |
3053 | |
3054 | case OPT_fpatchable_function_entry_: |
3055 | { |
3056 | HOST_WIDE_INT patch_area_size, patch_area_start; |
3057 | parse_and_check_patch_area (arg, report_error: true, patch_area_size: &patch_area_size, |
3058 | patch_area_start: &patch_area_start); |
3059 | } |
3060 | break; |
3061 | |
3062 | case OPT_ftree_vectorize: |
3063 | /* Automatically sets -ftree-loop-vectorize and |
3064 | -ftree-slp-vectorize. Nothing more to do here. */ |
3065 | break; |
3066 | case OPT_fzero_call_used_regs_: |
3067 | opts->x_flag_zero_call_used_regs |
3068 | = parse_zero_call_used_regs_options (arg); |
3069 | break; |
3070 | |
3071 | case OPT_fshow_column: |
3072 | dc->m_show_column = value; |
3073 | break; |
3074 | |
3075 | case OPT_frandom_seed: |
3076 | /* The real switch is -fno-random-seed. */ |
3077 | if (value) |
3078 | return false; |
3079 | /* Deferred. */ |
3080 | break; |
3081 | |
3082 | case OPT_frandom_seed_: |
3083 | /* Deferred. */ |
3084 | break; |
3085 | |
3086 | case OPT_fsched_verbose_: |
3087 | #ifdef INSN_SCHEDULING |
3088 | /* Handled with Var in common.opt. */ |
3089 | break; |
3090 | #else |
3091 | return false; |
3092 | #endif |
3093 | |
3094 | case OPT_fsched_stalled_insns_: |
3095 | opts->x_flag_sched_stalled_insns = value; |
3096 | if (opts->x_flag_sched_stalled_insns == 0) |
3097 | opts->x_flag_sched_stalled_insns = -1; |
3098 | break; |
3099 | |
3100 | case OPT_fsched_stalled_insns_dep_: |
3101 | opts->x_flag_sched_stalled_insns_dep = value; |
3102 | break; |
3103 | |
3104 | case OPT_fstack_check_: |
3105 | if (!strcmp (s1: arg, s2: "no" )) |
3106 | opts->x_flag_stack_check = NO_STACK_CHECK; |
3107 | else if (!strcmp (s1: arg, s2: "generic" )) |
3108 | /* This is the old stack checking method. */ |
3109 | opts->x_flag_stack_check = STACK_CHECK_BUILTIN |
3110 | ? FULL_BUILTIN_STACK_CHECK |
3111 | : GENERIC_STACK_CHECK; |
3112 | else if (!strcmp (s1: arg, s2: "specific" )) |
3113 | /* This is the new stack checking method. */ |
3114 | opts->x_flag_stack_check = STACK_CHECK_BUILTIN |
3115 | ? FULL_BUILTIN_STACK_CHECK |
3116 | : STACK_CHECK_STATIC_BUILTIN |
3117 | ? STATIC_BUILTIN_STACK_CHECK |
3118 | : GENERIC_STACK_CHECK; |
3119 | else |
3120 | warning_at (loc, 0, "unknown stack check parameter %qs" , arg); |
3121 | break; |
3122 | |
3123 | case OPT_fstack_limit: |
3124 | /* The real switch is -fno-stack-limit. */ |
3125 | if (value) |
3126 | return false; |
3127 | /* Deferred. */ |
3128 | break; |
3129 | |
3130 | case OPT_fstack_limit_register_: |
3131 | case OPT_fstack_limit_symbol_: |
3132 | /* Deferred. */ |
3133 | break; |
3134 | |
3135 | case OPT_fstack_usage: |
3136 | opts->x_flag_stack_usage = value; |
3137 | opts->x_flag_stack_usage_info = value != 0; |
3138 | break; |
3139 | |
3140 | case OPT_g: |
3141 | set_debug_level (NO_DEBUG, DEFAULT_GDB_EXTENSIONS, arg, opts, opts_set, |
3142 | loc); |
3143 | break; |
3144 | |
3145 | case OPT_gcodeview: |
3146 | break; |
3147 | |
3148 | case OPT_gbtf: |
3149 | set_debug_level (BTF_DEBUG, extended: false, arg, opts, opts_set, loc); |
3150 | /* set the debug level to level 2, but if already at level 3, |
3151 | don't lower it. */ |
3152 | if (opts->x_debug_info_level < DINFO_LEVEL_NORMAL) |
3153 | opts->x_debug_info_level = DINFO_LEVEL_NORMAL; |
3154 | break; |
3155 | |
3156 | case OPT_gctf: |
3157 | set_debug_level (CTF_DEBUG, extended: false, arg, opts, opts_set, loc); |
3158 | /* CTF generation feeds off DWARF dies. For optimal CTF, switch debug |
3159 | info level to 2. If off or at level 1, set it to level 2, but if |
3160 | already at level 3, don't lower it. */ |
3161 | if (opts->x_debug_info_level < DINFO_LEVEL_NORMAL |
3162 | && opts->x_ctf_debug_info_level > CTFINFO_LEVEL_NONE) |
3163 | opts->x_debug_info_level = DINFO_LEVEL_NORMAL; |
3164 | break; |
3165 | |
3166 | case OPT_gdwarf: |
3167 | if (arg && strlen (s: arg) != 0) |
3168 | { |
3169 | error_at (loc, "%<-gdwarf%s%> is ambiguous; " |
3170 | "use %<-gdwarf-%s%> for DWARF version " |
3171 | "or %<-gdwarf%> %<-g%s%> for debug level" , arg, arg, arg); |
3172 | break; |
3173 | } |
3174 | else |
3175 | value = opts->x_dwarf_version; |
3176 | |
3177 | /* FALLTHRU */ |
3178 | case OPT_gdwarf_: |
3179 | if (value < 2 || value > 5) |
3180 | error_at (loc, "dwarf version %wu is not supported" , value); |
3181 | else |
3182 | opts->x_dwarf_version = value; |
3183 | set_debug_level (DWARF2_DEBUG, extended: false, arg: "" , opts, opts_set, loc); |
3184 | break; |
3185 | |
3186 | case OPT_ggdb: |
3187 | set_debug_level (NO_DEBUG, extended: 2, arg, opts, opts_set, loc); |
3188 | break; |
3189 | |
3190 | case OPT_gvms: |
3191 | set_debug_level (VMS_DEBUG, extended: false, arg, opts, opts_set, loc); |
3192 | break; |
3193 | |
3194 | case OPT_gz: |
3195 | case OPT_gz_: |
3196 | /* Handled completely via specs. */ |
3197 | break; |
3198 | |
3199 | case OPT_pedantic_errors: |
3200 | dc->m_pedantic_errors = 1; |
3201 | control_warning_option (opt_index: OPT_Wpedantic, kind: DK_ERROR, NULL, imply: value, |
3202 | loc, lang_mask, |
3203 | handlers, opts, opts_set, |
3204 | dc); |
3205 | break; |
3206 | |
3207 | case OPT_flto: |
3208 | opts->x_flag_lto = value ? "" : NULL; |
3209 | break; |
3210 | |
3211 | case OPT_flto_: |
3212 | if (strcmp (s1: arg, s2: "none" ) != 0 |
3213 | && strcmp (s1: arg, s2: "jobserver" ) != 0 |
3214 | && strcmp (s1: arg, s2: "auto" ) != 0 |
3215 | && atoi (nptr: arg) == 0) |
3216 | error_at (loc, |
3217 | "unrecognized argument to %<-flto=%> option: %qs" , arg); |
3218 | break; |
3219 | |
3220 | case OPT_w: |
3221 | dc->m_inhibit_warnings = true; |
3222 | break; |
3223 | |
3224 | case OPT_fmax_errors_: |
3225 | dc->set_max_errors (value); |
3226 | break; |
3227 | |
3228 | case OPT_fuse_ld_bfd: |
3229 | case OPT_fuse_ld_gold: |
3230 | case OPT_fuse_ld_lld: |
3231 | case OPT_fuse_ld_mold: |
3232 | case OPT_fuse_linker_plugin: |
3233 | /* No-op. Used by the driver and passed to us because it starts with f.*/ |
3234 | break; |
3235 | |
3236 | case OPT_fwrapv: |
3237 | if (value) |
3238 | opts->x_flag_trapv = 0; |
3239 | break; |
3240 | |
3241 | case OPT_ftrapv: |
3242 | if (value) |
3243 | opts->x_flag_wrapv = 0; |
3244 | break; |
3245 | |
3246 | case OPT_fstrict_overflow: |
3247 | opts->x_flag_wrapv = !value; |
3248 | opts->x_flag_wrapv_pointer = !value; |
3249 | if (!value) |
3250 | opts->x_flag_trapv = 0; |
3251 | break; |
3252 | |
3253 | case OPT_fipa_icf: |
3254 | opts->x_flag_ipa_icf_functions = value; |
3255 | opts->x_flag_ipa_icf_variables = value; |
3256 | break; |
3257 | |
3258 | case OPT_falign_loops_: |
3259 | check_alignment_argument (loc, flag: arg, name: "loops" , |
3260 | opt_flag: &opts->x_flag_align_loops, |
3261 | opt_str: &opts->x_str_align_loops); |
3262 | break; |
3263 | |
3264 | case OPT_falign_jumps_: |
3265 | check_alignment_argument (loc, flag: arg, name: "jumps" , |
3266 | opt_flag: &opts->x_flag_align_jumps, |
3267 | opt_str: &opts->x_str_align_jumps); |
3268 | break; |
3269 | |
3270 | case OPT_falign_labels_: |
3271 | check_alignment_argument (loc, flag: arg, name: "labels" , |
3272 | opt_flag: &opts->x_flag_align_labels, |
3273 | opt_str: &opts->x_str_align_labels); |
3274 | break; |
3275 | |
3276 | case OPT_falign_functions_: |
3277 | check_alignment_argument (loc, flag: arg, name: "functions" , |
3278 | opt_flag: &opts->x_flag_align_functions, |
3279 | opt_str: &opts->x_str_align_functions); |
3280 | break; |
3281 | |
3282 | case OPT_ftabstop_: |
3283 | /* It is documented that we silently ignore silly values. */ |
3284 | if (value >= 1 && value <= 100) |
3285 | dc->m_tabstop = value; |
3286 | break; |
3287 | |
3288 | case OPT_freport_bug: |
3289 | dc->set_report_bug (value); |
3290 | break; |
3291 | |
3292 | case OPT_fmultiflags: |
3293 | gcc_checking_assert (lang_mask == CL_DRIVER); |
3294 | break; |
3295 | |
3296 | default: |
3297 | /* If the flag was handled in a standard way, assume the lack of |
3298 | processing here is intentional. */ |
3299 | gcc_assert (option_flag_var (scode, opts)); |
3300 | break; |
3301 | } |
3302 | |
3303 | common_handle_option_auto (opts, opts_set, decoded, lang_mask, kind, |
3304 | loc, handlers, dc); |
3305 | return true; |
3306 | } |
3307 | |
3308 | /* Used to set the level of strict aliasing warnings in OPTS, |
3309 | when no level is specified (i.e., when -Wstrict-aliasing, and not |
3310 | -Wstrict-aliasing=level was given). |
3311 | ONOFF is assumed to take value 1 when -Wstrict-aliasing is specified, |
3312 | and 0 otherwise. After calling this function, wstrict_aliasing will be |
3313 | set to the default value of -Wstrict_aliasing=level, currently 3. */ |
3314 | static void |
3315 | set_Wstrict_aliasing (struct gcc_options *opts, int onoff) |
3316 | { |
3317 | gcc_assert (onoff == 0 || onoff == 1); |
3318 | if (onoff != 0) |
3319 | opts->x_warn_strict_aliasing = 3; |
3320 | else |
3321 | opts->x_warn_strict_aliasing = 0; |
3322 | } |
3323 | |
3324 | /* The following routines are useful in setting all the flags that |
3325 | -ffast-math and -fno-fast-math imply. */ |
3326 | static void |
3327 | set_fast_math_flags (struct gcc_options *opts, int set) |
3328 | { |
3329 | if (!opts->frontend_set_flag_unsafe_math_optimizations) |
3330 | { |
3331 | opts->x_flag_unsafe_math_optimizations = set; |
3332 | set_unsafe_math_optimizations_flags (opts, set); |
3333 | } |
3334 | if (!opts->frontend_set_flag_finite_math_only) |
3335 | opts->x_flag_finite_math_only = set; |
3336 | if (!opts->frontend_set_flag_errno_math) |
3337 | opts->x_flag_errno_math = !set; |
3338 | if (set) |
3339 | { |
3340 | if (opts->frontend_set_flag_excess_precision == EXCESS_PRECISION_DEFAULT) |
3341 | opts->x_flag_excess_precision |
3342 | = set ? EXCESS_PRECISION_FAST : EXCESS_PRECISION_DEFAULT; |
3343 | if (!opts->frontend_set_flag_signaling_nans) |
3344 | opts->x_flag_signaling_nans = 0; |
3345 | if (!opts->frontend_set_flag_rounding_math) |
3346 | opts->x_flag_rounding_math = 0; |
3347 | if (!opts->frontend_set_flag_cx_limited_range) |
3348 | opts->x_flag_cx_limited_range = 1; |
3349 | } |
3350 | } |
3351 | |
3352 | /* When -funsafe-math-optimizations is set the following |
3353 | flags are set as well. */ |
3354 | static void |
3355 | set_unsafe_math_optimizations_flags (struct gcc_options *opts, int set) |
3356 | { |
3357 | if (!opts->frontend_set_flag_trapping_math) |
3358 | opts->x_flag_trapping_math = !set; |
3359 | if (!opts->frontend_set_flag_signed_zeros) |
3360 | opts->x_flag_signed_zeros = !set; |
3361 | if (!opts->frontend_set_flag_associative_math) |
3362 | opts->x_flag_associative_math = set; |
3363 | if (!opts->frontend_set_flag_reciprocal_math) |
3364 | opts->x_flag_reciprocal_math = set; |
3365 | } |
3366 | |
3367 | /* Return true iff flags in OPTS are set as if -ffast-math. */ |
3368 | bool |
3369 | fast_math_flags_set_p (const struct gcc_options *opts) |
3370 | { |
3371 | return (!opts->x_flag_trapping_math |
3372 | && opts->x_flag_unsafe_math_optimizations |
3373 | && opts->x_flag_finite_math_only |
3374 | && !opts->x_flag_signed_zeros |
3375 | && !opts->x_flag_errno_math |
3376 | && opts->x_flag_excess_precision == EXCESS_PRECISION_FAST); |
3377 | } |
3378 | |
3379 | /* Return true iff flags are set as if -ffast-math but using the flags stored |
3380 | in the struct cl_optimization structure. */ |
3381 | bool |
3382 | fast_math_flags_struct_set_p (struct cl_optimization *opt) |
3383 | { |
3384 | return (!opt->x_flag_trapping_math |
3385 | && opt->x_flag_unsafe_math_optimizations |
3386 | && opt->x_flag_finite_math_only |
3387 | && !opt->x_flag_signed_zeros |
3388 | && !opt->x_flag_errno_math); |
3389 | } |
3390 | |
3391 | /* Handle a debug output -g switch for options OPTS |
3392 | (OPTS_SET->x_write_symbols storing whether a debug format was passed |
3393 | explicitly), location LOC. EXTENDED is true or false to support |
3394 | extended output (2 is special and means "-ggdb" was given). */ |
3395 | static void |
3396 | set_debug_level (uint32_t dinfo, int extended, const char *arg, |
3397 | struct gcc_options *opts, struct gcc_options *opts_set, |
3398 | location_t loc) |
3399 | { |
3400 | if (dinfo == NO_DEBUG) |
3401 | { |
3402 | if (opts->x_write_symbols == NO_DEBUG) |
3403 | { |
3404 | opts->x_write_symbols = PREFERRED_DEBUGGING_TYPE; |
3405 | |
3406 | if (extended == 2) |
3407 | { |
3408 | #if defined DWARF2_DEBUGGING_INFO || defined DWARF2_LINENO_DEBUGGING_INFO |
3409 | if (opts->x_write_symbols & CTF_DEBUG) |
3410 | opts->x_write_symbols |= DWARF2_DEBUG; |
3411 | else |
3412 | opts->x_write_symbols = DWARF2_DEBUG; |
3413 | #endif |
3414 | } |
3415 | |
3416 | if (opts->x_write_symbols == NO_DEBUG) |
3417 | warning_at (loc, 0, "target system does not support debug output" ); |
3418 | } |
3419 | else if ((opts->x_write_symbols & CTF_DEBUG) |
3420 | || (opts->x_write_symbols & BTF_DEBUG)) |
3421 | { |
3422 | opts->x_write_symbols |= DWARF2_DEBUG; |
3423 | opts_set->x_write_symbols |= DWARF2_DEBUG; |
3424 | } |
3425 | } |
3426 | else |
3427 | { |
3428 | /* Make and retain the choice if both CTF and DWARF debug info are to |
3429 | be generated. */ |
3430 | if (((dinfo == DWARF2_DEBUG) || (dinfo == CTF_DEBUG)) |
3431 | && ((opts->x_write_symbols == (DWARF2_DEBUG|CTF_DEBUG)) |
3432 | || (opts->x_write_symbols == DWARF2_DEBUG) |
3433 | || (opts->x_write_symbols == CTF_DEBUG))) |
3434 | { |
3435 | opts->x_write_symbols |= dinfo; |
3436 | opts_set->x_write_symbols |= dinfo; |
3437 | } |
3438 | /* However, CTF and BTF are not allowed together at this time. */ |
3439 | else if (((dinfo == DWARF2_DEBUG) || (dinfo == BTF_DEBUG)) |
3440 | && ((opts->x_write_symbols == (DWARF2_DEBUG|BTF_DEBUG)) |
3441 | || (opts->x_write_symbols == DWARF2_DEBUG) |
3442 | || (opts->x_write_symbols == BTF_DEBUG))) |
3443 | { |
3444 | opts->x_write_symbols |= dinfo; |
3445 | opts_set->x_write_symbols |= dinfo; |
3446 | } |
3447 | else |
3448 | { |
3449 | /* Does it conflict with an already selected debug format? */ |
3450 | if (opts_set->x_write_symbols != NO_DEBUG |
3451 | && opts->x_write_symbols != NO_DEBUG |
3452 | && dinfo != opts->x_write_symbols) |
3453 | { |
3454 | gcc_assert (debug_set_count (dinfo) <= 1); |
3455 | error_at (loc, "debug format %qs conflicts with prior selection" , |
3456 | debug_type_names[debug_set_to_format (debug_info_set: dinfo)]); |
3457 | } |
3458 | opts->x_write_symbols = dinfo; |
3459 | opts_set->x_write_symbols = dinfo; |
3460 | } |
3461 | } |
3462 | |
3463 | if (dinfo != BTF_DEBUG) |
3464 | { |
3465 | /* A debug flag without a level defaults to level 2. |
3466 | If off or at level 1, set it to level 2, but if already |
3467 | at level 3, don't lower it. */ |
3468 | if (*arg == '\0') |
3469 | { |
3470 | if (dinfo == CTF_DEBUG) |
3471 | opts->x_ctf_debug_info_level = CTFINFO_LEVEL_NORMAL; |
3472 | else if (opts->x_debug_info_level < DINFO_LEVEL_NORMAL) |
3473 | opts->x_debug_info_level = DINFO_LEVEL_NORMAL; |
3474 | } |
3475 | else |
3476 | { |
3477 | int argval = integral_argument (arg); |
3478 | if (argval == -1) |
3479 | error_at (loc, "unrecognized debug output level %qs" , arg); |
3480 | else if (argval > 3) |
3481 | error_at (loc, "debug output level %qs is too high" , arg); |
3482 | else |
3483 | { |
3484 | if (dinfo == CTF_DEBUG) |
3485 | opts->x_ctf_debug_info_level |
3486 | = (enum ctf_debug_info_levels) argval; |
3487 | else |
3488 | opts->x_debug_info_level = (enum debug_info_levels) argval; |
3489 | } |
3490 | } |
3491 | } |
3492 | else if (*arg != '\0') |
3493 | error_at (loc, "unrecognized btf debug output level %qs" , arg); |
3494 | } |
3495 | |
3496 | /* Arrange to dump core on error for diagnostic context DC. (The |
3497 | regular error message is still printed first, except in the case of |
3498 | abort ().) */ |
3499 | |
3500 | static void |
3501 | setup_core_dumping (diagnostic_context *dc) |
3502 | { |
3503 | #ifdef SIGABRT |
3504 | signal (SIGABRT, SIG_DFL); |
3505 | #endif |
3506 | #if defined(HAVE_SETRLIMIT) |
3507 | { |
3508 | struct rlimit rlim; |
3509 | if (getrlimit (RLIMIT_CORE, rlimits: &rlim) != 0) |
3510 | fatal_error (input_location, "getting core file size maximum limit: %m" ); |
3511 | rlim.rlim_cur = rlim.rlim_max; |
3512 | if (setrlimit (RLIMIT_CORE, rlimits: &rlim) != 0) |
3513 | fatal_error (input_location, |
3514 | "setting core file size limit to maximum: %m" ); |
3515 | } |
3516 | #endif |
3517 | diagnostic_abort_on_error (context: dc); |
3518 | } |
3519 | |
3520 | /* Parse a -d<ARG> command line switch for OPTS, location LOC, |
3521 | diagnostic context DC. */ |
3522 | |
3523 | static void |
3524 | decode_d_option (const char *arg, struct gcc_options *opts, |
3525 | location_t loc, diagnostic_context *dc) |
3526 | { |
3527 | int c; |
3528 | |
3529 | while (*arg) |
3530 | switch (c = *arg++) |
3531 | { |
3532 | case 'A': |
3533 | opts->x_flag_debug_asm = 1; |
3534 | break; |
3535 | case 'p': |
3536 | opts->x_flag_print_asm_name = 1; |
3537 | break; |
3538 | case 'P': |
3539 | opts->x_flag_dump_rtl_in_asm = 1; |
3540 | opts->x_flag_print_asm_name = 1; |
3541 | break; |
3542 | case 'x': |
3543 | opts->x_rtl_dump_and_exit = 1; |
3544 | break; |
3545 | case 'D': /* These are handled by the preprocessor. */ |
3546 | case 'I': |
3547 | case 'M': |
3548 | case 'N': |
3549 | case 'U': |
3550 | break; |
3551 | case 'H': |
3552 | setup_core_dumping (dc); |
3553 | break; |
3554 | case 'a': |
3555 | opts->x_flag_dump_all_passed = true; |
3556 | break; |
3557 | |
3558 | default: |
3559 | warning_at (loc, 0, "unrecognized gcc debugging option: %c" , c); |
3560 | break; |
3561 | } |
3562 | } |
3563 | |
3564 | /* Enable (or disable if VALUE is 0) a warning option ARG (language |
3565 | mask LANG_MASK, option handlers HANDLERS) as an error for option |
3566 | structures OPTS and OPTS_SET, diagnostic context DC (possibly |
3567 | NULL), location LOC. This is used by -Werror=. */ |
3568 | |
3569 | static void |
3570 | enable_warning_as_error (const char *arg, int value, unsigned int lang_mask, |
3571 | const struct cl_option_handlers *handlers, |
3572 | struct gcc_options *opts, |
3573 | struct gcc_options *opts_set, |
3574 | location_t loc, diagnostic_context *dc) |
3575 | { |
3576 | char *new_option; |
3577 | int option_index; |
3578 | |
3579 | new_option = XNEWVEC (char, strlen (arg) + 2); |
3580 | new_option[0] = 'W'; |
3581 | strcpy (dest: new_option + 1, src: arg); |
3582 | option_index = find_opt (input: new_option, lang_mask); |
3583 | if (option_index == OPT_SPECIAL_unknown) |
3584 | { |
3585 | option_proposer op; |
3586 | const char *hint = op.suggest_option (bad_opt: new_option); |
3587 | if (hint) |
3588 | error_at (loc, "%<-W%serror=%s%>: no option %<-%s%>;" |
3589 | " did you mean %<-%s%>?" , value ? "" : "no-" , |
3590 | arg, new_option, hint); |
3591 | else |
3592 | error_at (loc, "%<-W%serror=%s%>: no option %<-%s%>" , |
3593 | value ? "" : "no-" , arg, new_option); |
3594 | } |
3595 | else if (!(cl_options[option_index].flags & CL_WARNING)) |
3596 | error_at (loc, "%<-Werror=%s%>: %<-%s%> is not an option that " |
3597 | "controls warnings" , arg, new_option); |
3598 | else |
3599 | { |
3600 | const diagnostic_t kind = value ? DK_ERROR : DK_WARNING; |
3601 | const char *arg = NULL; |
3602 | |
3603 | if (cl_options[option_index].flags & CL_JOINED) |
3604 | arg = new_option + cl_options[option_index].opt_len; |
3605 | control_warning_option (opt_index: option_index, kind: (int) kind, arg, imply: value, |
3606 | loc, lang_mask, |
3607 | handlers, opts, opts_set, dc); |
3608 | } |
3609 | free (ptr: new_option); |
3610 | } |
3611 | |
3612 | /* Return malloced memory for the name of the option OPTION_INDEX |
3613 | which enabled a diagnostic (context CONTEXT), originally of type |
3614 | ORIG_DIAG_KIND but possibly converted to DIAG_KIND by options such |
3615 | as -Werror. */ |
3616 | |
3617 | char * |
3618 | option_name (diagnostic_context *context, int option_index, |
3619 | diagnostic_t orig_diag_kind, diagnostic_t diag_kind) |
3620 | { |
3621 | if (option_index) |
3622 | { |
3623 | /* A warning classified as an error. */ |
3624 | if ((orig_diag_kind == DK_WARNING || orig_diag_kind == DK_PEDWARN) |
3625 | && diag_kind == DK_ERROR) |
3626 | return concat (cl_options[OPT_Werror_].opt_text, |
3627 | /* Skip over "-W". */ |
3628 | cl_options[option_index].opt_text + 2, |
3629 | NULL); |
3630 | /* A warning with option. */ |
3631 | else |
3632 | return xstrdup (cl_options[option_index].opt_text); |
3633 | } |
3634 | /* A warning without option classified as an error. */ |
3635 | else if ((orig_diag_kind == DK_WARNING || orig_diag_kind == DK_PEDWARN |
3636 | || diag_kind == DK_WARNING) |
3637 | && context->warning_as_error_requested_p ()) |
3638 | return xstrdup (cl_options[OPT_Werror].opt_text); |
3639 | else |
3640 | return NULL; |
3641 | } |
3642 | |
3643 | /* Get the page within the documentation for this option. */ |
3644 | |
3645 | static const char * |
3646 | get_option_html_page (int option_index) |
3647 | { |
3648 | const cl_option *cl_opt = &cl_options[option_index]; |
3649 | |
3650 | /* Analyzer options are on their own page. */ |
3651 | if (strstr (haystack: cl_opt->opt_text, needle: "analyzer-" )) |
3652 | return "gcc/Static-Analyzer-Options.html" ; |
3653 | |
3654 | /* Handle -flto= option. */ |
3655 | if (strstr (haystack: cl_opt->opt_text, needle: "flto" )) |
3656 | return "gcc/Optimize-Options.html" ; |
3657 | |
3658 | #ifdef CL_Fortran |
3659 | if ((cl_opt->flags & CL_Fortran) != 0 |
3660 | /* If it is option common to both C/C++ and Fortran, it is documented |
3661 | in gcc/ rather than gfortran/ docs. */ |
3662 | && (cl_opt->flags & CL_C) == 0 |
3663 | #ifdef CL_CXX |
3664 | && (cl_opt->flags & CL_CXX) == 0 |
3665 | #endif |
3666 | ) |
3667 | return "gfortran/Error-and-Warning-Options.html" ; |
3668 | #endif |
3669 | |
3670 | return "gcc/Warning-Options.html" ; |
3671 | } |
3672 | |
3673 | /* Return malloced memory for a URL describing the option OPTION_INDEX |
3674 | which enabled a diagnostic (context CONTEXT). */ |
3675 | |
3676 | char * |
3677 | get_option_url (diagnostic_context *, int option_index) |
3678 | { |
3679 | if (option_index) |
3680 | return concat (/* DOCUMENTATION_ROOT_URL should be supplied via |
3681 | #include "config.h" (see --with-documentation-root-url), |
3682 | and should have a trailing slash. */ |
3683 | DOCUMENTATION_ROOT_URL, |
3684 | |
3685 | /* get_option_html_page will return something like |
3686 | "gcc/Warning-Options.html". */ |
3687 | get_option_html_page (option_index), |
3688 | |
3689 | /* Expect an anchor of the form "index-Wfoo" e.g. |
3690 | <a name="index-Wformat"></a>, and thus an id within |
3691 | the URL of "#index-Wformat". */ |
3692 | "#index" , cl_options[option_index].opt_text, |
3693 | NULL); |
3694 | else |
3695 | return NULL; |
3696 | } |
3697 | |
3698 | /* Return a heap allocated producer with command line options. */ |
3699 | |
3700 | char * |
3701 | gen_command_line_string (cl_decoded_option *options, |
3702 | unsigned int options_count) |
3703 | { |
3704 | auto_vec<const char *> switches; |
3705 | char *options_string, *tail; |
3706 | const char *p; |
3707 | size_t len = 0; |
3708 | |
3709 | for (unsigned i = 0; i < options_count; i++) |
3710 | switch (options[i].opt_index) |
3711 | { |
3712 | case OPT_o: |
3713 | case OPT_d: |
3714 | case OPT_dumpbase: |
3715 | case OPT_dumpbase_ext: |
3716 | case OPT_dumpdir: |
3717 | case OPT_quiet: |
3718 | case OPT_version: |
3719 | case OPT_v: |
3720 | case OPT_w: |
3721 | case OPT_L: |
3722 | case OPT_D: |
3723 | case OPT_I: |
3724 | case OPT_U: |
3725 | case OPT_SPECIAL_unknown: |
3726 | case OPT_SPECIAL_ignore: |
3727 | case OPT_SPECIAL_warn_removed: |
3728 | case OPT_SPECIAL_program_name: |
3729 | case OPT_SPECIAL_input_file: |
3730 | case OPT_grecord_gcc_switches: |
3731 | case OPT_frecord_gcc_switches: |
3732 | case OPT__output_pch: |
3733 | case OPT_fdiagnostics_show_location_: |
3734 | case OPT_fdiagnostics_show_option: |
3735 | case OPT_fdiagnostics_show_caret: |
3736 | case OPT_fdiagnostics_show_labels: |
3737 | case OPT_fdiagnostics_show_line_numbers: |
3738 | case OPT_fdiagnostics_color_: |
3739 | case OPT_fdiagnostics_format_: |
3740 | case OPT_fverbose_asm: |
3741 | case OPT____: |
3742 | case OPT__sysroot_: |
3743 | case OPT_nostdinc: |
3744 | case OPT_nostdinc__: |
3745 | case OPT_fpreprocessed: |
3746 | case OPT_fltrans_output_list_: |
3747 | case OPT_fresolution_: |
3748 | case OPT_fdebug_prefix_map_: |
3749 | case OPT_fmacro_prefix_map_: |
3750 | case OPT_ffile_prefix_map_: |
3751 | case OPT_fprofile_prefix_map_: |
3752 | case OPT_fcanon_prefix_map: |
3753 | case OPT_fcompare_debug: |
3754 | case OPT_fchecking: |
3755 | case OPT_fchecking_: |
3756 | /* Ignore these. */ |
3757 | continue; |
3758 | case OPT_flto_: |
3759 | { |
3760 | const char *lto_canonical = "-flto" ; |
3761 | switches.safe_push (obj: lto_canonical); |
3762 | len += strlen (s: lto_canonical) + 1; |
3763 | break; |
3764 | } |
3765 | default: |
3766 | if (cl_options[options[i].opt_index].flags |
3767 | & CL_NO_DWARF_RECORD) |
3768 | continue; |
3769 | gcc_checking_assert (options[i].canonical_option[0][0] == '-'); |
3770 | switch (options[i].canonical_option[0][1]) |
3771 | { |
3772 | case 'M': |
3773 | case 'i': |
3774 | case 'W': |
3775 | continue; |
3776 | case 'f': |
3777 | if (strncmp (s1: options[i].canonical_option[0] + 2, |
3778 | s2: "dump" , n: 4) == 0) |
3779 | continue; |
3780 | break; |
3781 | default: |
3782 | break; |
3783 | } |
3784 | switches.safe_push (obj: options[i].orig_option_with_args_text); |
3785 | len += strlen (s: options[i].orig_option_with_args_text) + 1; |
3786 | break; |
3787 | } |
3788 | |
3789 | options_string = XNEWVEC (char, len + 1); |
3790 | tail = options_string; |
3791 | |
3792 | unsigned i; |
3793 | FOR_EACH_VEC_ELT (switches, i, p) |
3794 | { |
3795 | len = strlen (s: p); |
3796 | memcpy (dest: tail, src: p, n: len); |
3797 | tail += len; |
3798 | if (i != switches.length () - 1) |
3799 | { |
3800 | *tail = ' '; |
3801 | ++tail; |
3802 | } |
3803 | } |
3804 | |
3805 | *tail = '\0'; |
3806 | return options_string; |
3807 | } |
3808 | |
3809 | /* Return a heap allocated producer string including command line options. */ |
3810 | |
3811 | char * |
3812 | gen_producer_string (const char *language_string, cl_decoded_option *options, |
3813 | unsigned int options_count) |
3814 | { |
3815 | char *cmdline = gen_command_line_string (options, options_count); |
3816 | char *combined = concat (language_string, " " , version_string, " " , |
3817 | cmdline, NULL); |
3818 | free (ptr: cmdline); |
3819 | return combined; |
3820 | } |
3821 | |
3822 | #if CHECKING_P |
3823 | |
3824 | namespace selftest { |
3825 | |
3826 | /* Verify that get_option_html_page works as expected. */ |
3827 | |
3828 | static void |
3829 | test_get_option_html_page () |
3830 | { |
3831 | ASSERT_STREQ (get_option_html_page (OPT_Wcpp), "gcc/Warning-Options.html" ); |
3832 | ASSERT_STREQ (get_option_html_page (OPT_Wanalyzer_double_free), |
3833 | "gcc/Static-Analyzer-Options.html" ); |
3834 | #ifdef CL_Fortran |
3835 | ASSERT_STREQ (get_option_html_page (OPT_Wline_truncation), |
3836 | "gfortran/Error-and-Warning-Options.html" ); |
3837 | #endif |
3838 | } |
3839 | |
3840 | /* Verify EnumSet and EnumBitSet requirements. */ |
3841 | |
3842 | static void |
3843 | test_enum_sets () |
3844 | { |
3845 | for (unsigned i = 0; i < cl_options_count; ++i) |
3846 | if (cl_options[i].var_type == CLVC_ENUM |
3847 | && cl_options[i].var_value != CLEV_NORMAL) |
3848 | { |
3849 | const struct cl_enum *e = &cl_enums[cl_options[i].var_enum]; |
3850 | unsigned HOST_WIDE_INT used_sets = 0; |
3851 | unsigned HOST_WIDE_INT mask = 0; |
3852 | unsigned highest_set = 0; |
3853 | for (unsigned j = 0; e->values[j].arg; ++j) |
3854 | { |
3855 | unsigned set = e->values[j].flags >> CL_ENUM_SET_SHIFT; |
3856 | if (cl_options[i].var_value == CLEV_BITSET) |
3857 | { |
3858 | /* For EnumBitSet Set shouldn't be used and Value should |
3859 | be a power of two. */ |
3860 | ASSERT_TRUE (set == 0); |
3861 | ASSERT_TRUE (pow2p_hwi (e->values[j].value)); |
3862 | continue; |
3863 | } |
3864 | /* Test that enumerators referenced in EnumSet have all |
3865 | Set(n) on them within the valid range. */ |
3866 | ASSERT_TRUE (set >= 1 && set <= HOST_BITS_PER_WIDE_INT); |
3867 | highest_set = MAX (set, highest_set); |
3868 | used_sets |= HOST_WIDE_INT_1U << (set - 1); |
3869 | } |
3870 | if (cl_options[i].var_value == CLEV_BITSET) |
3871 | continue; |
3872 | /* If there is just one set, no point to using EnumSet. */ |
3873 | ASSERT_TRUE (highest_set >= 2); |
3874 | /* Test that there are no gaps in between the sets. */ |
3875 | if (highest_set == HOST_BITS_PER_WIDE_INT) |
3876 | ASSERT_TRUE (used_sets == HOST_WIDE_INT_M1U); |
3877 | else |
3878 | ASSERT_TRUE (used_sets == (HOST_WIDE_INT_1U << highest_set) - 1); |
3879 | for (unsigned int j = 1; j <= highest_set; ++j) |
3880 | { |
3881 | unsigned HOST_WIDE_INT this_mask = 0; |
3882 | for (unsigned k = 0; e->values[k].arg; ++k) |
3883 | { |
3884 | unsigned set = e->values[j].flags >> CL_ENUM_SET_SHIFT; |
3885 | if (set == j) |
3886 | this_mask |= e->values[j].value; |
3887 | } |
3888 | ASSERT_TRUE ((mask & this_mask) == 0); |
3889 | mask |= this_mask; |
3890 | } |
3891 | } |
3892 | } |
3893 | |
3894 | /* Run all of the selftests within this file. */ |
3895 | |
3896 | void |
3897 | opts_cc_tests () |
3898 | { |
3899 | test_get_option_html_page (); |
3900 | test_enum_sets (); |
3901 | } |
3902 | |
3903 | } // namespace selftest |
3904 | |
3905 | #endif /* #if CHECKING_P */ |
3906 | |