1 | /* Command line option handling. |
2 | Copyright (C) 2006-2023 Free Software Foundation, Inc. |
3 | |
4 | This file is part of GCC. |
5 | |
6 | GCC is free software; you can redistribute it and/or modify it under |
7 | the terms of the GNU General Public License as published by the Free |
8 | Software Foundation; either version 3, or (at your option) any later |
9 | version. |
10 | |
11 | GCC is distributed in the hope that it will be useful, but WITHOUT ANY |
12 | WARRANTY; without even the implied warranty of MERCHANTABILITY or |
13 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
14 | for more details. |
15 | |
16 | You should have received a copy of the GNU General Public License |
17 | along with GCC; see the file COPYING3. If not see |
18 | <http://www.gnu.org/licenses/>. */ |
19 | |
20 | #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 | /* Helper function for gcc.cc's driver::suggest_option, for populating the |
472 | vec of suggestions for misspelled options. |
473 | |
474 | option_map above provides various prefixes for spelling command-line |
475 | options, which decode_cmdline_option uses to map spellings of options |
476 | to specific options. We want to do the reverse: to find all the ways |
477 | that a user could validly spell an option. |
478 | |
479 | Given valid OPT_TEXT (with a leading dash) for OPTION, add it and all |
480 | of its valid variant spellings to CANDIDATES, each without a leading |
481 | dash. |
482 | |
483 | For example, given "-Wabi-tag", the following are added to CANDIDATES: |
484 | "Wabi-tag" |
485 | "Wno-abi-tag" |
486 | "-warn-abi-tag" |
487 | "-warn-no-abi-tag". |
488 | |
489 | The added strings must be freed using free. */ |
490 | |
491 | void |
492 | add_misspelling_candidates (auto_vec<char *> *candidates, |
493 | const struct cl_option *option, |
494 | const char *opt_text) |
495 | { |
496 | gcc_assert (candidates); |
497 | gcc_assert (option); |
498 | gcc_assert (opt_text); |
499 | if (remapping_prefix_p (opt: option)) |
500 | return; |
501 | candidates->safe_push (obj: xstrdup (opt_text + 1)); |
502 | for (unsigned i = 0; i < ARRAY_SIZE (option_map); i++) |
503 | { |
504 | const char *opt0 = option_map[i].opt0; |
505 | const char *new_prefix = option_map[i].new_prefix; |
506 | size_t new_prefix_len = strlen (s: new_prefix); |
507 | |
508 | if (option->cl_reject_negative && option_map[i].negated) |
509 | continue; |
510 | |
511 | if (strncmp (s1: opt_text, s2: new_prefix, n: new_prefix_len) == 0) |
512 | { |
513 | char *alternative = concat (opt0 + 1, opt_text + new_prefix_len, |
514 | NULL); |
515 | candidates->safe_push (obj: alternative); |
516 | } |
517 | } |
518 | |
519 | /* For all params (e.g. --param=key=value), |
520 | include also '--param key=value'. */ |
521 | const char *prefix = "--param=" ; |
522 | if (strstr (haystack: opt_text, needle: prefix) == opt_text) |
523 | { |
524 | char *param = xstrdup (opt_text + 1); |
525 | gcc_assert (param[6] == '='); |
526 | param[6] = ' '; |
527 | candidates->safe_push (obj: param); |
528 | } |
529 | } |
530 | |
531 | /* Decode the switch beginning at ARGV for the language indicated by |
532 | LANG_MASK (including CL_COMMON and CL_TARGET if applicable), into |
533 | the structure *DECODED. Returns the number of switches |
534 | consumed. */ |
535 | |
536 | static unsigned int |
537 | decode_cmdline_option (const char *const *argv, unsigned int lang_mask, |
538 | struct cl_decoded_option *decoded) |
539 | { |
540 | size_t opt_index; |
541 | const char *arg = 0; |
542 | HOST_WIDE_INT value = 1, mask = 0; |
543 | unsigned int result = 1, i, , separate_args = 0; |
544 | int adjust_len = 0; |
545 | size_t total_len; |
546 | char *p; |
547 | const struct cl_option *option; |
548 | int errors = 0; |
549 | const char *warn_message = NULL; |
550 | bool separate_arg_flag; |
551 | bool joined_arg_flag; |
552 | bool have_separate_arg = false; |
553 | |
554 | extra_args = 0; |
555 | |
556 | const char *opt_value = argv[0] + 1; |
557 | opt_index = find_opt (input: opt_value, lang_mask); |
558 | i = 0; |
559 | while (opt_index == OPT_SPECIAL_unknown |
560 | && i < ARRAY_SIZE (option_map)) |
561 | { |
562 | const char *opt0 = option_map[i].opt0; |
563 | const char *opt1 = option_map[i].opt1; |
564 | const char *new_prefix = option_map[i].new_prefix; |
565 | bool another_char_needed = option_map[i].another_char_needed; |
566 | size_t opt0_len = strlen (s: opt0); |
567 | size_t opt1_len = (opt1 == NULL ? 0 : strlen (s: opt1)); |
568 | size_t optn_len = (opt1 == NULL ? opt0_len : opt1_len); |
569 | size_t new_prefix_len = strlen (s: new_prefix); |
570 | |
571 | extra_args = (opt1 == NULL ? 0 : 1); |
572 | value = !option_map[i].negated; |
573 | |
574 | if (strncmp (s1: argv[0], s2: opt0, n: opt0_len) == 0 |
575 | && (opt1 == NULL |
576 | || (argv[1] != NULL && strncmp (s1: argv[1], s2: opt1, n: opt1_len) == 0)) |
577 | && (!another_char_needed |
578 | || argv[extra_args][optn_len] != 0)) |
579 | { |
580 | size_t arglen = strlen (s: argv[extra_args]); |
581 | char *dup; |
582 | |
583 | adjust_len = (int) optn_len - (int) new_prefix_len; |
584 | dup = XNEWVEC (char, arglen + 1 - adjust_len); |
585 | memcpy (dest: dup, src: new_prefix, n: new_prefix_len); |
586 | memcpy (dest: dup + new_prefix_len, src: argv[extra_args] + optn_len, |
587 | n: arglen - optn_len + 1); |
588 | opt_index = find_opt (input: dup + 1, lang_mask); |
589 | free (ptr: dup); |
590 | } |
591 | i++; |
592 | } |
593 | |
594 | if (opt_index == OPT_SPECIAL_unknown) |
595 | { |
596 | arg = argv[0]; |
597 | extra_args = 0; |
598 | value = 1; |
599 | goto done; |
600 | } |
601 | |
602 | option = &cl_options[opt_index]; |
603 | |
604 | /* Reject negative form of switches that don't take negatives as |
605 | unrecognized. */ |
606 | if (!value && option->cl_reject_negative) |
607 | { |
608 | opt_index = OPT_SPECIAL_unknown; |
609 | errors |= CL_ERR_NEGATIVE; |
610 | arg = argv[0]; |
611 | goto done; |
612 | } |
613 | |
614 | /* Clear the initial value for size options (it will be overwritten |
615 | later based on the Init(value) specification in the opt file. */ |
616 | if (option->var_type == CLVC_SIZE) |
617 | value = 0; |
618 | |
619 | result = extra_args + 1; |
620 | warn_message = option->warn_message; |
621 | |
622 | /* Check to see if the option is disabled for this configuration. */ |
623 | if (option->cl_disabled) |
624 | errors |= CL_ERR_DISABLED; |
625 | |
626 | /* Determine whether there may be a separate argument based on |
627 | whether this option is being processed for the driver, and, if |
628 | so, how many such arguments. */ |
629 | separate_arg_flag = ((option->flags & CL_SEPARATE) |
630 | && !(option->cl_no_driver_arg |
631 | && (lang_mask & CL_DRIVER))); |
632 | separate_args = (separate_arg_flag |
633 | ? option->cl_separate_nargs + 1 |
634 | : 0); |
635 | joined_arg_flag = (option->flags & CL_JOINED) != 0; |
636 | |
637 | /* Sort out any argument the switch takes. */ |
638 | if (joined_arg_flag) |
639 | { |
640 | /* Have arg point to the original switch. This is because |
641 | some code, such as disable_builtin_function, expects its |
642 | argument to be persistent until the program exits. */ |
643 | arg = argv[extra_args] + cl_options[opt_index].opt_len + 1 + adjust_len; |
644 | |
645 | if (*arg == '\0' && !option->cl_missing_ok) |
646 | { |
647 | if (separate_arg_flag) |
648 | { |
649 | arg = argv[extra_args + 1]; |
650 | result = extra_args + 2; |
651 | if (arg == NULL) |
652 | result = extra_args + 1; |
653 | else |
654 | have_separate_arg = true; |
655 | } |
656 | else |
657 | /* Missing argument. */ |
658 | arg = NULL; |
659 | } |
660 | } |
661 | else if (separate_arg_flag) |
662 | { |
663 | arg = argv[extra_args + 1]; |
664 | for (i = 0; i < separate_args; i++) |
665 | if (argv[extra_args + 1 + i] == NULL) |
666 | { |
667 | errors |= CL_ERR_MISSING_ARG; |
668 | break; |
669 | } |
670 | result = extra_args + 1 + i; |
671 | if (arg != NULL) |
672 | have_separate_arg = true; |
673 | } |
674 | |
675 | if (arg == NULL && (separate_arg_flag || joined_arg_flag)) |
676 | errors |= CL_ERR_MISSING_ARG; |
677 | |
678 | /* Is this option an alias (or an ignored option, marked as an alias |
679 | of OPT_SPECIAL_ignore)? */ |
680 | if (option->alias_target != N_OPTS |
681 | && (!option->cl_separate_alias || have_separate_arg)) |
682 | { |
683 | size_t new_opt_index = option->alias_target; |
684 | |
685 | if (new_opt_index == OPT_SPECIAL_ignore |
686 | || new_opt_index == OPT_SPECIAL_warn_removed) |
687 | { |
688 | gcc_assert (option->alias_arg == NULL); |
689 | gcc_assert (option->neg_alias_arg == NULL); |
690 | opt_index = new_opt_index; |
691 | arg = NULL; |
692 | } |
693 | else |
694 | { |
695 | const struct cl_option *new_option = &cl_options[new_opt_index]; |
696 | |
697 | /* The new option must not be an alias itself. */ |
698 | gcc_assert (new_option->alias_target == N_OPTS |
699 | || new_option->cl_separate_alias); |
700 | |
701 | if (option->neg_alias_arg) |
702 | { |
703 | gcc_assert (option->alias_arg != NULL); |
704 | gcc_assert (arg == NULL); |
705 | gcc_assert (!option->cl_negative_alias); |
706 | if (value) |
707 | arg = option->alias_arg; |
708 | else |
709 | arg = option->neg_alias_arg; |
710 | value = 1; |
711 | } |
712 | else if (option->alias_arg) |
713 | { |
714 | gcc_assert (value == 1); |
715 | gcc_assert (arg == NULL); |
716 | gcc_assert (!option->cl_negative_alias); |
717 | arg = option->alias_arg; |
718 | } |
719 | |
720 | if (option->cl_negative_alias) |
721 | value = !value; |
722 | |
723 | opt_index = new_opt_index; |
724 | option = new_option; |
725 | |
726 | if (value == 0) |
727 | gcc_assert (!option->cl_reject_negative); |
728 | |
729 | /* Recompute what arguments are allowed. */ |
730 | separate_arg_flag = ((option->flags & CL_SEPARATE) |
731 | && !(option->cl_no_driver_arg |
732 | && (lang_mask & CL_DRIVER))); |
733 | joined_arg_flag = (option->flags & CL_JOINED) != 0; |
734 | |
735 | if (separate_args > 1 || option->cl_separate_nargs) |
736 | gcc_assert (separate_args |
737 | == (unsigned int) option->cl_separate_nargs + 1); |
738 | |
739 | if (!(errors & CL_ERR_MISSING_ARG)) |
740 | { |
741 | if (separate_arg_flag || joined_arg_flag) |
742 | { |
743 | if (option->cl_missing_ok && arg == NULL) |
744 | arg = "" ; |
745 | gcc_assert (arg != NULL); |
746 | } |
747 | else |
748 | gcc_assert (arg == NULL); |
749 | } |
750 | |
751 | /* Recheck for warnings and disabled options. */ |
752 | if (option->warn_message) |
753 | { |
754 | gcc_assert (warn_message == NULL); |
755 | warn_message = option->warn_message; |
756 | } |
757 | if (option->cl_disabled) |
758 | errors |= CL_ERR_DISABLED; |
759 | } |
760 | } |
761 | |
762 | /* Check if this is a switch for a different front end. */ |
763 | if (!option_ok_for_language (option, lang_mask)) |
764 | errors |= CL_ERR_WRONG_LANG; |
765 | else if (strcmp (s1: option->opt_text, s2: "-Werror=" ) == 0 |
766 | && strchr (s: opt_value, c: ',') == NULL) |
767 | { |
768 | /* Verify that -Werror argument is a valid warning |
769 | for a language. */ |
770 | char *werror_arg = xstrdup (opt_value + 6); |
771 | werror_arg[0] = 'W'; |
772 | |
773 | size_t warning_index = find_opt (input: werror_arg, lang_mask); |
774 | free (ptr: werror_arg); |
775 | if (warning_index != OPT_SPECIAL_unknown) |
776 | { |
777 | const struct cl_option *warning_option |
778 | = &cl_options[warning_index]; |
779 | if (!option_ok_for_language (option: warning_option, lang_mask)) |
780 | errors |= CL_ERR_WRONG_LANG; |
781 | } |
782 | } |
783 | |
784 | /* Convert the argument to lowercase if appropriate. */ |
785 | if (arg && option->cl_tolower) |
786 | { |
787 | size_t j; |
788 | size_t len = strlen (s: arg); |
789 | char *arg_lower = XOBNEWVEC (&opts_obstack, char, len + 1); |
790 | |
791 | for (j = 0; j < len; j++) |
792 | arg_lower[j] = TOLOWER ((unsigned char) arg[j]); |
793 | arg_lower[len] = 0; |
794 | arg = arg_lower; |
795 | } |
796 | |
797 | /* If the switch takes an integer argument, convert it. */ |
798 | if (arg && (option->cl_uinteger || option->cl_host_wide_int)) |
799 | { |
800 | int error = 0; |
801 | value = *arg ? integral_argument (arg, err: &error, byte_size_suffix: option->cl_byte_size) : 0; |
802 | if (error) |
803 | errors |= CL_ERR_UINT_ARG; |
804 | |
805 | /* Reject value out of a range. */ |
806 | if (option->range_max != -1 |
807 | && (value < option->range_min || value > option->range_max)) |
808 | errors |= CL_ERR_INT_RANGE_ARG; |
809 | } |
810 | |
811 | /* If the switch takes an enumerated argument, convert it. */ |
812 | if (arg && (option->var_type == CLVC_ENUM)) |
813 | { |
814 | const struct cl_enum *e = &cl_enums[option->var_enum]; |
815 | |
816 | gcc_assert (option->var_value != CLEV_NORMAL || value == 1); |
817 | if (option->var_value != CLEV_NORMAL) |
818 | { |
819 | const char *p = arg; |
820 | HOST_WIDE_INT sum_value = 0; |
821 | unsigned HOST_WIDE_INT used_sets = 0; |
822 | do |
823 | { |
824 | const char *q = strchr (s: p, c: ','); |
825 | HOST_WIDE_INT this_value = 0; |
826 | if (q && q == p) |
827 | { |
828 | errors |= CL_ERR_ENUM_SET_ARG; |
829 | break; |
830 | } |
831 | int idx = enum_arg_to_value (enum_args: e->values, arg: p, len: q ? q - p : 0, |
832 | value: &this_value, lang_mask); |
833 | if (idx < 0) |
834 | { |
835 | errors |= CL_ERR_ENUM_SET_ARG; |
836 | break; |
837 | } |
838 | |
839 | HOST_WIDE_INT this_mask = 0; |
840 | if (option->var_value == CLEV_SET) |
841 | { |
842 | unsigned set = e->values[idx].flags >> CL_ENUM_SET_SHIFT; |
843 | gcc_checking_assert (set >= 1 |
844 | && set <= HOST_BITS_PER_WIDE_INT); |
845 | if ((used_sets & (HOST_WIDE_INT_1U << (set - 1))) != 0) |
846 | { |
847 | errors |= CL_ERR_ENUM_SET_ARG; |
848 | break; |
849 | } |
850 | used_sets |= HOST_WIDE_INT_1U << (set - 1); |
851 | |
852 | for (int i = 0; e->values[i].arg != NULL; i++) |
853 | if (set == (e->values[i].flags >> CL_ENUM_SET_SHIFT)) |
854 | this_mask |= e->values[i].value; |
855 | } |
856 | else |
857 | { |
858 | gcc_assert (option->var_value == CLEV_BITSET |
859 | && ((e->values[idx].flags >> CL_ENUM_SET_SHIFT) |
860 | == 0)); |
861 | this_mask = this_value; |
862 | } |
863 | |
864 | sum_value |= this_value; |
865 | mask |= this_mask; |
866 | if (q == NULL) |
867 | break; |
868 | p = q + 1; |
869 | } |
870 | while (1); |
871 | if (value == 1) |
872 | value = sum_value; |
873 | else |
874 | gcc_checking_assert (value == 0); |
875 | } |
876 | else if (enum_arg_to_value (enum_args: e->values, arg, len: 0, value: &value, lang_mask) >= 0) |
877 | { |
878 | const char *carg = NULL; |
879 | |
880 | if (enum_value_to_arg (enum_args: e->values, argp: &carg, value, lang_mask)) |
881 | arg = carg; |
882 | gcc_assert (carg != NULL); |
883 | } |
884 | else |
885 | errors |= CL_ERR_ENUM_ARG; |
886 | } |
887 | |
888 | done: |
889 | decoded->opt_index = opt_index; |
890 | decoded->arg = arg; |
891 | decoded->value = value; |
892 | decoded->mask = mask; |
893 | decoded->errors = errors; |
894 | decoded->warn_message = warn_message; |
895 | |
896 | if (opt_index == OPT_SPECIAL_unknown) |
897 | gcc_assert (result == 1); |
898 | |
899 | gcc_assert (result >= 1 && result <= ARRAY_SIZE (decoded->canonical_option)); |
900 | decoded->canonical_option_num_elements = result; |
901 | total_len = 0; |
902 | for (i = 0; i < ARRAY_SIZE (decoded->canonical_option); i++) |
903 | { |
904 | if (i < result) |
905 | { |
906 | size_t len; |
907 | if (opt_index == OPT_SPECIAL_unknown) |
908 | decoded->canonical_option[i] = argv[i]; |
909 | else |
910 | decoded->canonical_option[i] = NULL; |
911 | len = strlen (s: argv[i]); |
912 | /* If the argument is an empty string, we will print it as "" in |
913 | orig_option_with_args_text. */ |
914 | total_len += (len != 0 ? len : 2) + 1; |
915 | } |
916 | else |
917 | decoded->canonical_option[i] = NULL; |
918 | } |
919 | if (opt_index != OPT_SPECIAL_unknown && opt_index != OPT_SPECIAL_ignore |
920 | && opt_index != OPT_SPECIAL_warn_removed) |
921 | { |
922 | generate_canonical_option (opt_index, arg, value, decoded); |
923 | if (separate_args > 1) |
924 | { |
925 | for (i = 0; i < separate_args; i++) |
926 | { |
927 | if (argv[extra_args + 1 + i] == NULL) |
928 | break; |
929 | else |
930 | decoded->canonical_option[1 + i] = argv[extra_args + 1 + i]; |
931 | } |
932 | gcc_assert (result == 1 + i); |
933 | decoded->canonical_option_num_elements = result; |
934 | } |
935 | } |
936 | decoded->orig_option_with_args_text |
937 | = p = XOBNEWVEC (&opts_obstack, char, total_len); |
938 | for (i = 0; i < result; i++) |
939 | { |
940 | size_t len = strlen (s: argv[i]); |
941 | |
942 | /* Print the empty string verbally. */ |
943 | if (len == 0) |
944 | { |
945 | *p++ = '"'; |
946 | *p++ = '"'; |
947 | } |
948 | else |
949 | memcpy (dest: p, src: argv[i], n: len); |
950 | p += len; |
951 | if (i == result - 1) |
952 | *p++ = 0; |
953 | else |
954 | *p++ = ' '; |
955 | } |
956 | |
957 | return result; |
958 | } |
959 | |
960 | /* Obstack for option strings. */ |
961 | |
962 | struct obstack opts_obstack; |
963 | |
964 | /* Like libiberty concat, but allocate using opts_obstack. */ |
965 | |
966 | char * |
967 | opts_concat (const char *first, ...) |
968 | { |
969 | char *newstr, *end; |
970 | size_t length = 0; |
971 | const char *arg; |
972 | va_list ap; |
973 | |
974 | /* First compute the size of the result and get sufficient memory. */ |
975 | va_start (ap, first); |
976 | for (arg = first; arg; arg = va_arg (ap, const char *)) |
977 | length += strlen (s: arg); |
978 | newstr = XOBNEWVEC (&opts_obstack, char, length + 1); |
979 | va_end (ap); |
980 | |
981 | /* Now copy the individual pieces to the result string. */ |
982 | va_start (ap, first); |
983 | for (arg = first, end = newstr; arg; arg = va_arg (ap, const char *)) |
984 | { |
985 | length = strlen (s: arg); |
986 | memcpy (dest: end, src: arg, n: length); |
987 | end += length; |
988 | } |
989 | *end = '\0'; |
990 | va_end (ap); |
991 | return newstr; |
992 | } |
993 | |
994 | /* Decode command-line options (ARGC and ARGV being the arguments of |
995 | main) into an array, setting *DECODED_OPTIONS to a pointer to that |
996 | array and *DECODED_OPTIONS_COUNT to the number of entries in the |
997 | array. The first entry in the array is always one for the program |
998 | name (OPT_SPECIAL_program_name). LANG_MASK indicates the language |
999 | flags applicable for decoding (including CL_COMMON and CL_TARGET if |
1000 | those options should be considered applicable). Do not produce any |
1001 | diagnostics or set state outside of these variables. */ |
1002 | |
1003 | void |
1004 | decode_cmdline_options_to_array (unsigned int argc, const char **argv, |
1005 | unsigned int lang_mask, |
1006 | struct cl_decoded_option **decoded_options, |
1007 | unsigned int *decoded_options_count) |
1008 | { |
1009 | unsigned int n, i; |
1010 | struct cl_decoded_option *opt_array; |
1011 | unsigned int num_decoded_options; |
1012 | |
1013 | int opt_array_len = argc; |
1014 | opt_array = XNEWVEC (struct cl_decoded_option, opt_array_len); |
1015 | |
1016 | opt_array[0].opt_index = OPT_SPECIAL_program_name; |
1017 | opt_array[0].warn_message = NULL; |
1018 | opt_array[0].arg = argv[0]; |
1019 | opt_array[0].orig_option_with_args_text = argv[0]; |
1020 | opt_array[0].canonical_option_num_elements = 1; |
1021 | opt_array[0].canonical_option[0] = argv[0]; |
1022 | opt_array[0].canonical_option[1] = NULL; |
1023 | opt_array[0].canonical_option[2] = NULL; |
1024 | opt_array[0].canonical_option[3] = NULL; |
1025 | opt_array[0].value = 1; |
1026 | opt_array[0].mask = 0; |
1027 | opt_array[0].errors = 0; |
1028 | num_decoded_options = 1; |
1029 | |
1030 | for (i = 1; i < argc; i += n) |
1031 | { |
1032 | const char *opt = argv[i]; |
1033 | |
1034 | /* Interpret "-" or a non-switch as a file name. */ |
1035 | if (opt[0] != '-' || opt[1] == '\0') |
1036 | { |
1037 | generate_option_input_file (file: opt, decoded: &opt_array[num_decoded_options]); |
1038 | num_decoded_options++; |
1039 | n = 1; |
1040 | continue; |
1041 | } |
1042 | |
1043 | /* Interpret "--param" "key=name" as "--param=key=name". */ |
1044 | const char *needle = "--param" ; |
1045 | if (i + 1 < argc && strcmp (s1: opt, s2: needle) == 0) |
1046 | { |
1047 | const char *replacement |
1048 | = opts_concat (first: needle, "=" , argv[i + 1], NULL); |
1049 | argv[++i] = replacement; |
1050 | } |
1051 | |
1052 | /* Expand -fdiagnostics-plain-output to its constituents. This needs |
1053 | to happen here so that prune_options can handle -fdiagnostics-color |
1054 | specially. */ |
1055 | if (!strcmp (s1: opt, s2: "-fdiagnostics-plain-output" )) |
1056 | { |
1057 | /* If you have changed the default diagnostics output, and this new |
1058 | output is not appropriately "plain" (e.g., the change needs to be |
1059 | undone in order for the testsuite to work properly), then please do |
1060 | the following: |
1061 | 1. Add the necessary option to undo the new behavior to |
1062 | the array below. |
1063 | 2. Update the documentation for -fdiagnostics-plain-output |
1064 | in invoke.texi. */ |
1065 | const char *const expanded_args[] = { |
1066 | "-fno-diagnostics-show-caret" , |
1067 | "-fno-diagnostics-show-line-numbers" , |
1068 | "-fdiagnostics-color=never" , |
1069 | "-fdiagnostics-urls=never" , |
1070 | "-fdiagnostics-path-format=separate-events" , |
1071 | "-fdiagnostics-text-art-charset=none" |
1072 | }; |
1073 | const int num_expanded = ARRAY_SIZE (expanded_args); |
1074 | opt_array_len += num_expanded - 1; |
1075 | opt_array = XRESIZEVEC (struct cl_decoded_option, |
1076 | opt_array, opt_array_len); |
1077 | for (int j = 0, nj; j < num_expanded; j += nj) |
1078 | { |
1079 | nj = decode_cmdline_option (argv: expanded_args + j, lang_mask, |
1080 | decoded: &opt_array[num_decoded_options]); |
1081 | num_decoded_options++; |
1082 | } |
1083 | |
1084 | n = 1; |
1085 | continue; |
1086 | } |
1087 | |
1088 | n = decode_cmdline_option (argv: argv + i, lang_mask, |
1089 | decoded: &opt_array[num_decoded_options]); |
1090 | num_decoded_options++; |
1091 | } |
1092 | |
1093 | *decoded_options = opt_array; |
1094 | *decoded_options_count = num_decoded_options; |
1095 | prune_options (decoded_options, decoded_options_count); |
1096 | } |
1097 | |
1098 | /* Return true if NEXT_OPT_IDX cancels OPT_IDX. Return false if the |
1099 | next one is the same as ORIG_NEXT_OPT_IDX. */ |
1100 | |
1101 | static bool |
1102 | cancel_option (int opt_idx, int next_opt_idx, int orig_next_opt_idx) |
1103 | { |
1104 | /* An option can be canceled by the same option or an option with |
1105 | Negative. */ |
1106 | if (cl_options [next_opt_idx].neg_index == opt_idx) |
1107 | return true; |
1108 | |
1109 | if (cl_options [next_opt_idx].neg_index != orig_next_opt_idx) |
1110 | return cancel_option (opt_idx, next_opt_idx: cl_options [next_opt_idx].neg_index, |
1111 | orig_next_opt_idx); |
1112 | |
1113 | return false; |
1114 | } |
1115 | |
1116 | /* Filter out options canceled by the ones after them, and related |
1117 | rearrangement. */ |
1118 | |
1119 | static void |
1120 | prune_options (struct cl_decoded_option **decoded_options, |
1121 | unsigned int *decoded_options_count) |
1122 | { |
1123 | unsigned int old_decoded_options_count = *decoded_options_count; |
1124 | struct cl_decoded_option *old_decoded_options = *decoded_options; |
1125 | unsigned int new_decoded_options_count; |
1126 | struct cl_decoded_option *new_decoded_options |
1127 | = XNEWVEC (struct cl_decoded_option, old_decoded_options_count); |
1128 | unsigned int i; |
1129 | const struct cl_option *option; |
1130 | unsigned int options_to_prepend = 0; |
1131 | unsigned int Wcomplain_wrong_lang_idx = 0; |
1132 | unsigned int fdiagnostics_color_idx = 0; |
1133 | |
1134 | /* Remove arguments which are negated by others after them. */ |
1135 | new_decoded_options_count = 0; |
1136 | for (i = 0; i < old_decoded_options_count; i++) |
1137 | { |
1138 | unsigned int j, opt_idx, next_opt_idx; |
1139 | |
1140 | if (old_decoded_options[i].errors & ~CL_ERR_WRONG_LANG) |
1141 | goto keep; |
1142 | |
1143 | opt_idx = old_decoded_options[i].opt_index; |
1144 | switch (opt_idx) |
1145 | { |
1146 | case OPT_SPECIAL_unknown: |
1147 | case OPT_SPECIAL_ignore: |
1148 | case OPT_SPECIAL_warn_removed: |
1149 | case OPT_SPECIAL_program_name: |
1150 | case OPT_SPECIAL_input_file: |
1151 | goto keep; |
1152 | |
1153 | /* Do not handle the following yet, just remember the last one. */ |
1154 | case OPT_Wcomplain_wrong_lang: |
1155 | gcc_checking_assert (i != 0); |
1156 | if (Wcomplain_wrong_lang_idx == 0) |
1157 | ++options_to_prepend; |
1158 | Wcomplain_wrong_lang_idx = i; |
1159 | continue; |
1160 | case OPT_fdiagnostics_color_: |
1161 | gcc_checking_assert (i != 0); |
1162 | if (fdiagnostics_color_idx == 0) |
1163 | ++options_to_prepend; |
1164 | fdiagnostics_color_idx = i; |
1165 | continue; |
1166 | |
1167 | default: |
1168 | gcc_assert (opt_idx < cl_options_count); |
1169 | option = &cl_options[opt_idx]; |
1170 | if (option->neg_index < 0) |
1171 | goto keep; |
1172 | |
1173 | /* Skip joined switches. */ |
1174 | if ((option->flags & CL_JOINED) |
1175 | && (!option->cl_reject_negative |
1176 | || (unsigned int) option->neg_index != opt_idx)) |
1177 | goto keep; |
1178 | |
1179 | for (j = i + 1; j < old_decoded_options_count; j++) |
1180 | { |
1181 | if (old_decoded_options[j].errors & ~CL_ERR_WRONG_LANG) |
1182 | continue; |
1183 | next_opt_idx = old_decoded_options[j].opt_index; |
1184 | if (next_opt_idx >= cl_options_count) |
1185 | continue; |
1186 | if (cl_options[next_opt_idx].neg_index < 0) |
1187 | continue; |
1188 | if ((cl_options[next_opt_idx].flags & CL_JOINED) |
1189 | && (!cl_options[next_opt_idx].cl_reject_negative |
1190 | || ((unsigned int) cl_options[next_opt_idx].neg_index |
1191 | != next_opt_idx))) |
1192 | continue; |
1193 | if (cancel_option (opt_idx, next_opt_idx, orig_next_opt_idx: next_opt_idx)) |
1194 | break; |
1195 | } |
1196 | if (j == old_decoded_options_count) |
1197 | { |
1198 | keep: |
1199 | new_decoded_options[new_decoded_options_count] |
1200 | = old_decoded_options[i]; |
1201 | new_decoded_options_count++; |
1202 | } |
1203 | break; |
1204 | } |
1205 | } |
1206 | |
1207 | /* For those not yet handled, put (only) the last at a front position after |
1208 | 'argv[0]', so they can take effect immediately. */ |
1209 | if (options_to_prepend) |
1210 | { |
1211 | const unsigned int argv_0 = 1; |
1212 | memmove (dest: new_decoded_options + argv_0 + options_to_prepend, |
1213 | src: new_decoded_options + argv_0, |
1214 | n: sizeof (struct cl_decoded_option) |
1215 | * (new_decoded_options_count - argv_0)); |
1216 | unsigned int options_prepended = 0; |
1217 | if (Wcomplain_wrong_lang_idx != 0) |
1218 | { |
1219 | new_decoded_options[argv_0 + options_prepended++] |
1220 | = old_decoded_options[Wcomplain_wrong_lang_idx]; |
1221 | new_decoded_options_count++; |
1222 | } |
1223 | if (fdiagnostics_color_idx != 0) |
1224 | { |
1225 | new_decoded_options[argv_0 + options_prepended++] |
1226 | = old_decoded_options[fdiagnostics_color_idx]; |
1227 | new_decoded_options_count++; |
1228 | } |
1229 | gcc_checking_assert (options_to_prepend == options_prepended); |
1230 | } |
1231 | |
1232 | free (ptr: old_decoded_options); |
1233 | new_decoded_options = XRESIZEVEC (struct cl_decoded_option, |
1234 | new_decoded_options, |
1235 | new_decoded_options_count); |
1236 | *decoded_options = new_decoded_options; |
1237 | *decoded_options_count = new_decoded_options_count; |
1238 | } |
1239 | |
1240 | /* Handle option DECODED for the language indicated by LANG_MASK, |
1241 | using the handlers in HANDLERS and setting fields in OPTS and |
1242 | OPTS_SET. KIND is the diagnostic_t if this is a diagnostics |
1243 | option, DK_UNSPECIFIED otherwise, and LOC is the location of the |
1244 | option for options from the source file, UNKNOWN_LOCATION |
1245 | otherwise. GENERATED_P is true for an option generated as part of |
1246 | processing another option or otherwise generated internally, false |
1247 | for one explicitly passed by the user. control_warning_option |
1248 | generated options are considered explicitly passed by the user. |
1249 | Returns false if the switch was invalid. DC is the diagnostic |
1250 | context for options affecting diagnostics state, or NULL. */ |
1251 | |
1252 | static bool |
1253 | handle_option (struct gcc_options *opts, |
1254 | struct gcc_options *opts_set, |
1255 | const struct cl_decoded_option *decoded, |
1256 | unsigned int lang_mask, int kind, location_t loc, |
1257 | const struct cl_option_handlers *handlers, |
1258 | bool generated_p, diagnostic_context *dc) |
1259 | { |
1260 | size_t opt_index = decoded->opt_index; |
1261 | const char *arg = decoded->arg; |
1262 | HOST_WIDE_INT value = decoded->value; |
1263 | HOST_WIDE_INT mask = decoded->mask; |
1264 | const struct cl_option *option = &cl_options[opt_index]; |
1265 | void *flag_var = option_flag_var (opt_index, opts); |
1266 | size_t i; |
1267 | |
1268 | if (flag_var) |
1269 | set_option (opts, opts_set: (generated_p ? NULL : opts_set), |
1270 | opt_index, value, arg, kind, loc, dc, mask); |
1271 | |
1272 | for (i = 0; i < handlers->num_handlers; i++) |
1273 | if (option->flags & handlers->handlers[i].mask) |
1274 | { |
1275 | if (!handlers->handlers[i].handler (opts, opts_set, decoded, |
1276 | lang_mask, kind, loc, |
1277 | handlers, dc, |
1278 | handlers->target_option_override_hook)) |
1279 | return false; |
1280 | } |
1281 | |
1282 | return true; |
1283 | } |
1284 | |
1285 | /* Like handle_option, but OPT_INDEX, ARG and VALUE describe the |
1286 | option instead of DECODED. This is used for callbacks when one |
1287 | option implies another instead of an option being decoded from the |
1288 | command line. */ |
1289 | |
1290 | bool |
1291 | handle_generated_option (struct gcc_options *opts, |
1292 | struct gcc_options *opts_set, |
1293 | size_t opt_index, const char *arg, HOST_WIDE_INT value, |
1294 | unsigned int lang_mask, int kind, location_t loc, |
1295 | const struct cl_option_handlers *handlers, |
1296 | bool generated_p, diagnostic_context *dc) |
1297 | { |
1298 | struct cl_decoded_option decoded; |
1299 | |
1300 | generate_option (opt_index, arg, value, lang_mask, decoded: &decoded); |
1301 | return handle_option (opts, opts_set, decoded: &decoded, lang_mask, kind, loc, |
1302 | handlers, generated_p, dc); |
1303 | } |
1304 | |
1305 | /* Fill in *DECODED with an option described by OPT_INDEX, ARG and |
1306 | VALUE for a front end using LANG_MASK. This is used when the |
1307 | compiler generates options internally. */ |
1308 | |
1309 | void |
1310 | generate_option (size_t opt_index, const char *arg, HOST_WIDE_INT value, |
1311 | unsigned int lang_mask, struct cl_decoded_option *decoded) |
1312 | { |
1313 | const struct cl_option *option = &cl_options[opt_index]; |
1314 | |
1315 | decoded->opt_index = opt_index; |
1316 | decoded->warn_message = NULL; |
1317 | decoded->arg = arg; |
1318 | decoded->value = value; |
1319 | decoded->mask = 0; |
1320 | decoded->errors = (option_ok_for_language (option, lang_mask) |
1321 | ? 0 |
1322 | : CL_ERR_WRONG_LANG); |
1323 | |
1324 | generate_canonical_option (opt_index, arg, value, decoded); |
1325 | switch (decoded->canonical_option_num_elements) |
1326 | { |
1327 | case 1: |
1328 | decoded->orig_option_with_args_text = decoded->canonical_option[0]; |
1329 | break; |
1330 | |
1331 | case 2: |
1332 | decoded->orig_option_with_args_text |
1333 | = opts_concat (first: decoded->canonical_option[0], " " , |
1334 | decoded->canonical_option[1], NULL); |
1335 | break; |
1336 | |
1337 | default: |
1338 | gcc_unreachable (); |
1339 | } |
1340 | } |
1341 | |
1342 | /* Fill in *DECODED with an option for input file FILE. */ |
1343 | |
1344 | void |
1345 | generate_option_input_file (const char *file, |
1346 | struct cl_decoded_option *decoded) |
1347 | { |
1348 | decoded->opt_index = OPT_SPECIAL_input_file; |
1349 | decoded->warn_message = NULL; |
1350 | decoded->arg = file; |
1351 | decoded->orig_option_with_args_text = file; |
1352 | decoded->canonical_option_num_elements = 1; |
1353 | decoded->canonical_option[0] = file; |
1354 | decoded->canonical_option[1] = NULL; |
1355 | decoded->canonical_option[2] = NULL; |
1356 | decoded->canonical_option[3] = NULL; |
1357 | decoded->value = 1; |
1358 | decoded->mask = 0; |
1359 | decoded->errors = 0; |
1360 | } |
1361 | |
1362 | /* Helper function for listing valid choices and hint for misspelled |
1363 | value. CANDIDATES is a vector containing all valid strings, |
1364 | STR is set to a heap allocated string that contains all those |
1365 | strings concatenated, separated by spaces, and the return value |
1366 | is the closest string from those to ARG, or NULL if nothing is |
1367 | close enough. Callers should XDELETEVEC (STR) after using it |
1368 | to avoid memory leaks. */ |
1369 | |
1370 | const char * |
1371 | candidates_list_and_hint (const char *arg, char *&str, |
1372 | const auto_vec <const char *> &candidates) |
1373 | { |
1374 | size_t len = 0; |
1375 | int i; |
1376 | const char *candidate; |
1377 | char *p; |
1378 | |
1379 | gcc_assert (!candidates.is_empty ()); |
1380 | |
1381 | FOR_EACH_VEC_ELT (candidates, i, candidate) |
1382 | len += strlen (s: candidate) + 1; |
1383 | |
1384 | str = p = XNEWVEC (char, len); |
1385 | FOR_EACH_VEC_ELT (candidates, i, candidate) |
1386 | { |
1387 | len = strlen (s: candidate); |
1388 | memcpy (dest: p, src: candidate, n: len); |
1389 | p[len] = ' '; |
1390 | p += len + 1; |
1391 | } |
1392 | p[-1] = '\0'; |
1393 | return find_closest_string (target: arg, candidates: &candidates); |
1394 | } |
1395 | |
1396 | /* Perform diagnostics for read_cmdline_option and control_warning_option |
1397 | functions. Returns true if an error has been diagnosed. |
1398 | LOC and LANG_MASK arguments like in read_cmdline_option. |
1399 | OPTION is the option to report diagnostics for, OPT the name |
1400 | of the option as text, ARG the argument of the option (for joined |
1401 | options), ERRORS is bitmask of CL_ERR_* values. */ |
1402 | |
1403 | static bool |
1404 | cmdline_handle_error (location_t loc, const struct cl_option *option, |
1405 | const char *opt, const char *arg, int errors, |
1406 | unsigned int lang_mask) |
1407 | { |
1408 | if (errors & CL_ERR_DISABLED) |
1409 | { |
1410 | error_at (loc, "command-line option %qs" |
1411 | " is not supported by this configuration" , opt); |
1412 | return true; |
1413 | } |
1414 | |
1415 | if (errors & CL_ERR_MISSING_ARG) |
1416 | { |
1417 | if (option->missing_argument_error) |
1418 | error_at (loc, option->missing_argument_error, opt); |
1419 | else |
1420 | error_at (loc, "missing argument to %qs" , opt); |
1421 | return true; |
1422 | } |
1423 | |
1424 | if (errors & CL_ERR_UINT_ARG) |
1425 | { |
1426 | if (option->cl_byte_size) |
1427 | error_at (loc, "argument to %qs should be a non-negative integer " |
1428 | "optionally followed by a size unit" , |
1429 | option->opt_text); |
1430 | else |
1431 | error_at (loc, "argument to %qs should be a non-negative integer" , |
1432 | option->opt_text); |
1433 | return true; |
1434 | } |
1435 | |
1436 | if (errors & CL_ERR_INT_RANGE_ARG) |
1437 | { |
1438 | error_at (loc, "argument to %qs is not between %d and %d" , |
1439 | option->opt_text, option->range_min, option->range_max); |
1440 | return true; |
1441 | } |
1442 | |
1443 | if (errors & CL_ERR_ENUM_SET_ARG) |
1444 | { |
1445 | const struct cl_enum *e = &cl_enums[option->var_enum]; |
1446 | const char *p = arg; |
1447 | unsigned HOST_WIDE_INT used_sets = 0; |
1448 | const char *second_opt = NULL; |
1449 | size_t second_opt_len = 0; |
1450 | errors = 0; |
1451 | do |
1452 | { |
1453 | const char *q = strchr (s: p, c: ','); |
1454 | HOST_WIDE_INT this_value = 0; |
1455 | if (q && q == p) |
1456 | { |
1457 | arg = "" ; |
1458 | errors = CL_ERR_ENUM_ARG; |
1459 | break; |
1460 | } |
1461 | int idx = enum_arg_to_value (enum_args: e->values, arg: p, len: q ? q - p : 0, |
1462 | value: &this_value, lang_mask); |
1463 | if (idx < 0) |
1464 | { |
1465 | if (q == NULL) |
1466 | q = strchr (s: p, c: '\0'); |
1467 | char *narg = XALLOCAVEC (char, (q - p) + 1); |
1468 | memcpy (dest: narg, src: p, n: q - p); |
1469 | narg[q - p] = '\0'; |
1470 | arg = narg; |
1471 | errors = CL_ERR_ENUM_ARG; |
1472 | break; |
1473 | } |
1474 | |
1475 | if (option->var_value == CLEV_BITSET) |
1476 | { |
1477 | if (q == NULL) |
1478 | break; |
1479 | p = q + 1; |
1480 | continue; |
1481 | } |
1482 | |
1483 | unsigned set = e->values[idx].flags >> CL_ENUM_SET_SHIFT; |
1484 | gcc_checking_assert (set >= 1 && set <= HOST_BITS_PER_WIDE_INT); |
1485 | if ((used_sets & (HOST_WIDE_INT_1U << (set - 1))) != 0) |
1486 | { |
1487 | if (q == NULL) |
1488 | q = strchr (s: p, c: '\0'); |
1489 | if (second_opt == NULL) |
1490 | { |
1491 | used_sets = HOST_WIDE_INT_1U << (set - 1); |
1492 | second_opt = p; |
1493 | second_opt_len = q - p; |
1494 | p = arg; |
1495 | continue; |
1496 | } |
1497 | char *args = XALLOCAVEC (char, (q - p) + 1 + second_opt_len + 1); |
1498 | memcpy (dest: args, src: p, n: q - p); |
1499 | args[q - p] = '\0'; |
1500 | memcpy (dest: args + (q - p) + 1, src: second_opt, n: second_opt_len); |
1501 | args[(q - p) + 1 + second_opt_len] = '\0'; |
1502 | error_at (loc, "invalid argument in option %qs" , opt); |
1503 | if (strcmp (s1: args, s2: args + (q - p) + 1) == 0) |
1504 | inform (loc, "%qs specified multiple times in the same option" , |
1505 | args); |
1506 | else |
1507 | inform (loc, "%qs is mutually exclusive with %qs and cannot be" |
1508 | " specified together" , args, args + (q - p) + 1); |
1509 | return true; |
1510 | } |
1511 | used_sets |= HOST_WIDE_INT_1U << (set - 1); |
1512 | if (q == NULL) |
1513 | break; |
1514 | p = q + 1; |
1515 | } |
1516 | while (1); |
1517 | } |
1518 | |
1519 | if (errors & CL_ERR_ENUM_ARG) |
1520 | { |
1521 | const struct cl_enum *e = &cl_enums[option->var_enum]; |
1522 | unsigned int i; |
1523 | char *s; |
1524 | |
1525 | auto_diagnostic_group d; |
1526 | if (e->unknown_error) |
1527 | error_at (loc, e->unknown_error, arg); |
1528 | else |
1529 | error_at (loc, "unrecognized argument in option %qs" , opt); |
1530 | |
1531 | auto_vec <const char *> candidates; |
1532 | for (i = 0; e->values[i].arg != NULL; i++) |
1533 | { |
1534 | if (!enum_arg_ok_for_language (enum_arg: &e->values[i], lang_mask)) |
1535 | continue; |
1536 | candidates.safe_push (obj: e->values[i].arg); |
1537 | } |
1538 | const char *hint = candidates_list_and_hint (arg, str&: s, candidates); |
1539 | if (hint) |
1540 | inform (loc, "valid arguments to %qs are: %s; did you mean %qs?" , |
1541 | option->opt_text, s, hint); |
1542 | else |
1543 | inform (loc, "valid arguments to %qs are: %s" , option->opt_text, s); |
1544 | XDELETEVEC (s); |
1545 | |
1546 | return true; |
1547 | } |
1548 | |
1549 | return false; |
1550 | } |
1551 | |
1552 | /* Handle the switch DECODED (location LOC) for the language indicated |
1553 | by LANG_MASK, using the handlers in *HANDLERS and setting fields in |
1554 | OPTS and OPTS_SET and using diagnostic context DC (if not NULL) for |
1555 | diagnostic options. */ |
1556 | |
1557 | void |
1558 | read_cmdline_option (struct gcc_options *opts, |
1559 | struct gcc_options *opts_set, |
1560 | struct cl_decoded_option *decoded, |
1561 | location_t loc, |
1562 | unsigned int lang_mask, |
1563 | const struct cl_option_handlers *handlers, |
1564 | diagnostic_context *dc) |
1565 | { |
1566 | const struct cl_option *option; |
1567 | const char *opt = decoded->orig_option_with_args_text; |
1568 | |
1569 | if (decoded->warn_message) |
1570 | warning_at (loc, 0, decoded->warn_message, opt); |
1571 | |
1572 | if (decoded->opt_index == OPT_SPECIAL_unknown) |
1573 | { |
1574 | if (handlers->unknown_option_callback (decoded)) |
1575 | error_at (loc, "unrecognized command-line option %qs" , decoded->arg); |
1576 | return; |
1577 | } |
1578 | |
1579 | if (decoded->opt_index == OPT_SPECIAL_ignore) |
1580 | return; |
1581 | |
1582 | if (decoded->opt_index == OPT_SPECIAL_warn_removed) |
1583 | { |
1584 | /* Warn only about positive ignored options. */ |
1585 | if (decoded->value) |
1586 | warning_at (loc, 0, "switch %qs is no longer supported" , opt); |
1587 | return; |
1588 | } |
1589 | |
1590 | option = &cl_options[decoded->opt_index]; |
1591 | |
1592 | if (decoded->errors |
1593 | && cmdline_handle_error (loc, option, opt, arg: decoded->arg, |
1594 | errors: decoded->errors, lang_mask)) |
1595 | return; |
1596 | |
1597 | if (decoded->errors & CL_ERR_WRONG_LANG) |
1598 | { |
1599 | handlers->wrong_lang_callback (decoded, lang_mask); |
1600 | return; |
1601 | } |
1602 | |
1603 | gcc_assert (!decoded->errors); |
1604 | |
1605 | if (!handle_option (opts, opts_set, decoded, lang_mask, kind: DK_UNSPECIFIED, |
1606 | loc, handlers, generated_p: false, dc)) |
1607 | error_at (loc, "unrecognized command-line option %qs" , opt); |
1608 | } |
1609 | |
1610 | /* Set any field in OPTS, and OPTS_SET if not NULL, for option |
1611 | OPT_INDEX according to VALUE and ARG, diagnostic kind KIND, |
1612 | location LOC, using diagnostic context DC if not NULL for |
1613 | diagnostic classification. */ |
1614 | |
1615 | void |
1616 | set_option (struct gcc_options *opts, struct gcc_options *opts_set, |
1617 | int opt_index, HOST_WIDE_INT value, const char *arg, int kind, |
1618 | location_t loc, diagnostic_context *dc, |
1619 | HOST_WIDE_INT mask /* = 0 */) |
1620 | { |
1621 | const struct cl_option *option = &cl_options[opt_index]; |
1622 | void *flag_var = option_flag_var (opt_index, opts); |
1623 | void *set_flag_var = NULL; |
1624 | |
1625 | if (!flag_var) |
1626 | return; |
1627 | |
1628 | if ((diagnostic_t) kind != DK_UNSPECIFIED && dc != NULL) |
1629 | diagnostic_classify_diagnostic (context: dc, optidx: opt_index, kind: (diagnostic_t) kind, where: loc); |
1630 | |
1631 | if (opts_set != NULL) |
1632 | set_flag_var = option_flag_var (opt_index, opts: opts_set); |
1633 | |
1634 | switch (option->var_type) |
1635 | { |
1636 | case CLVC_INTEGER: |
1637 | if (option->cl_host_wide_int) |
1638 | { |
1639 | *(HOST_WIDE_INT *) flag_var = value; |
1640 | if (set_flag_var) |
1641 | *(HOST_WIDE_INT *) set_flag_var = 1; |
1642 | } |
1643 | else |
1644 | { |
1645 | if (value > INT_MAX) |
1646 | error_at (loc, "argument to %qs is bigger than %d" , |
1647 | option->opt_text, INT_MAX); |
1648 | else |
1649 | { |
1650 | *(int *) flag_var = value; |
1651 | if (set_flag_var) |
1652 | *(int *) set_flag_var = 1; |
1653 | } |
1654 | } |
1655 | |
1656 | break; |
1657 | |
1658 | case CLVC_SIZE: |
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 = value; |
1664 | } |
1665 | else |
1666 | { |
1667 | *(int *) flag_var = value; |
1668 | if (set_flag_var) |
1669 | *(int *) set_flag_var = value; |
1670 | } |
1671 | |
1672 | break; |
1673 | |
1674 | case CLVC_EQUAL: |
1675 | if (option->cl_host_wide_int) |
1676 | { |
1677 | *(HOST_WIDE_INT *) flag_var = (value |
1678 | ? option->var_value |
1679 | : !option->var_value); |
1680 | if (set_flag_var) |
1681 | *(HOST_WIDE_INT *) set_flag_var = 1; |
1682 | } |
1683 | else |
1684 | { |
1685 | *(int *) flag_var = (value |
1686 | ? option->var_value |
1687 | : !option->var_value); |
1688 | if (set_flag_var) |
1689 | *(int *) set_flag_var = 1; |
1690 | } |
1691 | break; |
1692 | |
1693 | case CLVC_BIT_CLEAR: |
1694 | case CLVC_BIT_SET: |
1695 | if ((value != 0) == (option->var_type == CLVC_BIT_SET)) |
1696 | { |
1697 | if (option->cl_host_wide_int) |
1698 | *(HOST_WIDE_INT *) flag_var |= option->var_value; |
1699 | else |
1700 | *(int *) flag_var |= option->var_value; |
1701 | } |
1702 | else |
1703 | { |
1704 | if (option->cl_host_wide_int) |
1705 | *(HOST_WIDE_INT *) flag_var &= ~option->var_value; |
1706 | else |
1707 | *(int *) flag_var &= ~option->var_value; |
1708 | } |
1709 | if (set_flag_var) |
1710 | { |
1711 | if (option->cl_host_wide_int) |
1712 | *(HOST_WIDE_INT *) set_flag_var |= option->var_value; |
1713 | else |
1714 | *(int *) set_flag_var |= option->var_value; |
1715 | } |
1716 | break; |
1717 | |
1718 | case CLVC_STRING: |
1719 | *(const char **) flag_var = arg; |
1720 | if (set_flag_var) |
1721 | *(const char **) set_flag_var = "" ; |
1722 | break; |
1723 | |
1724 | case CLVC_ENUM: |
1725 | { |
1726 | const struct cl_enum *e = &cl_enums[option->var_enum]; |
1727 | |
1728 | if (mask) |
1729 | e->set (flag_var, value | (e->get (flag_var) & ~mask)); |
1730 | else |
1731 | e->set (flag_var, value); |
1732 | if (set_flag_var) |
1733 | e->set (set_flag_var, 1); |
1734 | } |
1735 | break; |
1736 | |
1737 | case CLVC_DEFER: |
1738 | { |
1739 | vec<cl_deferred_option> *v |
1740 | = (vec<cl_deferred_option> *) *(void **) flag_var; |
1741 | cl_deferred_option p = {.opt_index: opt_index, .arg: arg, .value: value}; |
1742 | if (!v) |
1743 | v = XCNEW (vec<cl_deferred_option>); |
1744 | v->safe_push (obj: p); |
1745 | *(void **) flag_var = v; |
1746 | if (set_flag_var) |
1747 | *(void **) set_flag_var = v; |
1748 | } |
1749 | break; |
1750 | } |
1751 | } |
1752 | |
1753 | /* Return the address of the flag variable for option OPT_INDEX in |
1754 | options structure OPTS, or NULL if there is no flag variable. */ |
1755 | |
1756 | void * |
1757 | option_flag_var (int opt_index, struct gcc_options *opts) |
1758 | { |
1759 | const struct cl_option *option = &cl_options[opt_index]; |
1760 | |
1761 | if (option->flag_var_offset == (unsigned short) -1) |
1762 | return NULL; |
1763 | return (void *)(((char *) opts) + option->flag_var_offset); |
1764 | } |
1765 | |
1766 | /* Return 1 if option OPT_IDX is enabled in OPTS, 0 if it is disabled, |
1767 | or -1 if it isn't a simple on-off switch |
1768 | (or if the value is unknown, typically set later in target). */ |
1769 | |
1770 | int |
1771 | option_enabled (int opt_idx, unsigned lang_mask, void *opts) |
1772 | { |
1773 | const struct cl_option *option = &(cl_options[opt_idx]); |
1774 | |
1775 | /* A language-specific option can only be considered enabled when it's |
1776 | valid for the current language. */ |
1777 | if (!(option->flags & CL_COMMON) |
1778 | && (option->flags & CL_LANG_ALL) |
1779 | && !(option->flags & lang_mask)) |
1780 | return 0; |
1781 | |
1782 | struct gcc_options *optsg = (struct gcc_options *) opts; |
1783 | void *flag_var = option_flag_var (opt_index: opt_idx, opts: optsg); |
1784 | |
1785 | if (flag_var) |
1786 | switch (option->var_type) |
1787 | { |
1788 | case CLVC_INTEGER: |
1789 | if (option->cl_host_wide_int) |
1790 | { |
1791 | HOST_WIDE_INT v = *(HOST_WIDE_INT *) flag_var; |
1792 | return v != 0 ? (v < 0 ? -1 : 1) : 0; |
1793 | } |
1794 | else |
1795 | { |
1796 | int v = *(int *) flag_var; |
1797 | return v != 0 ? (v < 0 ? -1 : 1) : 0; |
1798 | } |
1799 | |
1800 | case CLVC_EQUAL: |
1801 | if (option->cl_host_wide_int) |
1802 | return *(HOST_WIDE_INT *) flag_var == option->var_value; |
1803 | else |
1804 | return *(int *) flag_var == option->var_value; |
1805 | |
1806 | case CLVC_BIT_CLEAR: |
1807 | if (option->cl_host_wide_int) |
1808 | return (*(HOST_WIDE_INT *) flag_var & option->var_value) == 0; |
1809 | else |
1810 | return (*(int *) flag_var & option->var_value) == 0; |
1811 | |
1812 | case CLVC_BIT_SET: |
1813 | if (option->cl_host_wide_int) |
1814 | return (*(HOST_WIDE_INT *) flag_var & option->var_value) != 0; |
1815 | else |
1816 | return (*(int *) flag_var & option->var_value) != 0; |
1817 | |
1818 | case CLVC_SIZE: |
1819 | if (option->cl_host_wide_int) |
1820 | return *(HOST_WIDE_INT *) flag_var != -1; |
1821 | else |
1822 | return *(int *) flag_var != -1; |
1823 | |
1824 | case CLVC_STRING: |
1825 | case CLVC_ENUM: |
1826 | case CLVC_DEFER: |
1827 | break; |
1828 | } |
1829 | return -1; |
1830 | } |
1831 | |
1832 | /* Fill STATE with the current state of option OPTION in OPTS. Return |
1833 | true if there is some state to store. */ |
1834 | |
1835 | bool |
1836 | get_option_state (struct gcc_options *opts, int option, |
1837 | struct cl_option_state *state) |
1838 | { |
1839 | void *flag_var = option_flag_var (opt_index: option, opts); |
1840 | |
1841 | if (flag_var == 0) |
1842 | return false; |
1843 | |
1844 | switch (cl_options[option].var_type) |
1845 | { |
1846 | case CLVC_INTEGER: |
1847 | case CLVC_EQUAL: |
1848 | case CLVC_SIZE: |
1849 | state->data = flag_var; |
1850 | state->size = (cl_options[option].cl_host_wide_int |
1851 | ? sizeof (HOST_WIDE_INT) |
1852 | : sizeof (int)); |
1853 | break; |
1854 | |
1855 | case CLVC_BIT_CLEAR: |
1856 | case CLVC_BIT_SET: |
1857 | state->ch = option_enabled (opt_idx: option, lang_mask: -1, opts); |
1858 | state->data = &state->ch; |
1859 | state->size = 1; |
1860 | break; |
1861 | |
1862 | case CLVC_STRING: |
1863 | state->data = *(const char **) flag_var; |
1864 | if (state->data == 0) |
1865 | state->data = "" ; |
1866 | state->size = strlen (s: (const char *) state->data) + 1; |
1867 | break; |
1868 | |
1869 | case CLVC_ENUM: |
1870 | state->data = flag_var; |
1871 | state->size = cl_enums[cl_options[option].var_enum].var_size; |
1872 | break; |
1873 | |
1874 | case CLVC_DEFER: |
1875 | return false; |
1876 | } |
1877 | return true; |
1878 | } |
1879 | |
1880 | /* Set a warning option OPT_INDEX (language mask LANG_MASK, option |
1881 | handlers HANDLERS) to have diagnostic kind KIND for option |
1882 | structures OPTS and OPTS_SET and diagnostic context DC (possibly |
1883 | NULL), at location LOC (UNKNOWN_LOCATION for -Werror=). ARG is the |
1884 | argument of the option for joined options, or NULL otherwise. If IMPLY, |
1885 | the warning option in question is implied at this point. This is |
1886 | used by -Werror= and #pragma GCC diagnostic. */ |
1887 | |
1888 | void |
1889 | control_warning_option (unsigned int opt_index, int kind, const char *arg, |
1890 | bool imply, location_t loc, unsigned int lang_mask, |
1891 | const struct cl_option_handlers *handlers, |
1892 | struct gcc_options *opts, |
1893 | struct gcc_options *opts_set, |
1894 | diagnostic_context *dc) |
1895 | { |
1896 | if (cl_options[opt_index].alias_target != N_OPTS) |
1897 | { |
1898 | gcc_assert (!cl_options[opt_index].cl_separate_alias |
1899 | && !cl_options[opt_index].cl_negative_alias); |
1900 | if (cl_options[opt_index].alias_arg) |
1901 | arg = cl_options[opt_index].alias_arg; |
1902 | opt_index = cl_options[opt_index].alias_target; |
1903 | } |
1904 | if (opt_index == OPT_SPECIAL_ignore || opt_index == OPT_SPECIAL_warn_removed) |
1905 | return; |
1906 | if (dc) |
1907 | diagnostic_classify_diagnostic (context: dc, optidx: opt_index, kind: (diagnostic_t) kind, where: loc); |
1908 | if (imply) |
1909 | { |
1910 | const struct cl_option *option = &cl_options[opt_index]; |
1911 | |
1912 | /* -Werror=foo implies -Wfoo. */ |
1913 | if (option->var_type == CLVC_INTEGER |
1914 | || option->var_type == CLVC_ENUM |
1915 | || option->var_type == CLVC_SIZE) |
1916 | { |
1917 | HOST_WIDE_INT value = 1; |
1918 | |
1919 | if (arg && *arg == '\0' && !option->cl_missing_ok) |
1920 | arg = NULL; |
1921 | |
1922 | if ((option->flags & CL_JOINED) && arg == NULL) |
1923 | { |
1924 | cmdline_handle_error (loc, option, opt: option->opt_text, arg, |
1925 | CL_ERR_MISSING_ARG, lang_mask); |
1926 | return; |
1927 | } |
1928 | |
1929 | /* If the switch takes an integer argument, convert it. */ |
1930 | if (arg && (option->cl_uinteger || option->cl_host_wide_int)) |
1931 | { |
1932 | int error = 0; |
1933 | value = *arg ? integral_argument (arg, err: &error, |
1934 | byte_size_suffix: option->cl_byte_size) : 0; |
1935 | if (error) |
1936 | { |
1937 | cmdline_handle_error (loc, option, opt: option->opt_text, arg, |
1938 | CL_ERR_UINT_ARG, lang_mask); |
1939 | return; |
1940 | } |
1941 | } |
1942 | |
1943 | /* If the switch takes an enumerated argument, convert it. */ |
1944 | if (arg && option->var_type == CLVC_ENUM) |
1945 | { |
1946 | const struct cl_enum *e = &cl_enums[option->var_enum]; |
1947 | |
1948 | if (enum_arg_to_value (enum_args: e->values, arg, len: 0, value: &value, |
1949 | lang_mask) >= 0) |
1950 | { |
1951 | const char *carg = NULL; |
1952 | |
1953 | if (enum_value_to_arg (enum_args: e->values, argp: &carg, value, lang_mask)) |
1954 | arg = carg; |
1955 | gcc_assert (carg != NULL); |
1956 | } |
1957 | else |
1958 | { |
1959 | cmdline_handle_error (loc, option, opt: option->opt_text, arg, |
1960 | CL_ERR_ENUM_ARG, lang_mask); |
1961 | return; |
1962 | } |
1963 | } |
1964 | |
1965 | handle_generated_option (opts, opts_set, |
1966 | opt_index, arg, value, lang_mask, |
1967 | kind, loc, handlers, generated_p: false, dc); |
1968 | } |
1969 | } |
1970 | } |
1971 | |
1972 | /* Parse options in COLLECT_GCC_OPTIONS and push them on ARGV_OBSTACK. |
1973 | Store number of arguments into ARGC_P. */ |
1974 | |
1975 | void |
1976 | parse_options_from_collect_gcc_options (const char *collect_gcc_options, |
1977 | obstack *argv_obstack, |
1978 | int *argc_p) |
1979 | { |
1980 | char *argv_storage = xstrdup (collect_gcc_options); |
1981 | int j, k; |
1982 | |
1983 | for (j = 0, k = 0; argv_storage[j] != '\0'; ++j) |
1984 | { |
1985 | if (argv_storage[j] == '\'') |
1986 | { |
1987 | obstack_ptr_grow (argv_obstack, &argv_storage[k]); |
1988 | ++j; |
1989 | do |
1990 | { |
1991 | if (argv_storage[j] == '\0') |
1992 | fatal_error (input_location, |
1993 | "malformed %<COLLECT_GCC_OPTIONS%>" ); |
1994 | else if (startswith (str: &argv_storage[j], prefix: "'\\''" )) |
1995 | { |
1996 | argv_storage[k++] = '\''; |
1997 | j += 4; |
1998 | } |
1999 | else if (argv_storage[j] == '\'') |
2000 | break; |
2001 | else |
2002 | argv_storage[k++] = argv_storage[j++]; |
2003 | } |
2004 | while (1); |
2005 | argv_storage[k++] = '\0'; |
2006 | } |
2007 | } |
2008 | |
2009 | obstack_ptr_grow (argv_obstack, NULL); |
2010 | *argc_p = obstack_object_size (argv_obstack) / sizeof (void *) - 1; |
2011 | } |
2012 | |
2013 | /* Prepend -Xassembler for each option in COLLECT_AS_OPTIONS, |
2014 | and push on O. */ |
2015 | |
2016 | void prepend_xassembler_to_collect_as_options (const char *collect_as_options, |
2017 | obstack *o) |
2018 | { |
2019 | obstack opts_obstack; |
2020 | int opts_count; |
2021 | |
2022 | obstack_init (&opts_obstack); |
2023 | parse_options_from_collect_gcc_options (collect_gcc_options: collect_as_options, |
2024 | argv_obstack: &opts_obstack, argc_p: &opts_count); |
2025 | const char **assembler_opts = XOBFINISH (&opts_obstack, const char **); |
2026 | |
2027 | for (int i = 0; i < opts_count; i++) |
2028 | { |
2029 | obstack_grow (o, " '-Xassembler' " , |
2030 | strlen (" '-Xassembler' " )); |
2031 | const char *opt = assembler_opts[i]; |
2032 | obstack_1grow (o, '\''); |
2033 | obstack_grow (o, opt, strlen (opt)); |
2034 | obstack_1grow (o, '\''); |
2035 | } |
2036 | } |
2037 | |
2038 | jobserver_info::jobserver_info () |
2039 | { |
2040 | /* Traditionally, GNU make uses opened pipes for jobserver-auth, |
2041 | e.g. --jobserver-auth=3,4. |
2042 | Starting with GNU make 4.4, one can use --jobserver-style=fifo |
2043 | and then named pipe is used: --jobserver-auth=fifo:/tmp/hcsparta. */ |
2044 | |
2045 | /* Detect jobserver and drop it if it's not working. */ |
2046 | string js_needle = "--jobserver-auth=" ; |
2047 | string fifo_prefix = "fifo:" ; |
2048 | |
2049 | const char *envval = getenv (name: "MAKEFLAGS" ); |
2050 | if (envval != NULL) |
2051 | { |
2052 | string makeflags = envval; |
2053 | size_t n = makeflags.rfind (str: js_needle); |
2054 | if (n != string::npos) |
2055 | { |
2056 | string ending = makeflags.substr (pos: n + js_needle.size ()); |
2057 | if (ending.find (str: fifo_prefix) == 0) |
2058 | { |
2059 | ending = ending.substr (pos: fifo_prefix.size ()); |
2060 | pipe_path = ending.substr (pos: 0, n: ending.find (c: ' ')); |
2061 | is_active = true; |
2062 | } |
2063 | else if (sscanf (s: makeflags.c_str () + n + js_needle.size (), |
2064 | format: "%d,%d" , &rfd, &wfd) == 2 |
2065 | && rfd > 0 |
2066 | && wfd > 0 |
2067 | && is_valid_fd (fd: rfd) |
2068 | && is_valid_fd (fd: wfd)) |
2069 | is_active = true; |
2070 | else |
2071 | { |
2072 | string dup = makeflags.substr (pos: 0, n: n); |
2073 | size_t pos = makeflags.find (c: ' ', pos: n); |
2074 | if (pos != string::npos) |
2075 | dup += makeflags.substr (pos: pos); |
2076 | skipped_makeflags = "MAKEFLAGS=" + dup; |
2077 | error_msg |
2078 | = "cannot access %<" + js_needle + "%> file descriptors" ; |
2079 | } |
2080 | } |
2081 | error_msg = "%<" + js_needle + "%> is not present in %<MAKEFLAGS%>" ; |
2082 | } |
2083 | else |
2084 | error_msg = "%<MAKEFLAGS%> environment variable is unset" ; |
2085 | |
2086 | if (!error_msg.empty ()) |
2087 | error_msg = "jobserver is not available: " + error_msg; |
2088 | } |
2089 | |
2090 | void |
2091 | jobserver_info::connect () |
2092 | { |
2093 | if (!pipe_path.empty ()) |
2094 | { |
2095 | #if HOST_HAS_O_NONBLOCK |
2096 | pipefd = open (file: pipe_path.c_str (), O_RDWR | O_NONBLOCK); |
2097 | is_connected = true; |
2098 | #else |
2099 | is_connected = false; |
2100 | #endif |
2101 | } |
2102 | else |
2103 | is_connected = true; |
2104 | } |
2105 | |
2106 | void |
2107 | jobserver_info::disconnect () |
2108 | { |
2109 | if (!pipe_path.empty ()) |
2110 | { |
2111 | gcc_assert (close (pipefd) == 0); |
2112 | pipefd = -1; |
2113 | } |
2114 | } |
2115 | |
2116 | bool |
2117 | jobserver_info::get_token () |
2118 | { |
2119 | int fd = pipe_path.empty () ? rfd : pipefd; |
2120 | char c; |
2121 | unsigned n = read (fd: fd, buf: &c, nbytes: 1); |
2122 | if (n != 1) |
2123 | { |
2124 | gcc_assert (errno == EAGAIN); |
2125 | return false; |
2126 | } |
2127 | else |
2128 | return true; |
2129 | } |
2130 | |
2131 | void |
2132 | jobserver_info::return_token () |
2133 | { |
2134 | int fd = pipe_path.empty () ? wfd : pipefd; |
2135 | char c = 'G'; |
2136 | gcc_assert (write (fd, &c, 1) == 1); |
2137 | } |
2138 | |