1 | /* Command line option handling. |
2 | Copyright (C) 2006-2024 Free Software Foundation, Inc. |
3 | |
4 | This file is part of GCC. |
5 | |
6 | GCC is free software; you can redistribute it and/or modify it under |
7 | the terms of the GNU General Public License as published by the Free |
8 | Software Foundation; either version 3, or (at your option) any later |
9 | version. |
10 | |
11 | GCC is distributed in the hope that it will be useful, but WITHOUT ANY |
12 | WARRANTY; without even the implied warranty of MERCHANTABILITY or |
13 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
14 | for more details. |
15 | |
16 | You should have received a copy of the GNU General Public License |
17 | along with GCC; see the file COPYING3. If not see |
18 | <http://www.gnu.org/licenses/>. */ |
19 | |
20 | #define INCLUDE_STRING |
21 | #include "config.h" |
22 | #include "system.h" |
23 | #include "intl.h" |
24 | #include "coretypes.h" |
25 | #include "opts.h" |
26 | #include "options.h" |
27 | #include "diagnostic.h" |
28 | #include "spellcheck.h" |
29 | #include "opts-jobserver.h" |
30 | |
31 | static void prune_options (struct cl_decoded_option **, unsigned int *); |
32 | |
33 | /* An option that is undocumented, that takes a joined argument, and |
34 | that doesn't fit any of the classes of uses (language/common, |
35 | driver, target) is assumed to be a prefix used to catch |
36 | e.g. negated options, and stop them from being further shortened to |
37 | a prefix that could use the negated option as an argument. For |
38 | example, we want -gno-statement-frontiers to be taken as a negation |
39 | of -gstatement-frontiers, but without catching the gno- prefix and |
40 | signaling it's to be used for option remapping, it would end up |
41 | backtracked to g with no-statemnet-frontiers as the debug level. */ |
42 | |
43 | static bool |
44 | remapping_prefix_p (const struct cl_option *opt) |
45 | { |
46 | return opt->flags & CL_UNDOCUMENTED |
47 | && opt->flags & CL_JOINED |
48 | && !(opt->flags & (CL_DRIVER | CL_TARGET | CL_COMMON | CL_LANG_ALL)); |
49 | } |
50 | |
51 | /* Perform a binary search to find which option the command-line INPUT |
52 | matches. Returns its index in the option array, and |
53 | OPT_SPECIAL_unknown on failure. |
54 | |
55 | This routine is quite subtle. A normal binary search is not good |
56 | enough because some options can be suffixed with an argument, and |
57 | multiple sub-matches can occur, e.g. input of "-pedantic" matching |
58 | the initial substring of "-pedantic-errors". |
59 | |
60 | A more complicated example is -gstabs. It should match "-g" with |
61 | an argument of "stabs". Suppose, however, that the number and list |
62 | of switches are such that the binary search tests "-gen-decls" |
63 | before having tested "-g". This doesn't match, and as "-gen-decls" |
64 | is less than "-gstabs", it will become the lower bound of the |
65 | binary search range, and "-g" will never be seen. To resolve this |
66 | issue, 'optc-gen.awk' makes "-gen-decls" point, via the back_chain member, |
67 | to "-g" so that failed searches that end between "-gen-decls" and |
68 | the lexicographically subsequent switch know to go back and see if |
69 | "-g" causes a match (which it does in this example). |
70 | |
71 | This search is done in such a way that the longest match for the |
72 | front end in question wins. If there is no match for the current |
73 | front end, the longest match for a different front end is returned |
74 | (or N_OPTS if none) and the caller emits an error message. */ |
75 | size_t |
76 | find_opt (const char *input, unsigned int lang_mask) |
77 | { |
78 | size_t mn, mn_orig, mx, md, opt_len; |
79 | size_t match_wrong_lang; |
80 | int comp; |
81 | |
82 | mn = 0; |
83 | mx = cl_options_count; |
84 | |
85 | /* Find mn such this lexicographical inequality holds: |
86 | cl_options[mn] <= input < cl_options[mn + 1]. */ |
87 | while (mx - mn > 1) |
88 | { |
89 | md = (mn + mx) / 2; |
90 | opt_len = cl_options[md].opt_len; |
91 | comp = strncmp (s1: input, s2: cl_options[md].opt_text + 1, n: opt_len); |
92 | |
93 | if (comp < 0) |
94 | mx = md; |
95 | else |
96 | mn = md; |
97 | } |
98 | |
99 | mn_orig = mn; |
100 | |
101 | /* This is the switch that is the best match but for a different |
102 | front end, or OPT_SPECIAL_unknown if there is no match at all. */ |
103 | match_wrong_lang = OPT_SPECIAL_unknown; |
104 | |
105 | /* Backtrace the chain of possible matches, returning the longest |
106 | one, if any, that fits best. With current GCC switches, this |
107 | loop executes at most twice. */ |
108 | do |
109 | { |
110 | const struct cl_option *opt = &cl_options[mn]; |
111 | |
112 | /* Is the input either an exact match or a prefix that takes a |
113 | joined argument? */ |
114 | if (!strncmp (s1: input, s2: opt->opt_text + 1, n: opt->opt_len) |
115 | && (input[opt->opt_len] == '\0' || (opt->flags & CL_JOINED))) |
116 | { |
117 | /* If language is OK, return it. */ |
118 | if (opt->flags & lang_mask) |
119 | return mn; |
120 | |
121 | if (remapping_prefix_p (opt)) |
122 | return OPT_SPECIAL_unknown; |
123 | |
124 | /* If we haven't remembered a prior match, remember this |
125 | one. Any prior match is necessarily better. */ |
126 | if (match_wrong_lang == OPT_SPECIAL_unknown) |
127 | match_wrong_lang = mn; |
128 | } |
129 | |
130 | /* Try the next possibility. This is cl_options_count if there |
131 | are no more. */ |
132 | mn = opt->back_chain; |
133 | } |
134 | while (mn != cl_options_count); |
135 | |
136 | if (match_wrong_lang == OPT_SPECIAL_unknown && input[0] == '-') |
137 | { |
138 | /* Long options, starting "--", may be abbreviated if the |
139 | abbreviation is unambiguous. This only applies to options |
140 | not taking a joined argument, and abbreviations of "--option" |
141 | are permitted even if there is a variant "--option=". */ |
142 | size_t mnc = mn_orig + 1; |
143 | size_t cmp_len = strlen (s: input); |
144 | while (mnc < cl_options_count |
145 | && strncmp (s1: input, s2: cl_options[mnc].opt_text + 1, n: cmp_len) == 0) |
146 | { |
147 | /* Option matching this abbreviation. OK if it is the first |
148 | match and that does not take a joined argument, or the |
149 | second match, taking a joined argument and with only '=' |
150 | added to the first match; otherwise considered |
151 | ambiguous. */ |
152 | if (mnc == mn_orig + 1 |
153 | && !(cl_options[mnc].flags & CL_JOINED)) |
154 | match_wrong_lang = mnc; |
155 | else if (mnc == mn_orig + 2 |
156 | && match_wrong_lang == mn_orig + 1 |
157 | && (cl_options[mnc].flags & CL_JOINED) |
158 | && (cl_options[mnc].opt_len |
159 | == cl_options[mn_orig + 1].opt_len + 1) |
160 | && strncmp (s1: cl_options[mnc].opt_text + 1, |
161 | s2: cl_options[mn_orig + 1].opt_text + 1, |
162 | n: cl_options[mn_orig + 1].opt_len) == 0) |
163 | ; /* OK, as long as there are no more matches. */ |
164 | else |
165 | return OPT_SPECIAL_unknown; |
166 | mnc++; |
167 | } |
168 | } |
169 | |
170 | /* Return the best wrong match, or OPT_SPECIAL_unknown if none. */ |
171 | return match_wrong_lang; |
172 | } |
173 | |
174 | /* If ARG is a non-negative decimal or hexadecimal integer representable |
175 | in HOST_WIDE_INT return its value, otherwise return -1. If ERR is not |
176 | null set *ERR to zero on success or to EINVAL or to the value of errno |
177 | otherwise. */ |
178 | |
179 | HOST_WIDE_INT |
180 | integral_argument (const char *arg, int *err, bool byte_size_suffix) |
181 | { |
182 | if (!err) |
183 | err = &errno; |
184 | |
185 | if (!ISDIGIT (*arg)) |
186 | { |
187 | *err = EINVAL; |
188 | return -1; |
189 | } |
190 | |
191 | *err = 0; |
192 | errno = 0; |
193 | |
194 | char *end = NULL; |
195 | unsigned HOST_WIDE_INT unit = 1; |
196 | unsigned HOST_WIDE_INT value = strtoull (nptr: arg, endptr: &end, base: 10); |
197 | |
198 | /* If the value is too large to be represented use the maximum |
199 | representable value that strtoull sets VALUE to (setting |
200 | errno to ERANGE). */ |
201 | |
202 | if (end && *end) |
203 | { |
204 | if (!byte_size_suffix) |
205 | { |
206 | errno = 0; |
207 | value = strtoull (nptr: arg, endptr: &end, base: 0); |
208 | if (*end) |
209 | { |
210 | if (errno) |
211 | *err = errno; |
212 | else |
213 | *err = EINVAL; |
214 | return -1; |
215 | } |
216 | |
217 | return value; |
218 | } |
219 | |
220 | /* Numeric option arguments are at most INT_MAX. Make it |
221 | possible to specify a larger value by accepting common |
222 | suffixes. */ |
223 | if (!strcmp (s1: end, s2: "kB" )) |
224 | unit = 1000; |
225 | else if (!strcasecmp (s1: end, s2: "KiB" ) || !strcmp (s1: end, s2: "KB" )) |
226 | unit = 1024; |
227 | else if (!strcmp (s1: end, s2: "MB" )) |
228 | unit = HOST_WIDE_INT_UC (1000) * 1000; |
229 | else if (!strcasecmp (s1: end, s2: "MiB" )) |
230 | unit = HOST_WIDE_INT_UC (1024) * 1024; |
231 | else if (!strcasecmp (s1: end, s2: "GB" )) |
232 | unit = HOST_WIDE_INT_UC (1000) * 1000 * 1000; |
233 | else if (!strcasecmp (s1: end, s2: "GiB" )) |
234 | unit = HOST_WIDE_INT_UC (1024) * 1024 * 1024; |
235 | else if (!strcasecmp (s1: end, s2: "TB" )) |
236 | unit = HOST_WIDE_INT_UC (1000) * 1000 * 1000 * 1000; |
237 | else if (!strcasecmp (s1: end, s2: "TiB" )) |
238 | unit = HOST_WIDE_INT_UC (1024) * 1024 * 1024 * 1024; |
239 | else if (!strcasecmp (s1: end, s2: "PB" )) |
240 | unit = HOST_WIDE_INT_UC (1000) * 1000 * 1000 * 1000 * 1000; |
241 | else if (!strcasecmp (s1: end, s2: "PiB" )) |
242 | unit = HOST_WIDE_INT_UC (1024) * 1024 * 1024 * 1024 * 1024; |
243 | else if (!strcasecmp (s1: end, s2: "EB" )) |
244 | unit = HOST_WIDE_INT_UC (1000) * 1000 * 1000 * 1000 * 1000 |
245 | * 1000; |
246 | else if (!strcasecmp (s1: end, s2: "EiB" )) |
247 | unit = HOST_WIDE_INT_UC (1024) * 1024 * 1024 * 1024 * 1024 |
248 | * 1024; |
249 | else |
250 | { |
251 | /* This could mean an unknown suffix or a bad prefix, like |
252 | "+-1". */ |
253 | *err = EINVAL; |
254 | return -1; |
255 | } |
256 | } |
257 | |
258 | if (unit) |
259 | { |
260 | unsigned HOST_WIDE_INT prod = value * unit; |
261 | value = prod < value ? HOST_WIDE_INT_M1U : prod; |
262 | } |
263 | |
264 | return value; |
265 | } |
266 | |
267 | /* Return whether OPTION is OK for the language given by |
268 | LANG_MASK. */ |
269 | static bool |
270 | option_ok_for_language (const struct cl_option *option, |
271 | unsigned int lang_mask) |
272 | { |
273 | if (!(option->flags & lang_mask)) |
274 | return false; |
275 | else if ((option->flags & CL_TARGET) |
276 | && (option->flags & (CL_LANG_ALL | CL_DRIVER)) |
277 | && !(option->flags & (lang_mask & ~CL_COMMON & ~CL_TARGET))) |
278 | /* Complain for target flag language mismatches if any languages |
279 | are specified. */ |
280 | return false; |
281 | return true; |
282 | } |
283 | |
284 | /* Return whether ENUM_ARG is OK for the language given by |
285 | LANG_MASK. */ |
286 | |
287 | static bool |
288 | enum_arg_ok_for_language (const struct cl_enum_arg *enum_arg, |
289 | unsigned int lang_mask) |
290 | { |
291 | return (lang_mask & CL_DRIVER) || !(enum_arg->flags & CL_ENUM_DRIVER_ONLY); |
292 | } |
293 | |
294 | /* Look up ARG in ENUM_ARGS for language LANG_MASK, returning the cl_enum_arg |
295 | index and storing the value in *VALUE if found, and returning -1 without |
296 | modifying *VALUE if not found. */ |
297 | |
298 | static int |
299 | enum_arg_to_value (const struct cl_enum_arg *enum_args, |
300 | const char *arg, size_t len, HOST_WIDE_INT *value, |
301 | unsigned int lang_mask) |
302 | { |
303 | unsigned int i; |
304 | |
305 | for (i = 0; enum_args[i].arg != NULL; i++) |
306 | if ((len |
307 | ? (strncmp (s1: arg, s2: enum_args[i].arg, n: len) == 0 |
308 | && enum_args[i].arg[len] == '\0') |
309 | : strcmp (s1: arg, s2: enum_args[i].arg) == 0) |
310 | && enum_arg_ok_for_language (enum_arg: &enum_args[i], lang_mask)) |
311 | { |
312 | *value = enum_args[i].value; |
313 | return i; |
314 | } |
315 | |
316 | return -1; |
317 | } |
318 | |
319 | /* Look up ARG in the enum used by option OPT_INDEX for language |
320 | LANG_MASK, returning true and storing the value in *VALUE if found, |
321 | and returning false without modifying *VALUE if not found. */ |
322 | |
323 | bool |
324 | opt_enum_arg_to_value (size_t opt_index, const char *arg, |
325 | int *value, unsigned int lang_mask) |
326 | { |
327 | const struct cl_option *option = &cl_options[opt_index]; |
328 | |
329 | gcc_assert (option->var_type == CLVC_ENUM); |
330 | |
331 | HOST_WIDE_INT wideval; |
332 | if (enum_arg_to_value (enum_args: cl_enums[option->var_enum].values, arg, len: 0, |
333 | value: &wideval, lang_mask) >= 0) |
334 | { |
335 | *value = wideval; |
336 | return true; |
337 | } |
338 | |
339 | return false; |
340 | } |
341 | |
342 | /* Look of VALUE in ENUM_ARGS for language LANG_MASK and store the |
343 | corresponding string in *ARGP, returning true if the found string |
344 | was marked as canonical, false otherwise. If VALUE is not found |
345 | (which may be the case for uninitialized values if the relevant |
346 | option has not been passed), set *ARGP to NULL and return |
347 | false. */ |
348 | |
349 | bool |
350 | enum_value_to_arg (const struct cl_enum_arg *enum_args, |
351 | const char **argp, int value, unsigned int lang_mask) |
352 | { |
353 | unsigned int i; |
354 | |
355 | for (i = 0; enum_args[i].arg != NULL; i++) |
356 | if (enum_args[i].value == value |
357 | && (enum_args[i].flags & CL_ENUM_CANONICAL) |
358 | && enum_arg_ok_for_language (enum_arg: &enum_args[i], lang_mask)) |
359 | { |
360 | *argp = enum_args[i].arg; |
361 | return true; |
362 | } |
363 | |
364 | for (i = 0; enum_args[i].arg != NULL; i++) |
365 | if (enum_args[i].value == value |
366 | && enum_arg_ok_for_language (enum_arg: &enum_args[i], lang_mask)) |
367 | { |
368 | *argp = enum_args[i].arg; |
369 | return false; |
370 | } |
371 | |
372 | *argp = NULL; |
373 | return false; |
374 | } |
375 | |
376 | /* Fill in the canonical option part of *DECODED with an option |
377 | described by OPT_INDEX, ARG and VALUE. */ |
378 | |
379 | static void |
380 | generate_canonical_option (size_t opt_index, const char *arg, |
381 | HOST_WIDE_INT value, |
382 | struct cl_decoded_option *decoded) |
383 | { |
384 | const struct cl_option *option = &cl_options[opt_index]; |
385 | const char *opt_text = option->opt_text; |
386 | |
387 | if (value == 0 |
388 | && !option->cl_reject_negative |
389 | && (opt_text[1] == 'W' || opt_text[1] == 'f' |
390 | || opt_text[1] == 'g' || opt_text[1] == 'm')) |
391 | { |
392 | char *t = XOBNEWVEC (&opts_obstack, char, option->opt_len + 5); |
393 | t[0] = '-'; |
394 | t[1] = opt_text[1]; |
395 | t[2] = 'n'; |
396 | t[3] = 'o'; |
397 | t[4] = '-'; |
398 | memcpy (dest: t + 5, src: opt_text + 2, n: option->opt_len); |
399 | opt_text = t; |
400 | } |
401 | |
402 | decoded->canonical_option[2] = NULL; |
403 | decoded->canonical_option[3] = NULL; |
404 | |
405 | if (arg) |
406 | { |
407 | if ((option->flags & CL_SEPARATE) |
408 | && !option->cl_separate_alias) |
409 | { |
410 | decoded->canonical_option[0] = opt_text; |
411 | decoded->canonical_option[1] = arg; |
412 | decoded->canonical_option_num_elements = 2; |
413 | } |
414 | else |
415 | { |
416 | gcc_assert (option->flags & CL_JOINED); |
417 | decoded->canonical_option[0] = opts_concat (first: opt_text, arg, NULL); |
418 | decoded->canonical_option[1] = NULL; |
419 | decoded->canonical_option_num_elements = 1; |
420 | } |
421 | } |
422 | else |
423 | { |
424 | decoded->canonical_option[0] = opt_text; |
425 | decoded->canonical_option[1] = NULL; |
426 | decoded->canonical_option_num_elements = 1; |
427 | } |
428 | } |
429 | |
430 | /* Structure describing mappings from options on the command line to |
431 | options to look up with find_opt. */ |
432 | struct option_map |
433 | { |
434 | /* Prefix of the option on the command line. */ |
435 | const char *opt0; |
436 | /* If two argv elements are considered to be merged into one option, |
437 | prefix for the second element, otherwise NULL. */ |
438 | const char *opt1; |
439 | /* The new prefix to map to. */ |
440 | const char *new_prefix; |
441 | /* Whether at least one character is needed following opt1 or opt0 |
442 | for this mapping to be used. (--optimize= is valid for -O, but |
443 | --warn- is not valid for -W.) */ |
444 | bool another_char_needed; |
445 | /* Whether the original option is a negated form of the option |
446 | resulting from this map. */ |
447 | bool negated; |
448 | }; |
449 | static const struct option_map option_map[] = |
450 | { |
451 | { .opt0: "-Wno-" , NULL, .new_prefix: "-W" , .another_char_needed: false, .negated: true }, |
452 | { .opt0: "-fno-" , NULL, .new_prefix: "-f" , .another_char_needed: false, .negated: true }, |
453 | { .opt0: "-gno-" , NULL, .new_prefix: "-g" , .another_char_needed: false, .negated: true }, |
454 | { .opt0: "-mno-" , NULL, .new_prefix: "-m" , .another_char_needed: false, .negated: true }, |
455 | { .opt0: "--debug=" , NULL, .new_prefix: "-g" , .another_char_needed: false, .negated: false }, |
456 | { .opt0: "--machine-" , NULL, .new_prefix: "-m" , .another_char_needed: true, .negated: false }, |
457 | { .opt0: "--machine-no-" , NULL, .new_prefix: "-m" , .another_char_needed: false, .negated: true }, |
458 | { .opt0: "--machine=" , NULL, .new_prefix: "-m" , .another_char_needed: false, .negated: false }, |
459 | { .opt0: "--machine=no-" , NULL, .new_prefix: "-m" , .another_char_needed: false, .negated: true }, |
460 | { .opt0: "--machine" , .opt1: "" , .new_prefix: "-m" , .another_char_needed: false, .negated: false }, |
461 | { .opt0: "--machine" , .opt1: "no-" , .new_prefix: "-m" , .another_char_needed: false, .negated: true }, |
462 | { .opt0: "--optimize=" , NULL, .new_prefix: "-O" , .another_char_needed: false, .negated: false }, |
463 | { .opt0: "--std=" , NULL, .new_prefix: "-std=" , .another_char_needed: false, .negated: false }, |
464 | { .opt0: "--std" , .opt1: "" , .new_prefix: "-std=" , .another_char_needed: false, .negated: false }, |
465 | { .opt0: "--warn-" , NULL, .new_prefix: "-W" , .another_char_needed: true, .negated: false }, |
466 | { .opt0: "--warn-no-" , NULL, .new_prefix: "-W" , .another_char_needed: false, .negated: true }, |
467 | { .opt0: "--" , NULL, .new_prefix: "-f" , .another_char_needed: true, .negated: false }, |
468 | { .opt0: "--no-" , NULL, .new_prefix: "-f" , .another_char_needed: false, .negated: true } |
469 | }; |
470 | |
471 | /* Given buffer P of size SZ, look for a prefix within OPTION_MAP; |
472 | if found, return the prefix and write the new prefix to *OUT_NEW_PREFIX. |
473 | Otherwise return nullptr. */ |
474 | |
475 | const char * |
476 | get_option_prefix_remapping (const char *p, size_t sz, |
477 | const char **out_new_prefix) |
478 | { |
479 | for (unsigned i = 0; i < ARRAY_SIZE (option_map); i++) |
480 | { |
481 | const char * const old_prefix = option_map[i].opt0; |
482 | const size_t old_prefix_len = strlen (s: old_prefix); |
483 | if (old_prefix_len <= sz |
484 | && !memcmp (s1: p, s2: old_prefix, n: old_prefix_len)) |
485 | { |
486 | *out_new_prefix = option_map[i].new_prefix; |
487 | return old_prefix; |
488 | } |
489 | } |
490 | return nullptr; |
491 | } |
492 | |
493 | /* Helper function for gcc.cc's driver::suggest_option, for populating the |
494 | vec of suggestions for misspelled options. |
495 | |
496 | option_map above provides various prefixes for spelling command-line |
497 | options, which decode_cmdline_option uses to map spellings of options |
498 | to specific options. We want to do the reverse: to find all the ways |
499 | that a user could validly spell an option. |
500 | |
501 | Given valid OPT_TEXT (with a leading dash) for OPTION, add it and all |
502 | of its valid variant spellings to CANDIDATES, each without a leading |
503 | dash. |
504 | |
505 | For example, given "-Wabi-tag", the following are added to CANDIDATES: |
506 | "Wabi-tag" |
507 | "Wno-abi-tag" |
508 | "-warn-abi-tag" |
509 | "-warn-no-abi-tag". |
510 | |
511 | The added strings must be freed using free. */ |
512 | |
513 | void |
514 | add_misspelling_candidates (auto_vec<char *> *candidates, |
515 | const struct cl_option *option, |
516 | const char *opt_text) |
517 | { |
518 | gcc_assert (candidates); |
519 | gcc_assert (option); |
520 | gcc_assert (opt_text); |
521 | if (remapping_prefix_p (opt: option)) |
522 | return; |
523 | candidates->safe_push (obj: xstrdup (opt_text + 1)); |
524 | for (unsigned i = 0; i < ARRAY_SIZE (option_map); i++) |
525 | { |
526 | const char *opt0 = option_map[i].opt0; |
527 | const char *new_prefix = option_map[i].new_prefix; |
528 | size_t new_prefix_len = strlen (s: new_prefix); |
529 | |
530 | if (option->cl_reject_negative && option_map[i].negated) |
531 | continue; |
532 | |
533 | if (strncmp (s1: opt_text, s2: new_prefix, n: new_prefix_len) == 0) |
534 | { |
535 | char *alternative = concat (opt0 + 1, opt_text + new_prefix_len, |
536 | NULL); |
537 | candidates->safe_push (obj: alternative); |
538 | } |
539 | } |
540 | |
541 | /* For all params (e.g. --param=key=value), |
542 | include also '--param key=value'. */ |
543 | const char *prefix = "--param=" ; |
544 | if (strstr (haystack: opt_text, needle: prefix) == opt_text) |
545 | { |
546 | char *param = xstrdup (opt_text + 1); |
547 | gcc_assert (param[6] == '='); |
548 | param[6] = ' '; |
549 | candidates->safe_push (obj: param); |
550 | } |
551 | } |
552 | |
553 | /* Decode the switch beginning at ARGV for the language indicated by |
554 | LANG_MASK (including CL_COMMON and CL_TARGET if applicable), into |
555 | the structure *DECODED. Returns the number of switches |
556 | consumed. */ |
557 | |
558 | static unsigned int |
559 | decode_cmdline_option (const char *const *argv, unsigned int lang_mask, |
560 | struct cl_decoded_option *decoded) |
561 | { |
562 | size_t opt_index; |
563 | const char *arg = 0; |
564 | HOST_WIDE_INT value = 1, mask = 0; |
565 | unsigned int result = 1, i, , separate_args = 0; |
566 | int adjust_len = 0; |
567 | size_t total_len; |
568 | char *p; |
569 | const struct cl_option *option; |
570 | int errors = 0; |
571 | const char *warn_message = NULL; |
572 | bool separate_arg_flag; |
573 | bool joined_arg_flag; |
574 | bool have_separate_arg = false; |
575 | |
576 | extra_args = 0; |
577 | |
578 | const char *opt_value = argv[0] + 1; |
579 | opt_index = find_opt (input: opt_value, lang_mask); |
580 | i = 0; |
581 | while (opt_index == OPT_SPECIAL_unknown |
582 | && i < ARRAY_SIZE (option_map)) |
583 | { |
584 | const char *opt0 = option_map[i].opt0; |
585 | const char *opt1 = option_map[i].opt1; |
586 | const char *new_prefix = option_map[i].new_prefix; |
587 | bool another_char_needed = option_map[i].another_char_needed; |
588 | size_t opt0_len = strlen (s: opt0); |
589 | size_t opt1_len = (opt1 == NULL ? 0 : strlen (s: opt1)); |
590 | size_t optn_len = (opt1 == NULL ? opt0_len : opt1_len); |
591 | size_t new_prefix_len = strlen (s: new_prefix); |
592 | |
593 | extra_args = (opt1 == NULL ? 0 : 1); |
594 | value = !option_map[i].negated; |
595 | |
596 | if (strncmp (s1: argv[0], s2: opt0, n: opt0_len) == 0 |
597 | && (opt1 == NULL |
598 | || (argv[1] != NULL && strncmp (s1: argv[1], s2: opt1, n: opt1_len) == 0)) |
599 | && (!another_char_needed |
600 | || argv[extra_args][optn_len] != 0)) |
601 | { |
602 | size_t arglen = strlen (s: argv[extra_args]); |
603 | char *dup; |
604 | |
605 | adjust_len = (int) optn_len - (int) new_prefix_len; |
606 | dup = XNEWVEC (char, arglen + 1 - adjust_len); |
607 | memcpy (dest: dup, src: new_prefix, n: new_prefix_len); |
608 | memcpy (dest: dup + new_prefix_len, src: argv[extra_args] + optn_len, |
609 | n: arglen - optn_len + 1); |
610 | opt_index = find_opt (input: dup + 1, lang_mask); |
611 | free (ptr: dup); |
612 | } |
613 | i++; |
614 | } |
615 | |
616 | if (opt_index == OPT_SPECIAL_unknown) |
617 | { |
618 | arg = argv[0]; |
619 | extra_args = 0; |
620 | value = 1; |
621 | goto done; |
622 | } |
623 | |
624 | option = &cl_options[opt_index]; |
625 | |
626 | /* Reject negative form of switches that don't take negatives as |
627 | unrecognized. */ |
628 | if (!value && option->cl_reject_negative) |
629 | { |
630 | opt_index = OPT_SPECIAL_unknown; |
631 | errors |= CL_ERR_NEGATIVE; |
632 | arg = argv[0]; |
633 | goto done; |
634 | } |
635 | |
636 | /* Clear the initial value for size options (it will be overwritten |
637 | later based on the Init(value) specification in the opt file. */ |
638 | if (option->var_type == CLVC_SIZE) |
639 | value = 0; |
640 | |
641 | result = extra_args + 1; |
642 | warn_message = option->warn_message; |
643 | |
644 | /* Check to see if the option is disabled for this configuration. */ |
645 | if (option->cl_disabled) |
646 | errors |= CL_ERR_DISABLED; |
647 | |
648 | /* Determine whether there may be a separate argument based on |
649 | whether this option is being processed for the driver, and, if |
650 | so, how many such arguments. */ |
651 | separate_arg_flag = ((option->flags & CL_SEPARATE) |
652 | && !(option->cl_no_driver_arg |
653 | && (lang_mask & CL_DRIVER))); |
654 | separate_args = (separate_arg_flag |
655 | ? option->cl_separate_nargs + 1 |
656 | : 0); |
657 | joined_arg_flag = (option->flags & CL_JOINED) != 0; |
658 | |
659 | /* Sort out any argument the switch takes. */ |
660 | if (joined_arg_flag) |
661 | { |
662 | /* Have arg point to the original switch. This is because |
663 | some code, such as disable_builtin_function, expects its |
664 | argument to be persistent until the program exits. */ |
665 | arg = argv[extra_args] + cl_options[opt_index].opt_len + 1 + adjust_len; |
666 | |
667 | if (*arg == '\0' && !option->cl_missing_ok) |
668 | { |
669 | if (separate_arg_flag) |
670 | { |
671 | arg = argv[extra_args + 1]; |
672 | result = extra_args + 2; |
673 | if (arg == NULL) |
674 | result = extra_args + 1; |
675 | else |
676 | have_separate_arg = true; |
677 | } |
678 | else |
679 | /* Missing argument. */ |
680 | arg = NULL; |
681 | } |
682 | } |
683 | else if (separate_arg_flag) |
684 | { |
685 | arg = argv[extra_args + 1]; |
686 | for (i = 0; i < separate_args; i++) |
687 | if (argv[extra_args + 1 + i] == NULL) |
688 | { |
689 | errors |= CL_ERR_MISSING_ARG; |
690 | break; |
691 | } |
692 | result = extra_args + 1 + i; |
693 | if (arg != NULL) |
694 | have_separate_arg = true; |
695 | } |
696 | |
697 | if (arg == NULL && (separate_arg_flag || joined_arg_flag)) |
698 | errors |= CL_ERR_MISSING_ARG; |
699 | |
700 | /* Is this option an alias (or an ignored option, marked as an alias |
701 | of OPT_SPECIAL_ignore)? */ |
702 | if (option->alias_target != N_OPTS |
703 | && (!option->cl_separate_alias || have_separate_arg)) |
704 | { |
705 | size_t new_opt_index = option->alias_target; |
706 | |
707 | if (new_opt_index == OPT_SPECIAL_ignore |
708 | || new_opt_index == OPT_SPECIAL_warn_removed) |
709 | { |
710 | gcc_assert (option->alias_arg == NULL); |
711 | gcc_assert (option->neg_alias_arg == NULL); |
712 | opt_index = new_opt_index; |
713 | arg = NULL; |
714 | } |
715 | else |
716 | { |
717 | const struct cl_option *new_option = &cl_options[new_opt_index]; |
718 | |
719 | /* The new option must not be an alias itself. */ |
720 | gcc_assert (new_option->alias_target == N_OPTS |
721 | || new_option->cl_separate_alias); |
722 | |
723 | if (option->neg_alias_arg) |
724 | { |
725 | gcc_assert (option->alias_arg != NULL); |
726 | gcc_assert (arg == NULL); |
727 | gcc_assert (!option->cl_negative_alias); |
728 | if (value) |
729 | arg = option->alias_arg; |
730 | else |
731 | arg = option->neg_alias_arg; |
732 | value = 1; |
733 | } |
734 | else if (option->alias_arg) |
735 | { |
736 | gcc_assert (value == 1); |
737 | gcc_assert (arg == NULL); |
738 | gcc_assert (!option->cl_negative_alias); |
739 | arg = option->alias_arg; |
740 | } |
741 | |
742 | if (option->cl_negative_alias) |
743 | value = !value; |
744 | |
745 | opt_index = new_opt_index; |
746 | option = new_option; |
747 | |
748 | if (value == 0) |
749 | gcc_assert (!option->cl_reject_negative); |
750 | |
751 | /* Recompute what arguments are allowed. */ |
752 | separate_arg_flag = ((option->flags & CL_SEPARATE) |
753 | && !(option->cl_no_driver_arg |
754 | && (lang_mask & CL_DRIVER))); |
755 | joined_arg_flag = (option->flags & CL_JOINED) != 0; |
756 | |
757 | if (separate_args > 1 || option->cl_separate_nargs) |
758 | gcc_assert (separate_args |
759 | == (unsigned int) option->cl_separate_nargs + 1); |
760 | |
761 | if (!(errors & CL_ERR_MISSING_ARG)) |
762 | { |
763 | if (separate_arg_flag || joined_arg_flag) |
764 | { |
765 | if (option->cl_missing_ok && arg == NULL) |
766 | arg = "" ; |
767 | gcc_assert (arg != NULL); |
768 | } |
769 | else |
770 | gcc_assert (arg == NULL); |
771 | } |
772 | |
773 | /* Recheck for warnings and disabled options. */ |
774 | if (option->warn_message) |
775 | { |
776 | gcc_assert (warn_message == NULL); |
777 | warn_message = option->warn_message; |
778 | } |
779 | if (option->cl_disabled) |
780 | errors |= CL_ERR_DISABLED; |
781 | } |
782 | } |
783 | |
784 | /* Check if this is a switch for a different front end. */ |
785 | if (!option_ok_for_language (option, lang_mask)) |
786 | errors |= CL_ERR_WRONG_LANG; |
787 | else if (strcmp (s1: option->opt_text, s2: "-Werror=" ) == 0 |
788 | && strchr (s: opt_value, c: ',') == NULL) |
789 | { |
790 | /* Verify that -Werror argument is a valid warning |
791 | for a language. */ |
792 | char *werror_arg = xstrdup (opt_value + 6); |
793 | werror_arg[0] = 'W'; |
794 | |
795 | size_t warning_index = find_opt (input: werror_arg, lang_mask); |
796 | free (ptr: werror_arg); |
797 | if (warning_index != OPT_SPECIAL_unknown) |
798 | { |
799 | const struct cl_option *warning_option |
800 | = &cl_options[warning_index]; |
801 | if (!option_ok_for_language (option: warning_option, lang_mask)) |
802 | errors |= CL_ERR_WRONG_LANG; |
803 | } |
804 | } |
805 | |
806 | /* Convert the argument to lowercase if appropriate. */ |
807 | if (arg && option->cl_tolower) |
808 | { |
809 | size_t j; |
810 | size_t len = strlen (s: arg); |
811 | char *arg_lower = XOBNEWVEC (&opts_obstack, char, len + 1); |
812 | |
813 | for (j = 0; j < len; j++) |
814 | arg_lower[j] = TOLOWER ((unsigned char) arg[j]); |
815 | arg_lower[len] = 0; |
816 | arg = arg_lower; |
817 | } |
818 | |
819 | /* If the switch takes an integer argument, convert it. */ |
820 | if (arg && (option->cl_uinteger || option->cl_host_wide_int)) |
821 | { |
822 | int error = 0; |
823 | value = *arg ? integral_argument (arg, err: &error, byte_size_suffix: option->cl_byte_size) : 0; |
824 | if (error) |
825 | errors |= CL_ERR_UINT_ARG; |
826 | |
827 | /* Reject value out of a range. */ |
828 | if (option->range_max != -1 |
829 | && (value < option->range_min || value > option->range_max)) |
830 | errors |= CL_ERR_INT_RANGE_ARG; |
831 | } |
832 | |
833 | /* If the switch takes an enumerated argument, convert it. */ |
834 | if (arg && (option->var_type == CLVC_ENUM)) |
835 | { |
836 | const struct cl_enum *e = &cl_enums[option->var_enum]; |
837 | |
838 | gcc_assert (option->var_value != CLEV_NORMAL || value == 1); |
839 | if (option->var_value != CLEV_NORMAL) |
840 | { |
841 | const char *p = arg; |
842 | HOST_WIDE_INT sum_value = 0; |
843 | unsigned HOST_WIDE_INT used_sets = 0; |
844 | do |
845 | { |
846 | const char *q = strchr (s: p, c: ','); |
847 | HOST_WIDE_INT this_value = 0; |
848 | if (q && q == p) |
849 | { |
850 | errors |= CL_ERR_ENUM_SET_ARG; |
851 | break; |
852 | } |
853 | int idx = enum_arg_to_value (enum_args: e->values, arg: p, len: q ? q - p : 0, |
854 | value: &this_value, lang_mask); |
855 | if (idx < 0) |
856 | { |
857 | errors |= CL_ERR_ENUM_SET_ARG; |
858 | break; |
859 | } |
860 | |
861 | HOST_WIDE_INT this_mask = 0; |
862 | if (option->var_value == CLEV_SET) |
863 | { |
864 | unsigned set = e->values[idx].flags >> CL_ENUM_SET_SHIFT; |
865 | gcc_checking_assert (set >= 1 |
866 | && set <= HOST_BITS_PER_WIDE_INT); |
867 | if ((used_sets & (HOST_WIDE_INT_1U << (set - 1))) != 0) |
868 | { |
869 | errors |= CL_ERR_ENUM_SET_ARG; |
870 | break; |
871 | } |
872 | used_sets |= HOST_WIDE_INT_1U << (set - 1); |
873 | |
874 | for (int i = 0; e->values[i].arg != NULL; i++) |
875 | if (set == (e->values[i].flags >> CL_ENUM_SET_SHIFT)) |
876 | this_mask |= e->values[i].value; |
877 | } |
878 | else |
879 | { |
880 | gcc_assert (option->var_value == CLEV_BITSET |
881 | && ((e->values[idx].flags >> CL_ENUM_SET_SHIFT) |
882 | == 0)); |
883 | this_mask = this_value; |
884 | } |
885 | |
886 | sum_value |= this_value; |
887 | mask |= this_mask; |
888 | if (q == NULL) |
889 | break; |
890 | p = q + 1; |
891 | } |
892 | while (1); |
893 | if (value == 1) |
894 | value = sum_value; |
895 | else |
896 | gcc_checking_assert (value == 0); |
897 | } |
898 | else if (enum_arg_to_value (enum_args: e->values, arg, len: 0, value: &value, lang_mask) >= 0) |
899 | { |
900 | const char *carg = NULL; |
901 | |
902 | if (enum_value_to_arg (enum_args: e->values, argp: &carg, value, lang_mask)) |
903 | arg = carg; |
904 | gcc_assert (carg != NULL); |
905 | } |
906 | else |
907 | errors |= CL_ERR_ENUM_ARG; |
908 | } |
909 | |
910 | done: |
911 | decoded->opt_index = opt_index; |
912 | decoded->arg = arg; |
913 | decoded->value = value; |
914 | decoded->mask = mask; |
915 | decoded->errors = errors; |
916 | decoded->warn_message = warn_message; |
917 | |
918 | if (opt_index == OPT_SPECIAL_unknown) |
919 | gcc_assert (result == 1); |
920 | |
921 | gcc_assert (result >= 1 && result <= ARRAY_SIZE (decoded->canonical_option)); |
922 | decoded->canonical_option_num_elements = result; |
923 | total_len = 0; |
924 | for (i = 0; i < ARRAY_SIZE (decoded->canonical_option); i++) |
925 | { |
926 | if (i < result) |
927 | { |
928 | size_t len; |
929 | if (opt_index == OPT_SPECIAL_unknown) |
930 | decoded->canonical_option[i] = argv[i]; |
931 | else |
932 | decoded->canonical_option[i] = NULL; |
933 | len = strlen (s: argv[i]); |
934 | /* If the argument is an empty string, we will print it as "" in |
935 | orig_option_with_args_text. */ |
936 | total_len += (len != 0 ? len : 2) + 1; |
937 | } |
938 | else |
939 | decoded->canonical_option[i] = NULL; |
940 | } |
941 | if (opt_index != OPT_SPECIAL_unknown && opt_index != OPT_SPECIAL_ignore |
942 | && opt_index != OPT_SPECIAL_warn_removed) |
943 | { |
944 | generate_canonical_option (opt_index, arg, value, decoded); |
945 | if (separate_args > 1) |
946 | { |
947 | for (i = 0; i < separate_args; i++) |
948 | { |
949 | if (argv[extra_args + 1 + i] == NULL) |
950 | break; |
951 | else |
952 | decoded->canonical_option[1 + i] = argv[extra_args + 1 + i]; |
953 | } |
954 | gcc_assert (result == 1 + i); |
955 | decoded->canonical_option_num_elements = result; |
956 | } |
957 | } |
958 | decoded->orig_option_with_args_text |
959 | = p = XOBNEWVEC (&opts_obstack, char, total_len); |
960 | for (i = 0; i < result; i++) |
961 | { |
962 | size_t len = strlen (s: argv[i]); |
963 | |
964 | /* Print the empty string verbally. */ |
965 | if (len == 0) |
966 | { |
967 | *p++ = '"'; |
968 | *p++ = '"'; |
969 | } |
970 | else |
971 | memcpy (dest: p, src: argv[i], n: len); |
972 | p += len; |
973 | if (i == result - 1) |
974 | *p++ = 0; |
975 | else |
976 | *p++ = ' '; |
977 | } |
978 | |
979 | return result; |
980 | } |
981 | |
982 | /* Obstack for option strings. */ |
983 | |
984 | struct obstack opts_obstack; |
985 | |
986 | /* Like libiberty concat, but allocate using opts_obstack. */ |
987 | |
988 | char * |
989 | opts_concat (const char *first, ...) |
990 | { |
991 | char *newstr, *end; |
992 | size_t length = 0; |
993 | const char *arg; |
994 | va_list ap; |
995 | |
996 | /* First compute the size of the result and get sufficient memory. */ |
997 | va_start (ap, first); |
998 | for (arg = first; arg; arg = va_arg (ap, const char *)) |
999 | length += strlen (s: arg); |
1000 | newstr = XOBNEWVEC (&opts_obstack, char, length + 1); |
1001 | va_end (ap); |
1002 | |
1003 | /* Now copy the individual pieces to the result string. */ |
1004 | va_start (ap, first); |
1005 | for (arg = first, end = newstr; arg; arg = va_arg (ap, const char *)) |
1006 | { |
1007 | length = strlen (s: arg); |
1008 | memcpy (dest: end, src: arg, n: length); |
1009 | end += length; |
1010 | } |
1011 | *end = '\0'; |
1012 | va_end (ap); |
1013 | return newstr; |
1014 | } |
1015 | |
1016 | /* Decode command-line options (ARGC and ARGV being the arguments of |
1017 | main) into an array, setting *DECODED_OPTIONS to a pointer to that |
1018 | array and *DECODED_OPTIONS_COUNT to the number of entries in the |
1019 | array. The first entry in the array is always one for the program |
1020 | name (OPT_SPECIAL_program_name). LANG_MASK indicates the language |
1021 | flags applicable for decoding (including CL_COMMON and CL_TARGET if |
1022 | those options should be considered applicable). Do not produce any |
1023 | diagnostics or set state outside of these variables. */ |
1024 | |
1025 | void |
1026 | decode_cmdline_options_to_array (unsigned int argc, const char **argv, |
1027 | unsigned int lang_mask, |
1028 | struct cl_decoded_option **decoded_options, |
1029 | unsigned int *decoded_options_count) |
1030 | { |
1031 | unsigned int n, i; |
1032 | struct cl_decoded_option *opt_array; |
1033 | unsigned int num_decoded_options; |
1034 | |
1035 | int opt_array_len = argc; |
1036 | opt_array = XNEWVEC (struct cl_decoded_option, opt_array_len); |
1037 | |
1038 | opt_array[0].opt_index = OPT_SPECIAL_program_name; |
1039 | opt_array[0].warn_message = NULL; |
1040 | opt_array[0].arg = argv[0]; |
1041 | opt_array[0].orig_option_with_args_text = argv[0]; |
1042 | opt_array[0].canonical_option_num_elements = 1; |
1043 | opt_array[0].canonical_option[0] = argv[0]; |
1044 | opt_array[0].canonical_option[1] = NULL; |
1045 | opt_array[0].canonical_option[2] = NULL; |
1046 | opt_array[0].canonical_option[3] = NULL; |
1047 | opt_array[0].value = 1; |
1048 | opt_array[0].mask = 0; |
1049 | opt_array[0].errors = 0; |
1050 | num_decoded_options = 1; |
1051 | |
1052 | for (i = 1; i < argc; i += n) |
1053 | { |
1054 | const char *opt = argv[i]; |
1055 | |
1056 | /* Interpret "-" or a non-switch as a file name. */ |
1057 | if (opt[0] != '-' || opt[1] == '\0') |
1058 | { |
1059 | generate_option_input_file (file: opt, decoded: &opt_array[num_decoded_options]); |
1060 | num_decoded_options++; |
1061 | n = 1; |
1062 | continue; |
1063 | } |
1064 | |
1065 | /* Interpret "--param" "key=name" as "--param=key=name". */ |
1066 | const char *needle = "--param" ; |
1067 | if (i + 1 < argc && strcmp (s1: opt, s2: needle) == 0) |
1068 | { |
1069 | const char *replacement |
1070 | = opts_concat (first: needle, "=" , argv[i + 1], NULL); |
1071 | argv[++i] = replacement; |
1072 | } |
1073 | |
1074 | /* Expand -fdiagnostics-plain-output to its constituents. This needs |
1075 | to happen here so that prune_options can handle -fdiagnostics-color |
1076 | specially. */ |
1077 | if (!strcmp (s1: opt, s2: "-fdiagnostics-plain-output" )) |
1078 | { |
1079 | /* If you have changed the default diagnostics output, and this new |
1080 | output is not appropriately "plain" (e.g., the change needs to be |
1081 | undone in order for the testsuite to work properly), then please do |
1082 | the following: |
1083 | 1. Add the necessary option to undo the new behavior to |
1084 | the array below. |
1085 | 2. Update the documentation for -fdiagnostics-plain-output |
1086 | in invoke.texi. */ |
1087 | const char *const expanded_args[] = { |
1088 | "-fno-diagnostics-show-caret" , |
1089 | "-fno-diagnostics-show-line-numbers" , |
1090 | "-fdiagnostics-color=never" , |
1091 | "-fdiagnostics-urls=never" , |
1092 | "-fdiagnostics-path-format=separate-events" , |
1093 | "-fdiagnostics-text-art-charset=none" |
1094 | }; |
1095 | const int num_expanded = ARRAY_SIZE (expanded_args); |
1096 | opt_array_len += num_expanded - 1; |
1097 | opt_array = XRESIZEVEC (struct cl_decoded_option, |
1098 | opt_array, opt_array_len); |
1099 | for (int j = 0, nj; j < num_expanded; j += nj) |
1100 | { |
1101 | nj = decode_cmdline_option (argv: expanded_args + j, lang_mask, |
1102 | decoded: &opt_array[num_decoded_options]); |
1103 | num_decoded_options++; |
1104 | } |
1105 | |
1106 | n = 1; |
1107 | continue; |
1108 | } |
1109 | |
1110 | n = decode_cmdline_option (argv: argv + i, lang_mask, |
1111 | decoded: &opt_array[num_decoded_options]); |
1112 | num_decoded_options++; |
1113 | } |
1114 | |
1115 | *decoded_options = opt_array; |
1116 | *decoded_options_count = num_decoded_options; |
1117 | prune_options (decoded_options, decoded_options_count); |
1118 | } |
1119 | |
1120 | /* Return true if NEXT_OPT_IDX cancels OPT_IDX. Return false if the |
1121 | next one is the same as ORIG_NEXT_OPT_IDX. */ |
1122 | |
1123 | static bool |
1124 | cancel_option (int opt_idx, int next_opt_idx, int orig_next_opt_idx) |
1125 | { |
1126 | /* An option can be canceled by the same option or an option with |
1127 | Negative. */ |
1128 | if (cl_options [next_opt_idx].neg_index == opt_idx) |
1129 | return true; |
1130 | |
1131 | if (cl_options [next_opt_idx].neg_index != orig_next_opt_idx) |
1132 | return cancel_option (opt_idx, next_opt_idx: cl_options [next_opt_idx].neg_index, |
1133 | orig_next_opt_idx); |
1134 | |
1135 | return false; |
1136 | } |
1137 | |
1138 | /* Filter out options canceled by the ones after them, and related |
1139 | rearrangement. */ |
1140 | |
1141 | static void |
1142 | prune_options (struct cl_decoded_option **decoded_options, |
1143 | unsigned int *decoded_options_count) |
1144 | { |
1145 | unsigned int old_decoded_options_count = *decoded_options_count; |
1146 | struct cl_decoded_option *old_decoded_options = *decoded_options; |
1147 | unsigned int new_decoded_options_count; |
1148 | struct cl_decoded_option *new_decoded_options |
1149 | = XNEWVEC (struct cl_decoded_option, old_decoded_options_count); |
1150 | unsigned int i; |
1151 | const struct cl_option *option; |
1152 | unsigned int options_to_prepend = 0; |
1153 | unsigned int Wcomplain_wrong_lang_idx = 0; |
1154 | unsigned int fdiagnostics_color_idx = 0; |
1155 | |
1156 | /* Remove arguments which are negated by others after them. */ |
1157 | new_decoded_options_count = 0; |
1158 | for (i = 0; i < old_decoded_options_count; i++) |
1159 | { |
1160 | unsigned int j, opt_idx, next_opt_idx; |
1161 | |
1162 | if (old_decoded_options[i].errors & ~CL_ERR_WRONG_LANG) |
1163 | goto keep; |
1164 | |
1165 | opt_idx = old_decoded_options[i].opt_index; |
1166 | switch (opt_idx) |
1167 | { |
1168 | case OPT_SPECIAL_unknown: |
1169 | case OPT_SPECIAL_ignore: |
1170 | case OPT_SPECIAL_warn_removed: |
1171 | case OPT_SPECIAL_program_name: |
1172 | case OPT_SPECIAL_input_file: |
1173 | goto keep; |
1174 | |
1175 | /* Do not handle the following yet, just remember the last one. */ |
1176 | case OPT_Wcomplain_wrong_lang: |
1177 | gcc_checking_assert (i != 0); |
1178 | if (Wcomplain_wrong_lang_idx == 0) |
1179 | ++options_to_prepend; |
1180 | Wcomplain_wrong_lang_idx = i; |
1181 | continue; |
1182 | case OPT_fdiagnostics_color_: |
1183 | gcc_checking_assert (i != 0); |
1184 | if (fdiagnostics_color_idx == 0) |
1185 | ++options_to_prepend; |
1186 | fdiagnostics_color_idx = i; |
1187 | continue; |
1188 | |
1189 | default: |
1190 | gcc_assert (opt_idx < cl_options_count); |
1191 | option = &cl_options[opt_idx]; |
1192 | if (option->neg_index < 0) |
1193 | goto keep; |
1194 | |
1195 | /* Skip joined switches. */ |
1196 | if ((option->flags & CL_JOINED) |
1197 | && (!option->cl_reject_negative |
1198 | || (unsigned int) option->neg_index != opt_idx)) |
1199 | goto keep; |
1200 | |
1201 | for (j = i + 1; j < old_decoded_options_count; j++) |
1202 | { |
1203 | if (old_decoded_options[j].errors & ~CL_ERR_WRONG_LANG) |
1204 | continue; |
1205 | next_opt_idx = old_decoded_options[j].opt_index; |
1206 | if (next_opt_idx >= cl_options_count) |
1207 | continue; |
1208 | if (cl_options[next_opt_idx].neg_index < 0) |
1209 | continue; |
1210 | if ((cl_options[next_opt_idx].flags & CL_JOINED) |
1211 | && (!cl_options[next_opt_idx].cl_reject_negative |
1212 | || ((unsigned int) cl_options[next_opt_idx].neg_index |
1213 | != next_opt_idx))) |
1214 | continue; |
1215 | if (cancel_option (opt_idx, next_opt_idx, orig_next_opt_idx: next_opt_idx)) |
1216 | break; |
1217 | } |
1218 | if (j == old_decoded_options_count) |
1219 | { |
1220 | keep: |
1221 | new_decoded_options[new_decoded_options_count] |
1222 | = old_decoded_options[i]; |
1223 | new_decoded_options_count++; |
1224 | } |
1225 | break; |
1226 | } |
1227 | } |
1228 | |
1229 | /* For those not yet handled, put (only) the last at a front position after |
1230 | 'argv[0]', so they can take effect immediately. */ |
1231 | if (options_to_prepend) |
1232 | { |
1233 | const unsigned int argv_0 = 1; |
1234 | memmove (dest: new_decoded_options + argv_0 + options_to_prepend, |
1235 | src: new_decoded_options + argv_0, |
1236 | n: sizeof (struct cl_decoded_option) |
1237 | * (new_decoded_options_count - argv_0)); |
1238 | unsigned int options_prepended = 0; |
1239 | if (Wcomplain_wrong_lang_idx != 0) |
1240 | { |
1241 | new_decoded_options[argv_0 + options_prepended++] |
1242 | = old_decoded_options[Wcomplain_wrong_lang_idx]; |
1243 | new_decoded_options_count++; |
1244 | } |
1245 | if (fdiagnostics_color_idx != 0) |
1246 | { |
1247 | new_decoded_options[argv_0 + options_prepended++] |
1248 | = old_decoded_options[fdiagnostics_color_idx]; |
1249 | new_decoded_options_count++; |
1250 | } |
1251 | gcc_checking_assert (options_to_prepend == options_prepended); |
1252 | } |
1253 | |
1254 | free (ptr: old_decoded_options); |
1255 | new_decoded_options = XRESIZEVEC (struct cl_decoded_option, |
1256 | new_decoded_options, |
1257 | new_decoded_options_count); |
1258 | *decoded_options = new_decoded_options; |
1259 | *decoded_options_count = new_decoded_options_count; |
1260 | } |
1261 | |
1262 | /* Handle option DECODED for the language indicated by LANG_MASK, |
1263 | using the handlers in HANDLERS and setting fields in OPTS and |
1264 | OPTS_SET. KIND is the diagnostic_t if this is a diagnostics |
1265 | option, DK_UNSPECIFIED otherwise, and LOC is the location of the |
1266 | option for options from the source file, UNKNOWN_LOCATION |
1267 | otherwise. GENERATED_P is true for an option generated as part of |
1268 | processing another option or otherwise generated internally, false |
1269 | for one explicitly passed by the user. control_warning_option |
1270 | generated options are considered explicitly passed by the user. |
1271 | Returns false if the switch was invalid. DC is the diagnostic |
1272 | context for options affecting diagnostics state, or NULL. */ |
1273 | |
1274 | static bool |
1275 | handle_option (struct gcc_options *opts, |
1276 | struct gcc_options *opts_set, |
1277 | const struct cl_decoded_option *decoded, |
1278 | unsigned int lang_mask, int kind, location_t loc, |
1279 | const struct cl_option_handlers *handlers, |
1280 | bool generated_p, diagnostic_context *dc) |
1281 | { |
1282 | size_t opt_index = decoded->opt_index; |
1283 | const char *arg = decoded->arg; |
1284 | HOST_WIDE_INT value = decoded->value; |
1285 | HOST_WIDE_INT mask = decoded->mask; |
1286 | const struct cl_option *option = &cl_options[opt_index]; |
1287 | void *flag_var = option_flag_var (opt_index, opts); |
1288 | size_t i; |
1289 | |
1290 | if (flag_var) |
1291 | set_option (opts, opts_set: (generated_p ? NULL : opts_set), |
1292 | opt_index, value, arg, kind, loc, dc, mask); |
1293 | |
1294 | for (i = 0; i < handlers->num_handlers; i++) |
1295 | if (option->flags & handlers->handlers[i].mask) |
1296 | { |
1297 | if (!handlers->handlers[i].handler (opts, opts_set, decoded, |
1298 | lang_mask, kind, loc, |
1299 | handlers, dc, |
1300 | handlers->target_option_override_hook)) |
1301 | return false; |
1302 | } |
1303 | |
1304 | return true; |
1305 | } |
1306 | |
1307 | /* Like handle_option, but OPT_INDEX, ARG and VALUE describe the |
1308 | option instead of DECODED. This is used for callbacks when one |
1309 | option implies another instead of an option being decoded from the |
1310 | command line. */ |
1311 | |
1312 | bool |
1313 | handle_generated_option (struct gcc_options *opts, |
1314 | struct gcc_options *opts_set, |
1315 | size_t opt_index, const char *arg, HOST_WIDE_INT value, |
1316 | unsigned int lang_mask, int kind, location_t loc, |
1317 | const struct cl_option_handlers *handlers, |
1318 | bool generated_p, diagnostic_context *dc) |
1319 | { |
1320 | struct cl_decoded_option decoded; |
1321 | |
1322 | generate_option (opt_index, arg, value, lang_mask, decoded: &decoded); |
1323 | return handle_option (opts, opts_set, decoded: &decoded, lang_mask, kind, loc, |
1324 | handlers, generated_p, dc); |
1325 | } |
1326 | |
1327 | /* Fill in *DECODED with an option described by OPT_INDEX, ARG and |
1328 | VALUE for a front end using LANG_MASK. This is used when the |
1329 | compiler generates options internally. */ |
1330 | |
1331 | void |
1332 | generate_option (size_t opt_index, const char *arg, HOST_WIDE_INT value, |
1333 | unsigned int lang_mask, struct cl_decoded_option *decoded) |
1334 | { |
1335 | const struct cl_option *option = &cl_options[opt_index]; |
1336 | |
1337 | decoded->opt_index = opt_index; |
1338 | decoded->warn_message = NULL; |
1339 | decoded->arg = arg; |
1340 | decoded->value = value; |
1341 | decoded->mask = 0; |
1342 | decoded->errors = (option_ok_for_language (option, lang_mask) |
1343 | ? 0 |
1344 | : CL_ERR_WRONG_LANG); |
1345 | |
1346 | generate_canonical_option (opt_index, arg, value, decoded); |
1347 | switch (decoded->canonical_option_num_elements) |
1348 | { |
1349 | case 1: |
1350 | decoded->orig_option_with_args_text = decoded->canonical_option[0]; |
1351 | break; |
1352 | |
1353 | case 2: |
1354 | decoded->orig_option_with_args_text |
1355 | = opts_concat (first: decoded->canonical_option[0], " " , |
1356 | decoded->canonical_option[1], NULL); |
1357 | break; |
1358 | |
1359 | default: |
1360 | gcc_unreachable (); |
1361 | } |
1362 | } |
1363 | |
1364 | /* Fill in *DECODED with an option for input file FILE. */ |
1365 | |
1366 | void |
1367 | generate_option_input_file (const char *file, |
1368 | struct cl_decoded_option *decoded) |
1369 | { |
1370 | decoded->opt_index = OPT_SPECIAL_input_file; |
1371 | decoded->warn_message = NULL; |
1372 | decoded->arg = file; |
1373 | decoded->orig_option_with_args_text = file; |
1374 | decoded->canonical_option_num_elements = 1; |
1375 | decoded->canonical_option[0] = file; |
1376 | decoded->canonical_option[1] = NULL; |
1377 | decoded->canonical_option[2] = NULL; |
1378 | decoded->canonical_option[3] = NULL; |
1379 | decoded->value = 1; |
1380 | decoded->mask = 0; |
1381 | decoded->errors = 0; |
1382 | } |
1383 | |
1384 | /* Helper function for listing valid choices and hint for misspelled |
1385 | value. CANDIDATES is a vector containing all valid strings, |
1386 | STR is set to a heap allocated string that contains all those |
1387 | strings concatenated, separated by spaces, and the return value |
1388 | is the closest string from those to ARG, or NULL if nothing is |
1389 | close enough. Callers should XDELETEVEC (STR) after using it |
1390 | to avoid memory leaks. */ |
1391 | |
1392 | const char * |
1393 | candidates_list_and_hint (const char *arg, char *&str, |
1394 | const auto_vec <const char *> &candidates) |
1395 | { |
1396 | size_t len = 0; |
1397 | int i; |
1398 | const char *candidate; |
1399 | char *p; |
1400 | |
1401 | gcc_assert (!candidates.is_empty ()); |
1402 | |
1403 | FOR_EACH_VEC_ELT (candidates, i, candidate) |
1404 | len += strlen (s: candidate) + 1; |
1405 | |
1406 | str = p = XNEWVEC (char, len); |
1407 | FOR_EACH_VEC_ELT (candidates, i, candidate) |
1408 | { |
1409 | len = strlen (s: candidate); |
1410 | memcpy (dest: p, src: candidate, n: len); |
1411 | p[len] = ' '; |
1412 | p += len + 1; |
1413 | } |
1414 | p[-1] = '\0'; |
1415 | return find_closest_string (target: arg, candidates: &candidates); |
1416 | } |
1417 | |
1418 | /* Perform diagnostics for read_cmdline_option and control_warning_option |
1419 | functions. Returns true if an error has been diagnosed. |
1420 | LOC and LANG_MASK arguments like in read_cmdline_option. |
1421 | OPTION is the option to report diagnostics for, OPT the name |
1422 | of the option as text, ARG the argument of the option (for joined |
1423 | options), ERRORS is bitmask of CL_ERR_* values. */ |
1424 | |
1425 | static bool |
1426 | cmdline_handle_error (location_t loc, const struct cl_option *option, |
1427 | const char *opt, const char *arg, int errors, |
1428 | unsigned int lang_mask) |
1429 | { |
1430 | if (errors & CL_ERR_DISABLED) |
1431 | { |
1432 | error_at (loc, "command-line option %qs" |
1433 | " is not supported by this configuration" , opt); |
1434 | return true; |
1435 | } |
1436 | |
1437 | if (errors & CL_ERR_MISSING_ARG) |
1438 | { |
1439 | if (option->missing_argument_error) |
1440 | error_at (loc, option->missing_argument_error, opt); |
1441 | else |
1442 | error_at (loc, "missing argument to %qs" , opt); |
1443 | return true; |
1444 | } |
1445 | |
1446 | if (errors & CL_ERR_UINT_ARG) |
1447 | { |
1448 | if (option->cl_byte_size) |
1449 | error_at (loc, "argument to %qs should be a non-negative integer " |
1450 | "optionally followed by a size unit" , |
1451 | option->opt_text); |
1452 | else |
1453 | error_at (loc, "argument to %qs should be a non-negative integer" , |
1454 | option->opt_text); |
1455 | return true; |
1456 | } |
1457 | |
1458 | if (errors & CL_ERR_INT_RANGE_ARG) |
1459 | { |
1460 | error_at (loc, "argument to %qs is not between %d and %d" , |
1461 | option->opt_text, option->range_min, option->range_max); |
1462 | return true; |
1463 | } |
1464 | |
1465 | if (errors & CL_ERR_ENUM_SET_ARG) |
1466 | { |
1467 | const struct cl_enum *e = &cl_enums[option->var_enum]; |
1468 | const char *p = arg; |
1469 | unsigned HOST_WIDE_INT used_sets = 0; |
1470 | const char *second_opt = NULL; |
1471 | size_t second_opt_len = 0; |
1472 | errors = 0; |
1473 | do |
1474 | { |
1475 | const char *q = strchr (s: p, c: ','); |
1476 | HOST_WIDE_INT this_value = 0; |
1477 | if (q && q == p) |
1478 | { |
1479 | arg = "" ; |
1480 | errors = CL_ERR_ENUM_ARG; |
1481 | break; |
1482 | } |
1483 | int idx = enum_arg_to_value (enum_args: e->values, arg: p, len: q ? q - p : 0, |
1484 | value: &this_value, lang_mask); |
1485 | if (idx < 0) |
1486 | { |
1487 | if (q == NULL) |
1488 | q = strchr (s: p, c: '\0'); |
1489 | char *narg = XALLOCAVEC (char, (q - p) + 1); |
1490 | memcpy (dest: narg, src: p, n: q - p); |
1491 | narg[q - p] = '\0'; |
1492 | arg = narg; |
1493 | errors = CL_ERR_ENUM_ARG; |
1494 | break; |
1495 | } |
1496 | |
1497 | if (option->var_value == CLEV_BITSET) |
1498 | { |
1499 | if (q == NULL) |
1500 | break; |
1501 | p = q + 1; |
1502 | continue; |
1503 | } |
1504 | |
1505 | unsigned set = e->values[idx].flags >> CL_ENUM_SET_SHIFT; |
1506 | gcc_checking_assert (set >= 1 && set <= HOST_BITS_PER_WIDE_INT); |
1507 | if ((used_sets & (HOST_WIDE_INT_1U << (set - 1))) != 0) |
1508 | { |
1509 | if (q == NULL) |
1510 | q = strchr (s: p, c: '\0'); |
1511 | if (second_opt == NULL) |
1512 | { |
1513 | used_sets = HOST_WIDE_INT_1U << (set - 1); |
1514 | second_opt = p; |
1515 | second_opt_len = q - p; |
1516 | p = arg; |
1517 | continue; |
1518 | } |
1519 | char *args = XALLOCAVEC (char, (q - p) + 1 + second_opt_len + 1); |
1520 | memcpy (dest: args, src: p, n: q - p); |
1521 | args[q - p] = '\0'; |
1522 | memcpy (dest: args + (q - p) + 1, src: second_opt, n: second_opt_len); |
1523 | args[(q - p) + 1 + second_opt_len] = '\0'; |
1524 | error_at (loc, "invalid argument in option %qs" , opt); |
1525 | if (strcmp (s1: args, s2: args + (q - p) + 1) == 0) |
1526 | inform (loc, "%qs specified multiple times in the same option" , |
1527 | args); |
1528 | else |
1529 | inform (loc, "%qs is mutually exclusive with %qs and cannot be" |
1530 | " specified together" , args, args + (q - p) + 1); |
1531 | return true; |
1532 | } |
1533 | used_sets |= HOST_WIDE_INT_1U << (set - 1); |
1534 | if (q == NULL) |
1535 | break; |
1536 | p = q + 1; |
1537 | } |
1538 | while (1); |
1539 | } |
1540 | |
1541 | if (errors & CL_ERR_ENUM_ARG) |
1542 | { |
1543 | const struct cl_enum *e = &cl_enums[option->var_enum]; |
1544 | unsigned int i; |
1545 | char *s; |
1546 | |
1547 | auto_diagnostic_group d; |
1548 | if (e->unknown_error) |
1549 | error_at (loc, e->unknown_error, arg); |
1550 | else |
1551 | error_at (loc, "unrecognized argument in option %qs" , opt); |
1552 | |
1553 | auto_vec <const char *> candidates; |
1554 | for (i = 0; e->values[i].arg != NULL; i++) |
1555 | { |
1556 | if (!enum_arg_ok_for_language (enum_arg: &e->values[i], lang_mask)) |
1557 | continue; |
1558 | candidates.safe_push (obj: e->values[i].arg); |
1559 | } |
1560 | const char *hint = candidates_list_and_hint (arg, str&: s, candidates); |
1561 | if (hint) |
1562 | inform (loc, "valid arguments to %qs are: %s; did you mean %qs?" , |
1563 | option->opt_text, s, hint); |
1564 | else |
1565 | inform (loc, "valid arguments to %qs are: %s" , option->opt_text, s); |
1566 | XDELETEVEC (s); |
1567 | |
1568 | return true; |
1569 | } |
1570 | |
1571 | return false; |
1572 | } |
1573 | |
1574 | /* Handle the switch DECODED (location LOC) for the language indicated |
1575 | by LANG_MASK, using the handlers in *HANDLERS and setting fields in |
1576 | OPTS and OPTS_SET and using diagnostic context DC (if not NULL) for |
1577 | diagnostic options. */ |
1578 | |
1579 | void |
1580 | read_cmdline_option (struct gcc_options *opts, |
1581 | struct gcc_options *opts_set, |
1582 | struct cl_decoded_option *decoded, |
1583 | location_t loc, |
1584 | unsigned int lang_mask, |
1585 | const struct cl_option_handlers *handlers, |
1586 | diagnostic_context *dc) |
1587 | { |
1588 | const struct cl_option *option; |
1589 | const char *opt = decoded->orig_option_with_args_text; |
1590 | |
1591 | if (decoded->warn_message) |
1592 | warning_at (loc, 0, decoded->warn_message, opt); |
1593 | |
1594 | if (decoded->opt_index == OPT_SPECIAL_unknown) |
1595 | { |
1596 | if (handlers->unknown_option_callback (decoded)) |
1597 | error_at (loc, "unrecognized command-line option %qs" , decoded->arg); |
1598 | return; |
1599 | } |
1600 | |
1601 | if (decoded->opt_index == OPT_SPECIAL_ignore) |
1602 | return; |
1603 | |
1604 | if (decoded->opt_index == OPT_SPECIAL_warn_removed) |
1605 | { |
1606 | /* Warn only about positive ignored options. */ |
1607 | if (decoded->value) |
1608 | warning_at (loc, 0, "switch %qs is no longer supported" , opt); |
1609 | return; |
1610 | } |
1611 | |
1612 | option = &cl_options[decoded->opt_index]; |
1613 | |
1614 | if (decoded->errors |
1615 | && cmdline_handle_error (loc, option, opt, arg: decoded->arg, |
1616 | errors: decoded->errors, lang_mask)) |
1617 | return; |
1618 | |
1619 | if (decoded->errors & CL_ERR_WRONG_LANG) |
1620 | { |
1621 | handlers->wrong_lang_callback (decoded, lang_mask); |
1622 | return; |
1623 | } |
1624 | |
1625 | gcc_assert (!decoded->errors); |
1626 | |
1627 | if (!handle_option (opts, opts_set, decoded, lang_mask, kind: DK_UNSPECIFIED, |
1628 | loc, handlers, generated_p: false, dc)) |
1629 | error_at (loc, "unrecognized command-line option %qs" , opt); |
1630 | } |
1631 | |
1632 | /* Set any field in OPTS, and OPTS_SET if not NULL, for option |
1633 | OPT_INDEX according to VALUE and ARG, diagnostic kind KIND, |
1634 | location LOC, using diagnostic context DC if not NULL for |
1635 | diagnostic classification. */ |
1636 | |
1637 | void |
1638 | set_option (struct gcc_options *opts, struct gcc_options *opts_set, |
1639 | int opt_index, HOST_WIDE_INT value, const char *arg, int kind, |
1640 | location_t loc, diagnostic_context *dc, |
1641 | HOST_WIDE_INT mask /* = 0 */) |
1642 | { |
1643 | const struct cl_option *option = &cl_options[opt_index]; |
1644 | void *flag_var = option_flag_var (opt_index, opts); |
1645 | void *set_flag_var = NULL; |
1646 | |
1647 | if (!flag_var) |
1648 | return; |
1649 | |
1650 | if ((diagnostic_t) kind != DK_UNSPECIFIED && dc != NULL) |
1651 | diagnostic_classify_diagnostic (context: dc, optidx: opt_index, kind: (diagnostic_t) kind, where: loc); |
1652 | |
1653 | if (opts_set != NULL) |
1654 | set_flag_var = option_flag_var (opt_index, opts: opts_set); |
1655 | |
1656 | switch (option->var_type) |
1657 | { |
1658 | case CLVC_INTEGER: |
1659 | if (option->cl_host_wide_int) |
1660 | { |
1661 | *(HOST_WIDE_INT *) flag_var = value; |
1662 | if (set_flag_var) |
1663 | *(HOST_WIDE_INT *) set_flag_var = 1; |
1664 | } |
1665 | else |
1666 | { |
1667 | if (value > INT_MAX) |
1668 | error_at (loc, "argument to %qs is bigger than %d" , |
1669 | option->opt_text, INT_MAX); |
1670 | else |
1671 | { |
1672 | *(int *) flag_var = value; |
1673 | if (set_flag_var) |
1674 | *(int *) set_flag_var = 1; |
1675 | } |
1676 | } |
1677 | |
1678 | break; |
1679 | |
1680 | case CLVC_SIZE: |
1681 | if (option->cl_host_wide_int) |
1682 | { |
1683 | *(HOST_WIDE_INT *) flag_var = value; |
1684 | if (set_flag_var) |
1685 | *(HOST_WIDE_INT *) set_flag_var = value; |
1686 | } |
1687 | else |
1688 | { |
1689 | *(int *) flag_var = value; |
1690 | if (set_flag_var) |
1691 | *(int *) set_flag_var = value; |
1692 | } |
1693 | |
1694 | break; |
1695 | |
1696 | case CLVC_EQUAL: |
1697 | if (option->cl_host_wide_int) |
1698 | { |
1699 | *(HOST_WIDE_INT *) flag_var = (value |
1700 | ? option->var_value |
1701 | : !option->var_value); |
1702 | if (set_flag_var) |
1703 | *(HOST_WIDE_INT *) set_flag_var = 1; |
1704 | } |
1705 | else |
1706 | { |
1707 | *(int *) flag_var = (value |
1708 | ? option->var_value |
1709 | : !option->var_value); |
1710 | if (set_flag_var) |
1711 | *(int *) set_flag_var = 1; |
1712 | } |
1713 | break; |
1714 | |
1715 | case CLVC_BIT_CLEAR: |
1716 | case CLVC_BIT_SET: |
1717 | if ((value != 0) == (option->var_type == CLVC_BIT_SET)) |
1718 | { |
1719 | if (option->cl_host_wide_int) |
1720 | *(HOST_WIDE_INT *) flag_var |= option->var_value; |
1721 | else |
1722 | *(int *) flag_var |= option->var_value; |
1723 | } |
1724 | else |
1725 | { |
1726 | if (option->cl_host_wide_int) |
1727 | *(HOST_WIDE_INT *) flag_var &= ~option->var_value; |
1728 | else |
1729 | *(int *) flag_var &= ~option->var_value; |
1730 | } |
1731 | if (set_flag_var) |
1732 | { |
1733 | if (option->cl_host_wide_int) |
1734 | *(HOST_WIDE_INT *) set_flag_var |= option->var_value; |
1735 | else |
1736 | *(int *) set_flag_var |= option->var_value; |
1737 | } |
1738 | break; |
1739 | |
1740 | case CLVC_STRING: |
1741 | *(const char **) flag_var = arg; |
1742 | if (set_flag_var) |
1743 | *(const char **) set_flag_var = "" ; |
1744 | break; |
1745 | |
1746 | case CLVC_ENUM: |
1747 | { |
1748 | const struct cl_enum *e = &cl_enums[option->var_enum]; |
1749 | |
1750 | if (mask) |
1751 | e->set (flag_var, value | (e->get (flag_var) & ~mask)); |
1752 | else |
1753 | e->set (flag_var, value); |
1754 | if (set_flag_var) |
1755 | e->set (set_flag_var, 1); |
1756 | } |
1757 | break; |
1758 | |
1759 | case CLVC_DEFER: |
1760 | { |
1761 | vec<cl_deferred_option> *v |
1762 | = (vec<cl_deferred_option> *) *(void **) flag_var; |
1763 | cl_deferred_option p = {.opt_index: opt_index, .arg: arg, .value: value}; |
1764 | if (!v) |
1765 | v = XCNEW (vec<cl_deferred_option>); |
1766 | v->safe_push (obj: p); |
1767 | *(void **) flag_var = v; |
1768 | if (set_flag_var) |
1769 | *(void **) set_flag_var = v; |
1770 | } |
1771 | break; |
1772 | } |
1773 | } |
1774 | |
1775 | /* Return the address of the flag variable for option OPT_INDEX in |
1776 | options structure OPTS, or NULL if there is no flag variable. */ |
1777 | |
1778 | void * |
1779 | option_flag_var (int opt_index, struct gcc_options *opts) |
1780 | { |
1781 | const struct cl_option *option = &cl_options[opt_index]; |
1782 | |
1783 | if (option->flag_var_offset == (unsigned short) -1) |
1784 | return NULL; |
1785 | return (void *)(((char *) opts) + option->flag_var_offset); |
1786 | } |
1787 | |
1788 | /* Return 1 if option OPT_IDX is enabled in OPTS, 0 if it is disabled, |
1789 | or -1 if it isn't a simple on-off switch |
1790 | (or if the value is unknown, typically set later in target). */ |
1791 | |
1792 | int |
1793 | option_enabled (int opt_idx, unsigned lang_mask, void *opts) |
1794 | { |
1795 | const struct cl_option *option = &(cl_options[opt_idx]); |
1796 | |
1797 | /* A language-specific option can only be considered enabled when it's |
1798 | valid for the current language. */ |
1799 | if (!(option->flags & CL_COMMON) |
1800 | && (option->flags & CL_LANG_ALL) |
1801 | && !(option->flags & lang_mask)) |
1802 | return 0; |
1803 | |
1804 | struct gcc_options *optsg = (struct gcc_options *) opts; |
1805 | void *flag_var = option_flag_var (opt_index: opt_idx, opts: optsg); |
1806 | |
1807 | if (flag_var) |
1808 | switch (option->var_type) |
1809 | { |
1810 | case CLVC_INTEGER: |
1811 | if (option->cl_host_wide_int) |
1812 | { |
1813 | HOST_WIDE_INT v = *(HOST_WIDE_INT *) flag_var; |
1814 | return v != 0 ? (v < 0 ? -1 : 1) : 0; |
1815 | } |
1816 | else |
1817 | { |
1818 | int v = *(int *) flag_var; |
1819 | return v != 0 ? (v < 0 ? -1 : 1) : 0; |
1820 | } |
1821 | |
1822 | case CLVC_EQUAL: |
1823 | if (option->cl_host_wide_int) |
1824 | return *(HOST_WIDE_INT *) flag_var == option->var_value; |
1825 | else |
1826 | return *(int *) flag_var == option->var_value; |
1827 | |
1828 | case CLVC_BIT_CLEAR: |
1829 | if (option->cl_host_wide_int) |
1830 | return (*(HOST_WIDE_INT *) flag_var & option->var_value) == 0; |
1831 | else |
1832 | return (*(int *) flag_var & option->var_value) == 0; |
1833 | |
1834 | case CLVC_BIT_SET: |
1835 | if (option->cl_host_wide_int) |
1836 | return (*(HOST_WIDE_INT *) flag_var & option->var_value) != 0; |
1837 | else |
1838 | return (*(int *) flag_var & option->var_value) != 0; |
1839 | |
1840 | case CLVC_SIZE: |
1841 | if (option->cl_host_wide_int) |
1842 | return *(HOST_WIDE_INT *) flag_var != -1; |
1843 | else |
1844 | return *(int *) flag_var != -1; |
1845 | |
1846 | case CLVC_STRING: |
1847 | case CLVC_ENUM: |
1848 | case CLVC_DEFER: |
1849 | break; |
1850 | } |
1851 | return -1; |
1852 | } |
1853 | |
1854 | /* Fill STATE with the current state of option OPTION in OPTS. Return |
1855 | true if there is some state to store. */ |
1856 | |
1857 | bool |
1858 | get_option_state (struct gcc_options *opts, int option, |
1859 | struct cl_option_state *state) |
1860 | { |
1861 | void *flag_var = option_flag_var (opt_index: option, opts); |
1862 | |
1863 | if (flag_var == 0) |
1864 | return false; |
1865 | |
1866 | switch (cl_options[option].var_type) |
1867 | { |
1868 | case CLVC_INTEGER: |
1869 | case CLVC_EQUAL: |
1870 | case CLVC_SIZE: |
1871 | state->data = flag_var; |
1872 | state->size = (cl_options[option].cl_host_wide_int |
1873 | ? sizeof (HOST_WIDE_INT) |
1874 | : sizeof (int)); |
1875 | break; |
1876 | |
1877 | case CLVC_BIT_CLEAR: |
1878 | case CLVC_BIT_SET: |
1879 | state->ch = option_enabled (opt_idx: option, lang_mask: -1, opts); |
1880 | state->data = &state->ch; |
1881 | state->size = 1; |
1882 | break; |
1883 | |
1884 | case CLVC_STRING: |
1885 | state->data = *(const char **) flag_var; |
1886 | if (state->data == 0) |
1887 | state->data = "" ; |
1888 | state->size = strlen (s: (const char *) state->data) + 1; |
1889 | break; |
1890 | |
1891 | case CLVC_ENUM: |
1892 | state->data = flag_var; |
1893 | state->size = cl_enums[cl_options[option].var_enum].var_size; |
1894 | break; |
1895 | |
1896 | case CLVC_DEFER: |
1897 | return false; |
1898 | } |
1899 | return true; |
1900 | } |
1901 | |
1902 | /* Set a warning option OPT_INDEX (language mask LANG_MASK, option |
1903 | handlers HANDLERS) to have diagnostic kind KIND for option |
1904 | structures OPTS and OPTS_SET and diagnostic context DC (possibly |
1905 | NULL), at location LOC (UNKNOWN_LOCATION for -Werror=). ARG is the |
1906 | argument of the option for joined options, or NULL otherwise. If IMPLY, |
1907 | the warning option in question is implied at this point. This is |
1908 | used by -Werror= and #pragma GCC diagnostic. */ |
1909 | |
1910 | void |
1911 | control_warning_option (unsigned int opt_index, int kind, const char *arg, |
1912 | bool imply, location_t loc, unsigned int lang_mask, |
1913 | const struct cl_option_handlers *handlers, |
1914 | struct gcc_options *opts, |
1915 | struct gcc_options *opts_set, |
1916 | diagnostic_context *dc) |
1917 | { |
1918 | if (cl_options[opt_index].alias_target != N_OPTS) |
1919 | { |
1920 | gcc_assert (!cl_options[opt_index].cl_separate_alias |
1921 | && !cl_options[opt_index].cl_negative_alias); |
1922 | if (cl_options[opt_index].alias_arg) |
1923 | arg = cl_options[opt_index].alias_arg; |
1924 | opt_index = cl_options[opt_index].alias_target; |
1925 | } |
1926 | if (opt_index == OPT_SPECIAL_ignore || opt_index == OPT_SPECIAL_warn_removed) |
1927 | return; |
1928 | if (dc) |
1929 | diagnostic_classify_diagnostic (context: dc, optidx: opt_index, kind: (diagnostic_t) kind, where: loc); |
1930 | if (imply) |
1931 | { |
1932 | /* -Werror=foo implies -Wfoo. */ |
1933 | const struct cl_option *option = &cl_options[opt_index]; |
1934 | HOST_WIDE_INT value = 1; |
1935 | |
1936 | if (option->var_type == CLVC_INTEGER |
1937 | || option->var_type == CLVC_ENUM |
1938 | || option->var_type == CLVC_SIZE) |
1939 | { |
1940 | |
1941 | if (arg && *arg == '\0' && !option->cl_missing_ok) |
1942 | arg = NULL; |
1943 | |
1944 | if ((option->flags & CL_JOINED) && arg == NULL) |
1945 | { |
1946 | cmdline_handle_error (loc, option, opt: option->opt_text, arg, |
1947 | CL_ERR_MISSING_ARG, lang_mask); |
1948 | return; |
1949 | } |
1950 | |
1951 | /* If the switch takes an integer argument, convert it. */ |
1952 | if (arg && (option->cl_uinteger || option->cl_host_wide_int)) |
1953 | { |
1954 | int error = 0; |
1955 | value = *arg ? integral_argument (arg, err: &error, |
1956 | byte_size_suffix: option->cl_byte_size) : 0; |
1957 | if (error) |
1958 | { |
1959 | cmdline_handle_error (loc, option, opt: option->opt_text, arg, |
1960 | CL_ERR_UINT_ARG, lang_mask); |
1961 | return; |
1962 | } |
1963 | } |
1964 | |
1965 | /* If the switch takes an enumerated argument, convert it. */ |
1966 | if (arg && option->var_type == CLVC_ENUM) |
1967 | { |
1968 | const struct cl_enum *e = &cl_enums[option->var_enum]; |
1969 | |
1970 | if (enum_arg_to_value (enum_args: e->values, arg, len: 0, value: &value, |
1971 | lang_mask) >= 0) |
1972 | { |
1973 | const char *carg = NULL; |
1974 | |
1975 | if (enum_value_to_arg (enum_args: e->values, argp: &carg, value, lang_mask)) |
1976 | arg = carg; |
1977 | gcc_assert (carg != NULL); |
1978 | } |
1979 | else |
1980 | { |
1981 | cmdline_handle_error (loc, option, opt: option->opt_text, arg, |
1982 | CL_ERR_ENUM_ARG, lang_mask); |
1983 | return; |
1984 | } |
1985 | } |
1986 | } |
1987 | |
1988 | handle_generated_option (opts, opts_set, |
1989 | opt_index, arg, value, lang_mask, |
1990 | kind, loc, handlers, generated_p: false, dc); |
1991 | } |
1992 | } |
1993 | |
1994 | /* Parse options in COLLECT_GCC_OPTIONS and push them on ARGV_OBSTACK. |
1995 | Store number of arguments into ARGC_P. */ |
1996 | |
1997 | void |
1998 | parse_options_from_collect_gcc_options (const char *collect_gcc_options, |
1999 | obstack *argv_obstack, |
2000 | int *argc_p) |
2001 | { |
2002 | char *argv_storage = xstrdup (collect_gcc_options); |
2003 | int j, k; |
2004 | |
2005 | for (j = 0, k = 0; argv_storage[j] != '\0'; ++j) |
2006 | { |
2007 | if (argv_storage[j] == '\'') |
2008 | { |
2009 | obstack_ptr_grow (argv_obstack, &argv_storage[k]); |
2010 | ++j; |
2011 | do |
2012 | { |
2013 | if (argv_storage[j] == '\0') |
2014 | fatal_error (input_location, |
2015 | "malformed %<COLLECT_GCC_OPTIONS%>" ); |
2016 | else if (startswith (str: &argv_storage[j], prefix: "'\\''" )) |
2017 | { |
2018 | argv_storage[k++] = '\''; |
2019 | j += 4; |
2020 | } |
2021 | else if (argv_storage[j] == '\'') |
2022 | break; |
2023 | else |
2024 | argv_storage[k++] = argv_storage[j++]; |
2025 | } |
2026 | while (1); |
2027 | argv_storage[k++] = '\0'; |
2028 | } |
2029 | } |
2030 | |
2031 | obstack_ptr_grow (argv_obstack, NULL); |
2032 | *argc_p = obstack_object_size (argv_obstack) / sizeof (void *) - 1; |
2033 | } |
2034 | |
2035 | /* Prepend -Xassembler for each option in COLLECT_AS_OPTIONS, |
2036 | and push on O. */ |
2037 | |
2038 | void prepend_xassembler_to_collect_as_options (const char *collect_as_options, |
2039 | obstack *o) |
2040 | { |
2041 | obstack opts_obstack; |
2042 | int opts_count; |
2043 | |
2044 | obstack_init (&opts_obstack); |
2045 | parse_options_from_collect_gcc_options (collect_gcc_options: collect_as_options, |
2046 | argv_obstack: &opts_obstack, argc_p: &opts_count); |
2047 | const char **assembler_opts = XOBFINISH (&opts_obstack, const char **); |
2048 | |
2049 | for (int i = 0; i < opts_count; i++) |
2050 | { |
2051 | obstack_grow (o, " '-Xassembler' " , |
2052 | strlen (" '-Xassembler' " )); |
2053 | const char *opt = assembler_opts[i]; |
2054 | obstack_1grow (o, '\''); |
2055 | obstack_grow (o, opt, strlen (opt)); |
2056 | obstack_1grow (o, '\''); |
2057 | } |
2058 | } |
2059 | |
2060 | jobserver_info::jobserver_info () |
2061 | { |
2062 | /* Traditionally, GNU make uses opened pipes for jobserver-auth, |
2063 | e.g. --jobserver-auth=3,4. |
2064 | Starting with GNU make 4.4, one can use --jobserver-style=fifo |
2065 | and then named pipe is used: --jobserver-auth=fifo:/tmp/hcsparta. */ |
2066 | |
2067 | /* Detect jobserver and drop it if it's not working. */ |
2068 | string js_needle = "--jobserver-auth=" ; |
2069 | string fifo_prefix = "fifo:" ; |
2070 | |
2071 | const char *envval = getenv (name: "MAKEFLAGS" ); |
2072 | if (envval != NULL) |
2073 | { |
2074 | string makeflags = envval; |
2075 | size_t n = makeflags.rfind (str: js_needle); |
2076 | if (n != string::npos) |
2077 | { |
2078 | string ending = makeflags.substr (pos: n + js_needle.size ()); |
2079 | if (ending.find (str: fifo_prefix) == 0) |
2080 | { |
2081 | ending = ending.substr (pos: fifo_prefix.size ()); |
2082 | pipe_path = ending.substr (pos: 0, n: ending.find (c: ' ')); |
2083 | is_active = true; |
2084 | } |
2085 | else if (sscanf (s: makeflags.c_str () + n + js_needle.size (), |
2086 | format: "%d,%d" , &rfd, &wfd) == 2 |
2087 | && rfd > 0 |
2088 | && wfd > 0 |
2089 | && is_valid_fd (fd: rfd) |
2090 | && is_valid_fd (fd: wfd)) |
2091 | is_active = true; |
2092 | else |
2093 | { |
2094 | string dup = makeflags.substr (pos: 0, n: n); |
2095 | size_t pos = makeflags.find (c: ' ', pos: n); |
2096 | if (pos != string::npos) |
2097 | dup += makeflags.substr (pos: pos); |
2098 | skipped_makeflags = "MAKEFLAGS=" + dup; |
2099 | error_msg |
2100 | = "cannot access %<" + js_needle + "%> file descriptors" ; |
2101 | } |
2102 | } |
2103 | error_msg = "%<" + js_needle + "%> is not present in %<MAKEFLAGS%>" ; |
2104 | } |
2105 | else |
2106 | error_msg = "%<MAKEFLAGS%> environment variable is unset" ; |
2107 | |
2108 | if (!error_msg.empty ()) |
2109 | error_msg = "jobserver is not available: " + error_msg; |
2110 | } |
2111 | |
2112 | void |
2113 | jobserver_info::connect () |
2114 | { |
2115 | if (!pipe_path.empty ()) |
2116 | { |
2117 | #if HOST_HAS_O_NONBLOCK |
2118 | pipefd = open (file: pipe_path.c_str (), O_RDWR | O_NONBLOCK); |
2119 | is_connected = true; |
2120 | #else |
2121 | is_connected = false; |
2122 | #endif |
2123 | } |
2124 | else |
2125 | is_connected = true; |
2126 | } |
2127 | |
2128 | void |
2129 | jobserver_info::disconnect () |
2130 | { |
2131 | if (!pipe_path.empty ()) |
2132 | { |
2133 | gcc_assert (close (pipefd) == 0); |
2134 | pipefd = -1; |
2135 | } |
2136 | } |
2137 | |
2138 | bool |
2139 | jobserver_info::get_token () |
2140 | { |
2141 | int fd = pipe_path.empty () ? rfd : pipefd; |
2142 | char c; |
2143 | unsigned n = read (fd: fd, buf: &c, nbytes: 1); |
2144 | if (n != 1) |
2145 | { |
2146 | gcc_assert (errno == EAGAIN); |
2147 | return false; |
2148 | } |
2149 | else |
2150 | return true; |
2151 | } |
2152 | |
2153 | void |
2154 | jobserver_info::return_token () |
2155 | { |
2156 | int fd = pipe_path.empty () ? wfd : pipefd; |
2157 | char c = 'G'; |
2158 | gcc_assert (write (fd, &c, 1) == 1); |
2159 | } |
2160 | |