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