X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Fopts.c;h=19d56348e2ec7d6895576c9b3f8d8bfd4706d1ac;hb=18a49466c972ff6bc70f5da5645eefcde97e1ab8;hp=3c4982735126c31cfb4e8f5bdb3a633ae48fee2d;hpb=8a5df2ceff755c1f799239f751f78e87cbfdcb36;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/opts.c b/gcc/opts.c index 3c498273512..19d56348e2e 100644 --- a/gcc/opts.c +++ b/gcc/opts.c @@ -1,12 +1,13 @@ /* Command line option handling. - Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 + Free Software Foundation, Inc. Contributed by Neil Booth. This file is part of GCC. GCC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free -Software Foundation; either version 2, or (at your option) any later +Software Foundation; either version 3, or (at your option) any later version. GCC is distributed in the hope that it will be useful, but WITHOUT ANY @@ -15,9 +16,8 @@ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License -along with GCC; see the file COPYING. If not, write to the Free -Software Foundation, 59 Temple Place - Suite 330, Boston, MA -02111-1307, USA. */ +along with GCC; see the file COPYING3. If not see +. */ #include "config.h" #include "system.h" @@ -26,6 +26,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "tm.h" #include "tree.h" #include "rtl.h" +#include "expr.h" #include "ggc.h" #include "output.h" #include "langhooks.h" @@ -38,29 +39,33 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "tm_p.h" /* For OPTIMIZATION_OPTIONS. */ #include "insn-attr.h" /* For INSN_SCHEDULING. */ #include "target.h" +#include "tree-pass.h" +#include "dbgcnt.h" +#include "debug.h" +#include "plugin.h" +#include "except.h" +#include "lto-streamer.h" /* Value of the -G xx switch, and whether it was passed or not. */ unsigned HOST_WIDE_INT g_switch_value; bool g_switch_set; +/* Same for selective scheduling. */ +bool sel_sched_switch_set; + /* True if we should exit after parsing options. */ bool exit_after_options; -/* Print various extra warnings. -W/-Wextra. */ -bool extra_warnings; - /* True to warn about any objects definitions whose size is larger than N bytes. Also want about function definitions whose returned values are larger than N bytes, where N is `larger_than_size'. */ bool warn_larger_than; HOST_WIDE_INT larger_than_size; -/* Nonzero means warn about constructs which might not be - strict-aliasing safe. */ -int warn_strict_aliasing; - -/* Hack for cooperation between set_Wunused and set_Wextra. */ -static bool maybe_warn_unused_parameter; +/* True to warn about any function whose frame size is larger + * than N bytes. */ +bool warn_frame_larger_than; +HOST_WIDE_INT frame_larger_than_size; /* Type(s) of debugging information we are producing (if any). See flags.h for the definitions of the different possible types of @@ -71,6 +76,256 @@ enum debug_info_type write_symbols = NO_DEBUG; the definitions of the different possible levels. */ enum debug_info_level debug_info_level = DINFO_LEVEL_NONE; +/* A major contribution to object and executable size is debug + information size. A major contribution to debug information size + is struct descriptions replicated in several object files. The + following flags attempt to reduce this information. The basic + idea is to not emit struct debugging information in the current + compilation unit when that information will be generated by + another compilation unit. + + Debug information for a struct defined in the current source + file should be generated in the object file. Likewise the + debug information for a struct defined in a header should be + generated in the object file of the corresponding source file. + Both of these case are handled when the base name of the file of + the struct definition matches the base name of the source file + of the current compilation unit. This matching emits minimal + struct debugging information. + + The base file name matching rule above will fail to emit debug + information for structs defined in system headers. So a second + category of files includes system headers in addition to files + with matching bases. + + The remaining types of files are library headers and application + headers. We cannot currently distinguish these two types. */ + +enum debug_struct_file +{ + DINFO_STRUCT_FILE_NONE, /* Debug no structs. */ + DINFO_STRUCT_FILE_BASE, /* Debug structs defined in files with the + same base name as the compilation unit. */ + DINFO_STRUCT_FILE_SYS, /* Also debug structs defined in system + header files. */ + DINFO_STRUCT_FILE_ANY /* Debug structs defined in all files. */ +}; + +/* Generic structs (e.g. templates not explicitly specialized) + may not have a compilation unit associated with them, and so + may need to be treated differently from ordinary structs. + + Structs only handled by reference (indirectly), will also usually + not need as much debugging information. */ + +static enum debug_struct_file debug_struct_ordinary[DINFO_USAGE_NUM_ENUMS] + = { DINFO_STRUCT_FILE_ANY, DINFO_STRUCT_FILE_ANY, DINFO_STRUCT_FILE_ANY }; +static enum debug_struct_file debug_struct_generic[DINFO_USAGE_NUM_ENUMS] + = { DINFO_STRUCT_FILE_ANY, DINFO_STRUCT_FILE_ANY, DINFO_STRUCT_FILE_ANY }; + +/* Parse the -femit-struct-debug-detailed option value + and set the flag variables. */ + +#define MATCH( prefix, string ) \ + ((strncmp (prefix, string, sizeof prefix - 1) == 0) \ + ? ((string += sizeof prefix - 1), 1) : 0) + +void +set_struct_debug_option (const char *spec) +{ + /* various labels for comparison */ + static char dfn_lbl[] = "dfn:", dir_lbl[] = "dir:", ind_lbl[] = "ind:"; + static char ord_lbl[] = "ord:", gen_lbl[] = "gen:"; + static char none_lbl[] = "none", any_lbl[] = "any"; + static char base_lbl[] = "base", sys_lbl[] = "sys"; + + enum debug_struct_file files = DINFO_STRUCT_FILE_ANY; + /* Default is to apply to as much as possible. */ + enum debug_info_usage usage = DINFO_USAGE_NUM_ENUMS; + int ord = 1, gen = 1; + + /* What usage? */ + if (MATCH (dfn_lbl, spec)) + usage = DINFO_USAGE_DFN; + else if (MATCH (dir_lbl, spec)) + usage = DINFO_USAGE_DIR_USE; + else if (MATCH (ind_lbl, spec)) + usage = DINFO_USAGE_IND_USE; + + /* Generics or not? */ + if (MATCH (ord_lbl, spec)) + gen = 0; + else if (MATCH (gen_lbl, spec)) + ord = 0; + + /* What allowable environment? */ + if (MATCH (none_lbl, spec)) + files = DINFO_STRUCT_FILE_NONE; + else if (MATCH (any_lbl, spec)) + files = DINFO_STRUCT_FILE_ANY; + else if (MATCH (sys_lbl, spec)) + files = DINFO_STRUCT_FILE_SYS; + else if (MATCH (base_lbl, spec)) + files = DINFO_STRUCT_FILE_BASE; + else + error ("argument %qs to %<-femit-struct-debug-detailed%> not recognized", + spec); + + /* Effect the specification. */ + if (usage == DINFO_USAGE_NUM_ENUMS) + { + if (ord) + { + debug_struct_ordinary[DINFO_USAGE_DFN] = files; + debug_struct_ordinary[DINFO_USAGE_DIR_USE] = files; + debug_struct_ordinary[DINFO_USAGE_IND_USE] = files; + } + if (gen) + { + debug_struct_generic[DINFO_USAGE_DFN] = files; + debug_struct_generic[DINFO_USAGE_DIR_USE] = files; + debug_struct_generic[DINFO_USAGE_IND_USE] = files; + } + } + else + { + if (ord) + debug_struct_ordinary[usage] = files; + if (gen) + debug_struct_generic[usage] = files; + } + + if (*spec == ',') + set_struct_debug_option (spec+1); + else + { + /* No more -femit-struct-debug-detailed specifications. + Do final checks. */ + if (*spec != '\0') + error ("argument %qs to %<-femit-struct-debug-detailed%> unknown", + spec); + if (debug_struct_ordinary[DINFO_USAGE_DIR_USE] + < debug_struct_ordinary[DINFO_USAGE_IND_USE] + || debug_struct_generic[DINFO_USAGE_DIR_USE] + < debug_struct_generic[DINFO_USAGE_IND_USE]) + error ("%<-femit-struct-debug-detailed=dir:...%> must allow at least" + " as much as %<-femit-struct-debug-detailed=ind:...%>"); + } +} + +/* Find the base name of a path, stripping off both directories and + a single final extension. */ +static int +base_of_path (const char *path, const char **base_out) +{ + const char *base = path; + const char *dot = 0; + const char *p = path; + char c = *p; + while (c) + { + if (IS_DIR_SEPARATOR(c)) + { + base = p + 1; + dot = 0; + } + else if (c == '.') + dot = p; + c = *++p; + } + if (!dot) + dot = p; + *base_out = base; + return dot - base; +} + +/* Match the base name of a file to the base name of a compilation unit. */ + +static const char *main_input_basename; +static int main_input_baselength; + +static int +matches_main_base (const char *path) +{ + /* Cache the last query. */ + static const char *last_path = NULL; + static int last_match = 0; + if (path != last_path) + { + const char *base; + int length = base_of_path (path, &base); + last_path = path; + last_match = (length == main_input_baselength + && memcmp (base, main_input_basename, length) == 0); + } + return last_match; +} + +#ifdef DEBUG_DEBUG_STRUCT + +static int +dump_struct_debug (tree type, enum debug_info_usage usage, + enum debug_struct_file criterion, int generic, + int matches, int result) +{ + /* Find the type name. */ + tree type_decl = TYPE_STUB_DECL (type); + tree t = type_decl; + const char *name = 0; + if (TREE_CODE (t) == TYPE_DECL) + t = DECL_NAME (t); + if (t) + name = IDENTIFIER_POINTER (t); + + fprintf (stderr, " struct %d %s %s %s %s %d %p %s\n", + criterion, + DECL_IN_SYSTEM_HEADER (type_decl) ? "sys" : "usr", + matches ? "bas" : "hdr", + generic ? "gen" : "ord", + usage == DINFO_USAGE_DFN ? ";" : + usage == DINFO_USAGE_DIR_USE ? "." : "*", + result, + (void*) type_decl, name); + return result; +} +#define DUMP_GSTRUCT(type, usage, criterion, generic, matches, result) \ + dump_struct_debug (type, usage, criterion, generic, matches, result) + +#else + +#define DUMP_GSTRUCT(type, usage, criterion, generic, matches, result) \ + (result) + +#endif + + +bool +should_emit_struct_debug (tree type, enum debug_info_usage usage) +{ + enum debug_struct_file criterion; + tree type_decl; + bool generic = lang_hooks.types.generic_p (type); + + if (generic) + criterion = debug_struct_generic[usage]; + else + criterion = debug_struct_ordinary[usage]; + + if (criterion == DINFO_STRUCT_FILE_NONE) + return DUMP_GSTRUCT (type, usage, criterion, generic, false, false); + if (criterion == DINFO_STRUCT_FILE_ANY) + return DUMP_GSTRUCT (type, usage, criterion, generic, false, true); + + type_decl = TYPE_STUB_DECL (type); + + if (criterion == DINFO_STRUCT_FILE_SYS && DECL_IN_SYSTEM_HEADER (type_decl)) + return DUMP_GSTRUCT (type, usage, criterion, generic, false, true); + + if (matches_main_base (DECL_SOURCE_FILE (type_decl))) + return DUMP_GSTRUCT (type, usage, criterion, generic, true, true); + return DUMP_GSTRUCT (type, usage, criterion, generic, false, false); +} + /* Nonzero means use GNU-only extensions in the generated symbolic debugging information. Currently, this only has an effect when write_symbols is set to DBX_DEBUG, XCOFF_DEBUG, or DWARF_DEBUG. */ @@ -82,9 +337,6 @@ enum symbol_visibility default_visibility = VISIBILITY_DEFAULT; /* Global visibility options. */ struct visibility_flags visibility_options; -/* Columns of --help display. */ -static unsigned int columns = 80; - /* What to print when a switch has no documentation. */ static const char undocumented_msg[] = N_("This switch lacks documentation"); @@ -93,114 +345,43 @@ static const char undocumented_msg[] = N_("This switch lacks documentation"); static bool profile_arc_flag_set, flag_profile_values_set; static bool flag_unroll_loops_set, flag_tracer_set; static bool flag_value_profile_transformations_set; -bool flag_speculative_prefetching_set; static bool flag_peel_loops_set, flag_branch_probabilities_set; +static bool flag_inline_functions_set, flag_ipa_cp_set, flag_ipa_cp_clone_set; +static bool flag_predictive_commoning_set, flag_unswitch_loops_set, flag_gcse_after_reload_set; + +/* Functions excluded from profiling. */ + +typedef char *char_p; /* For DEF_VEC_P. */ +DEF_VEC_P(char_p); +DEF_VEC_ALLOC_P(char_p,heap); + +static VEC(char_p,heap) *flag_instrument_functions_exclude_functions; +static VEC(char_p,heap) *flag_instrument_functions_exclude_files; + +typedef const char *const_char_p; /* For DEF_VEC_P. */ +DEF_VEC_P(const_char_p); +DEF_VEC_ALLOC_P(const_char_p,heap); + +static VEC(const_char_p,heap) *ignored_options; + +/* Language specific warning pass for unused results. */ +bool flag_warn_unused_result = false; /* Input file names. */ const char **in_fnames; unsigned num_in_fnames; -static size_t find_opt (const char *, int); -static int common_handle_option (size_t scode, const char *arg, int value); +static int common_handle_option (size_t scode, const char *arg, int value, + unsigned int lang_mask); static void handle_param (const char *); -static void set_Wextra (int); static unsigned int handle_option (const char **argv, unsigned int lang_mask); static char *write_langs (unsigned int lang_mask); static void complain_wrong_lang (const char *, const struct cl_option *, unsigned int lang_mask); static void handle_options (unsigned int, const char **, unsigned int); -static void wrap_help (const char *help, const char *item, unsigned int); -static void print_help (void); -static void print_param_help (void); -static void print_filtered_help (unsigned int flag); -static unsigned int print_switch (const char *text, unsigned int indent); static void set_debug_level (enum debug_info_type type, int extended, const char *arg); -/* Perform a binary search to find which option the command-line INPUT - matches. Returns its index in the option array, and N_OPTS - (cl_options_count) on failure. - - This routine is quite subtle. A normal binary search is not good - enough because some options can be suffixed with an argument, and - multiple sub-matches can occur, e.g. input of "-pedantic" matching - the initial substring of "-pedantic-errors". - - A more complicated example is -gstabs. It should match "-g" with - an argument of "stabs". Suppose, however, that the number and list - of switches are such that the binary search tests "-gen-decls" - before having tested "-g". This doesn't match, and as "-gen-decls" - is less than "-gstabs", it will become the lower bound of the - binary search range, and "-g" will never be seen. To resolve this - issue, opts.sh makes "-gen-decls" point, via the back_chain member, - to "-g" so that failed searches that end between "-gen-decls" and - the lexicographically subsequent switch know to go back and see if - "-g" causes a match (which it does in this example). - - This search is done in such a way that the longest match for the - front end in question wins. If there is no match for the current - front end, the longest match for a different front end is returned - (or N_OPTS if none) and the caller emits an error message. */ -static size_t -find_opt (const char *input, int lang_mask) -{ - size_t mn, mx, md, opt_len; - size_t match_wrong_lang; - int comp; - - mn = 0; - mx = cl_options_count; - - /* Find mn such this lexicographical inequality holds: - cl_options[mn] <= input < cl_options[mn + 1]. */ - while (mx - mn > 1) - { - md = (mn + mx) / 2; - opt_len = cl_options[md].opt_len; - comp = strncmp (input, cl_options[md].opt_text + 1, opt_len); - - if (comp < 0) - mx = md; - else - mn = md; - } - - /* This is the switch that is the best match but for a different - front end, or cl_options_count if there is no match at all. */ - match_wrong_lang = cl_options_count; - - /* Backtrace the chain of possible matches, returning the longest - one, if any, that fits best. With current GCC switches, this - loop executes at most twice. */ - do - { - const struct cl_option *opt = &cl_options[mn]; - - /* Is this switch a prefix of the input? */ - if (!strncmp (input, opt->opt_text + 1, opt->opt_len)) - { - /* If language is OK, and the match is exact or the switch - takes a joined argument, return it. */ - if ((opt->flags & lang_mask) - && (input[opt->opt_len] == '\0' || (opt->flags & CL_JOINED))) - return mn; - - /* If we haven't remembered a prior match, remember this - one. Any prior match is necessarily better. */ - if (match_wrong_lang == cl_options_count) - match_wrong_lang = mn; - } - - /* Try the next possibility. This is cl_options_count if there - are no more. */ - mn = opt->back_chain; - } - while (mn != cl_options_count); - - /* Return the best wrong match, or cl_options_count if none. */ - return match_wrong_lang; -} - /* If ARG is a non-negative integer made up solely of digits, return its value, otherwise return -1. */ static int @@ -229,7 +410,7 @@ write_langs (unsigned int mask) if (mask & (1U << n)) len += strlen (lang_name) + 1; - result = xmalloc (len); + result = XNEWVEC (char, len); len = 0; for (n = 0; (lang_name = lang_names[n]) != 0; n++) if (mask & (1U << n)) @@ -252,17 +433,58 @@ complain_wrong_lang (const char *text, const struct cl_option *option, { char *ok_langs, *bad_lang; + /* The LTO front end inherits all the options from the first front + end that was used. However, not all the original front end + options make sense in LTO. + + A real solution would be to filter this in collect2, but collect2 + does not have access to all the option attributes to know what to + filter. So, in lto1 we silently accept inherited flags and do + nothing about it. */ + if (lang_mask & CL_LTO) + return; + ok_langs = write_langs (option->flags); bad_lang = write_langs (lang_mask); /* Eventually this should become a hard error IMO. */ - warning ("command line option \"%s\" is valid for %s but not for %s", + warning (0, "command line option \"%s\" is valid for %s but not for %s", text, ok_langs, bad_lang); free (ok_langs); free (bad_lang); } +/* Buffer the unknown option described by the string OPT. Currently, + we only complain about unknown -Wno-* options if they may have + prevented a diagnostic. Otherwise, we just ignore them. + Note that if we do complain, it is only as a warning, not an error; + passing the compiler an unrecognised -Wno-* option should never + change whether the compilation succeeds or fails. */ + +static void postpone_unknown_option_warning(const char *opt) +{ + VEC_safe_push (const_char_p, heap, ignored_options, opt); +} + +/* Produce a warning for each option previously buffered. */ + +void print_ignored_options (void) +{ + location_t saved_loc = input_location; + + input_location = 0; + + while (!VEC_empty (const_char_p, ignored_options)) + { + const char *opt; + opt = VEC_pop (const_char_p, ignored_options); + warning (0, "unrecognized command line option \"%s\"", opt); + } + + input_location = saved_loc; +} + /* Handle the switch beginning at ARGV for the language indicated by LANG_MASK. Returns the number of switches consumed. */ static unsigned int @@ -277,21 +499,31 @@ handle_option (const char **argv, unsigned int lang_mask) opt = argv[0]; - /* Drop the "no-" from negative switches. */ - if ((opt[1] == 'W' || opt[1] == 'f') + opt_index = find_opt (opt + 1, lang_mask | CL_COMMON | CL_TARGET); + if (opt_index == cl_options_count + && (opt[1] == 'W' || opt[1] == 'f' || opt[1] == 'm') && opt[2] == 'n' && opt[3] == 'o' && opt[4] == '-') { + /* Drop the "no-" from negative switches. */ size_t len = strlen (opt) - 3; - dup = xmalloc (len + 1); + dup = XNEWVEC (char, len + 1); dup[0] = '-'; dup[1] = opt[1]; memcpy (dup + 2, opt + 5, len - 2 + 1); opt = dup; value = 0; + opt_index = find_opt (opt + 1, lang_mask | CL_COMMON | CL_TARGET); + if (opt_index == cl_options_count && opt[1] == 'W') + { + /* We don't generate warnings for unknown -Wno-* options + unless we issue diagnostics. */ + postpone_unknown_option_warning (argv[0]); + result = 1; + goto done; + } } - opt_index = find_opt (opt + 1, lang_mask | CL_COMMON); if (opt_index == cl_options_count) goto done; @@ -305,6 +537,14 @@ handle_option (const char **argv, unsigned int lang_mask) /* We've recognized this switch. */ result = 1; + /* Check to see if the option is disabled for this configuration. */ + if (option->flags & CL_DISABLED) + { + error ("command line option %qs" + " is not supported by this configuration", opt); + goto done; + } + /* Sort out any argument the switch takes. */ if (option->flags & CL_JOINED) { @@ -335,11 +575,20 @@ handle_option (const char **argv, unsigned int lang_mask) /* Now we've swallowed any potential argument, complain if this is a switch for a different front end. */ - if (!(option->flags & (lang_mask | CL_COMMON))) + if (!(option->flags & (lang_mask | CL_COMMON | CL_TARGET))) { complain_wrong_lang (argv[0], option, lang_mask); goto done; } + else if ((option->flags & CL_TARGET) + && (option->flags & CL_LANG_ALL) + && !(option->flags & lang_mask)) + { + /* Complain for target flag language mismatches if any languages + are specified. */ + complain_wrong_lang (argv[0], option, lang_mask); + goto done; + } if (arg == NULL && (option->flags & (CL_JOINED | CL_SEPARATE))) { @@ -361,25 +610,31 @@ handle_option (const char **argv, unsigned int lang_mask) } if (option->flag_var) + set_option (option, value, arg); + + if (option->flags & lang_mask) { - if (option->has_set_value) - { - if (value) - *option->flag_var = option->set_value; - else - *option->flag_var = !option->set_value; - } + if (lang_hooks.handle_option (opt_index, arg, value) == 0) + result = 0; else - *option->flag_var = value; + lto_register_user_option (opt_index, arg, value, lang_mask); } - - if (option->flags & lang_mask) - if (lang_hooks.handle_option (opt_index, arg, value) == 0) - result = 0; if (result && (option->flags & CL_COMMON)) - if (common_handle_option (opt_index, arg, value) == 0) - result = 0; + { + if (common_handle_option (opt_index, arg, value, lang_mask) == 0) + result = 0; + else + lto_register_user_option (opt_index, arg, value, CL_COMMON); + } + + if (result && (option->flags & CL_TARGET)) + { + if (!targetm.handle_option (opt_index, arg, value)) + result = 0; + else + lto_register_user_option (opt_index, arg, value, CL_TARGET); + } done: if (dup) @@ -387,6 +642,95 @@ handle_option (const char **argv, unsigned int lang_mask) return result; } +/* Handle FILENAME from the command line. */ +static void +add_input_filename (const char *filename) +{ + num_in_fnames++; + in_fnames = XRESIZEVEC (const char *, in_fnames, num_in_fnames); + in_fnames[num_in_fnames - 1] = filename; +} + +/* Add comma-separated strings to a char_p vector. */ + +static void +add_comma_separated_to_vector (VEC(char_p,heap) **pvec, const char* arg) +{ + char *tmp; + char *r; + char *w; + char *token_start; + + /* We never free this string. */ + tmp = xstrdup (arg); + + r = tmp; + w = tmp; + token_start = tmp; + + while (*r != '\0') + { + if (*r == ',') + { + *w++ = '\0'; + ++r; + VEC_safe_push (char_p, heap, *pvec, token_start); + token_start = w; + } + if (*r == '\\' && r[1] == ',') + { + *w++ = ','; + r += 2; + } + else + *w++ = *r++; + } + if (*token_start != '\0') + VEC_safe_push (char_p, heap, *pvec, token_start); +} + +/* Return whether we should exclude FNDECL from instrumentation. */ + +bool +flag_instrument_functions_exclude_p (tree fndecl) +{ + if (VEC_length (char_p, flag_instrument_functions_exclude_functions) > 0) + { + const char *name; + int i; + char *s; + + name = lang_hooks.decl_printable_name (fndecl, 0); + for (i = 0; + VEC_iterate (char_p, flag_instrument_functions_exclude_functions, + i, s); + ++i) + { + if (strstr (name, s) != NULL) + return true; + } + } + + if (VEC_length (char_p, flag_instrument_functions_exclude_files) > 0) + { + const char *name; + int i; + char *s; + + name = DECL_SOURCE_FILE (fndecl); + for (i = 0; + VEC_iterate (char_p, flag_instrument_functions_exclude_files, i, s); + ++i) + { + if (strstr (name, s) != NULL) + return true; + } + } + + return false; +} + + /* Decode and handle the vector of command line options. LANG_MASK contains has a single bit set representing the current language. */ @@ -403,7 +747,11 @@ handle_options (unsigned int argc, const char **argv, unsigned int lang_mask) if (opt[0] != '-' || opt[1] == '\0') { if (main_input_filename == NULL) - main_input_filename = opt; + { + main_input_filename = opt; + main_input_baselength + = base_of_path (main_input_filename, &main_input_basename); + } add_input_filename (opt); n = 1; continue; @@ -419,26 +767,40 @@ handle_options (unsigned int argc, const char **argv, unsigned int lang_mask) } } -/* Handle FILENAME from the command line. */ -void -add_input_filename (const char *filename) -{ - num_in_fnames++; - in_fnames = xrealloc (in_fnames, num_in_fnames * sizeof (in_fnames[0])); - in_fnames[num_in_fnames - 1] = filename; -} - /* Parse command line options and set default flag values. Do minimal options processing. */ void decode_options (unsigned int argc, const char **argv) { - unsigned int i, lang_mask; + static bool first_time_p = true; + static int initial_min_crossjump_insns; + static int initial_max_fields_for_field_sensitive; + static int initial_loop_invariant_max_bbs_in_loop; + static unsigned int initial_lang_mask; - /* Perform language-specific options initialization. */ - lang_mask = lang_hooks.init_options (argc, argv); + unsigned int i, lang_mask; + int opt1; + int opt2; + int opt3; + int opt1_max; - lang_hooks.initialize_diagnostics (global_dc); + if (first_time_p) + { + /* Perform language-specific options initialization. */ + initial_lang_mask = lang_mask = lang_hooks.init_options (argc, argv); + + lang_hooks.initialize_diagnostics (global_dc); + + /* Save initial values of parameters we reset. */ + initial_min_crossjump_insns + = compiler_params[PARAM_MIN_CROSSJUMP_INSNS].value; + initial_max_fields_for_field_sensitive + = compiler_params[PARAM_MAX_FIELDS_FOR_FIELD_SENSITIVE].value; + initial_loop_invariant_max_bbs_in_loop + = compiler_params[PARAM_LOOP_INVARIANT_MAX_BBS_IN_LOOP].value; + } + else + lang_mask = initial_lang_mask; /* Scan to see what optimization level has been specified. That will determine the default value of many flags. */ @@ -467,129 +829,140 @@ decode_options (unsigned int argc, const char **argv) if (optimize_val != -1) { optimize = optimize_val; + if ((unsigned int) optimize > 255) + optimize = 255; optimize_size = 0; } } } } - if (!optimize) - { - flag_merge_constants = 0; - } + /* Use priority coloring if cover classes is not defined for the + target. */ + if (targetm.ira_cover_classes == NULL) + flag_ira_algorithm = IRA_ALGORITHM_PRIORITY; - if (optimize >= 1) - { - flag_defer_pop = 1; - flag_thread_jumps = 1; + /* -O1 optimizations. */ + opt1 = (optimize >= 1); + flag_defer_pop = opt1; #ifdef DELAY_SLOTS - flag_delayed_branch = 1; + flag_delayed_branch = opt1; #endif #ifdef CAN_DEBUG_WITHOUT_FP - flag_omit_frame_pointer = 1; + flag_omit_frame_pointer = opt1; #endif - flag_guess_branch_prob = 1; - flag_cprop_registers = 1; - flag_loop_optimize = 1; - flag_if_conversion = 1; - flag_if_conversion2 = 1; - flag_tree_ccp = 1; - flag_tree_dce = 1; - flag_tree_dom = 1; - flag_tree_dse = 1; - flag_tree_pre = 1; - flag_tree_ter = 1; - flag_tree_live_range_split = 1; - flag_tree_sra = 1; - flag_tree_copyrename = 1; - flag_tree_fre = 1; - - if (!optimize_size) - { - /* Loop header copying usually increases size of the code. This used - not to be true, since quite often it is possible to verify that - the condition is satisfied in the first iteration and therefore - to eliminate it. Jump threading handles these cases now. */ - flag_tree_ch = 1; - } - } - - if (optimize >= 2) - { - flag_crossjumping = 1; - flag_optimize_sibling_calls = 1; - flag_cse_follow_jumps = 1; - flag_cse_skip_blocks = 1; - flag_gcse = 1; - flag_expensive_optimizations = 1; - flag_strength_reduce = 1; - flag_rerun_cse_after_loop = 1; - flag_rerun_loop_opt = 1; - flag_caller_saves = 1; - flag_force_mem = 1; - flag_peephole2 = 1; + flag_guess_branch_prob = opt1; + flag_cprop_registers = opt1; + flag_forward_propagate = opt1; + flag_if_conversion = opt1; + flag_if_conversion2 = opt1; + flag_ipa_pure_const = opt1; + flag_ipa_reference = opt1; + flag_merge_constants = opt1; + flag_split_wide_types = opt1; + flag_tree_ccp = opt1; + flag_tree_dce = opt1; + flag_tree_dom = opt1; + flag_tree_dse = opt1; + flag_tree_ter = opt1; + flag_tree_sra = opt1; + flag_tree_copyrename = opt1; + flag_tree_fre = opt1; + flag_tree_copy_prop = opt1; + flag_tree_sink = opt1; + flag_tree_ch = opt1; + + /* -O2 optimizations. */ + opt2 = (optimize >= 2); + flag_inline_small_functions = opt2; + flag_indirect_inlining = opt2; + flag_thread_jumps = opt2; + flag_crossjumping = opt2; + flag_optimize_sibling_calls = opt2; + flag_cse_follow_jumps = opt2; + flag_gcse = opt2; + flag_expensive_optimizations = opt2; + flag_rerun_cse_after_loop = opt2; + flag_caller_saves = opt2; + flag_peephole2 = opt2; #ifdef INSN_SCHEDULING - flag_schedule_insns = 1; - flag_schedule_insns_after_reload = 1; + /* Only run the pre-regalloc scheduling pass if optimizing for speed. */ + flag_schedule_insns = opt2 && ! optimize_size; + flag_schedule_insns_after_reload = opt2; #endif - flag_regmove = 1; - flag_strict_aliasing = 1; - flag_delete_null_pointer_checks = 1; - flag_reorder_blocks = 1; - flag_reorder_functions = 1; - flag_unit_at_a_time = 1; - } + flag_regmove = opt2; + flag_strict_aliasing = opt2; + flag_strict_overflow = opt2; + flag_reorder_blocks = opt2; + flag_reorder_functions = opt2; + flag_tree_vrp = opt2; + flag_tree_builtin_call_dce = opt2; + flag_tree_pre = opt2; + flag_tree_switch_conversion = opt2; + flag_ipa_cp = opt2; + flag_ipa_sra = opt2; + + /* Track fields in field-sensitive alias analysis. */ + set_param_value ("max-fields-for-field-sensitive", + (opt2) ? 100 : initial_max_fields_for_field_sensitive); + + /* For -O1 only do loop invariant motion for very small loops. */ + set_param_value ("loop-invariant-max-bbs-in-loop", + (opt2) ? initial_loop_invariant_max_bbs_in_loop : 1000); + + /* -O3 optimizations. */ + opt3 = (optimize >= 3); + flag_predictive_commoning = opt3; + flag_inline_functions = opt3; + flag_unswitch_loops = opt3; + flag_gcse_after_reload = opt3; + flag_tree_vectorize = opt3; + flag_ipa_cp_clone = opt3; + if (flag_ipa_cp_clone) + flag_ipa_cp = 1; + + /* Just -O1/-O0 optimizations. */ + opt1_max = (optimize <= 1); + align_loops = opt1_max; + align_jumps = opt1_max; + align_labels = opt1_max; + align_functions = opt1_max; - if (optimize >= 3) + if (optimize_size) { + /* Inlining of functions reducing size is a good idea regardless of them + being declared inline. */ flag_inline_functions = 1; - flag_unswitch_loops = 1; - flag_gcse_after_reload = 1; - } - if (optimize < 2 || optimize_size) - { - align_loops = 1; - align_jumps = 1; - align_labels = 1; - align_functions = 1; - - /* Don't reorder blocks when optimizing for size because extra - jump insns may be created; also barrier may create extra padding. - - More correctly we should have a block reordering mode that tried - to minimize the combined size of all the jumps. This would more - or less automatically remove extra jumps, but would also try to - use more short jumps instead of long jumps. */ - flag_reorder_blocks = 0; - flag_reorder_blocks_and_partition = 0; + /* Basic optimization options. */ + optimize_size = 1; + if (optimize > 2) + optimize = 2; + + /* We want to crossjump as much as possible. */ + set_param_value ("min-crossjump-insns", 1); } + else + set_param_value ("min-crossjump-insns", initial_min_crossjump_insns); - if (optimize_size) + if (first_time_p) { - /* Inlining of very small functions usually reduces total size. */ - set_param_value ("max-inline-insns-single", 5); - set_param_value ("max-inline-insns-auto", 5); - set_param_value ("max-inline-insns-rtl", 10); - flag_inline_functions = 1; + /* Initialize whether `char' is signed. */ + flag_signed_char = DEFAULT_SIGNED_CHAR; + /* Set this to a special "uninitialized" value. The actual default is + set after target options have been processed. */ + flag_short_enums = 2; + + /* Initialize target_flags before OPTIMIZATION_OPTIONS so the latter can + modify it. */ + target_flags = targetm.default_target_flags; + + /* Some targets have ABI-specified unwind tables. */ + flag_unwind_tables = targetm.unwind_tables_default; } - /* Initialize whether `char' is signed. */ - flag_signed_char = DEFAULT_SIGNED_CHAR; - /* Set this to a special "uninitialized" value. The actual default is set - after target options have been processed. */ - flag_short_enums = 2; - - /* Initialize target_flags before OPTIMIZATION_OPTIONS so the latter can - modify it. */ - target_flags = 0; - set_target_switch (""); - - /* Unwind tables are always present when a target has ABI-specified unwind - tables, so the default should be ON. */ -#ifdef TARGET_UNWIND_INFO - flag_unwind_tables = TARGET_UNWIND_INFO; -#endif + /* Clear any options currently held for LTO. */ + lto_clear_user_options (); #ifdef OPTIMIZATION_OPTIONS /* Allow default optimizations to be specified on a per-machine basis. */ @@ -598,63 +971,480 @@ decode_options (unsigned int argc, const char **argv) handle_options (argc, argv, lang_mask); - if (flag_pie) - flag_pic = flag_pie; - if (flag_pic && !flag_pie) - flag_shlib = 1; + if (dump_base_name && ! IS_ABSOLUTE_PATH (dump_base_name)) + { + /* First try to make DUMP_BASE_NAME relative to the DUMP_DIR_NAME + directory. Then try to make DUMP_BASE_NAME relative to the + AUX_BASE_NAME directory, typically the directory to contain + the object file. */ + if (dump_dir_name) + dump_base_name = concat (dump_dir_name, dump_base_name, NULL); + else if (aux_base_name) + { + const char *aux_base; - if (flag_no_inline == 2) - flag_no_inline = 0; - else - flag_really_no_inline = flag_no_inline; + base_of_path (aux_base_name, &aux_base); + if (aux_base_name != aux_base) + { + int dir_len = aux_base - aux_base_name; + char *new_dump_base_name = + XNEWVEC (char, strlen(dump_base_name) + dir_len + 1); + + /* Copy directory component from AUX_BASE_NAME. */ + memcpy (new_dump_base_name, aux_base_name, dir_len); + /* Append existing DUMP_BASE_NAME. */ + strcpy (new_dump_base_name + dir_len, dump_base_name); + dump_base_name = new_dump_base_name; + } + } + } + + /* Handle related options for unit-at-a-time, toplevel-reorder, and + section-anchors. */ + if (!flag_unit_at_a_time) + { + if (flag_section_anchors == 1) + error ("Section anchors must be disabled when unit-at-a-time " + "is disabled."); + flag_section_anchors = 0; + if (flag_toplevel_reorder == 1) + error ("Toplevel reorder must be disabled when unit-at-a-time " + "is disabled."); + flag_toplevel_reorder = 0; + } + /* Unless the user has asked for section anchors, we disable toplevel + reordering at -O0 to disable transformations that might be surprising + to end users and to get -fno-toplevel-reorder tested. */ + if (!optimize && flag_toplevel_reorder == 2 && flag_section_anchors != 1) + { + flag_toplevel_reorder = 0; + flag_section_anchors = 0; + } + if (!flag_toplevel_reorder) + { + if (flag_section_anchors == 1) + error ("section anchors must be disabled when toplevel reorder" + " is disabled"); + flag_section_anchors = 0; + } + + if (first_time_p) + { + if (flag_pie) + flag_pic = flag_pie; + if (flag_pic && !flag_pie) + flag_shlib = 1; + first_time_p = false; + } - /* Set flag_no_inline before the post_options () hook. The C front - ends use it to determine tree inlining defaults. FIXME: such - code should be lang-independent when all front ends use tree - inlining, in which case it, and this condition, should be moved - to the top of process_options() instead. */ if (optimize == 0) { /* Inlining does not work if not optimizing, so force it not to be done. */ - flag_no_inline = 1; warn_inline = 0; - - /* The c_decode_option function and decode_option hook set - this to `2' if -Wall is used, so we can avoid giving out - lots of errors for people who don't realize what -Wall does. */ - if (warn_uninitialized == 1) - warning ("-Wuninitialized is not supported without -O"); + flag_no_inline = 1; } - if (flag_really_no_inline == 2) - flag_really_no_inline = flag_no_inline; - /* The optimization to partition hot and cold basic blocks into separate sections of the .o and executable files does not work (currently) - with exception handling. If flag_exceptions is turned on we need to + with exception handling. This is because there is no support for + generating unwind info. If flag_exceptions is turned on we need to turn off the partitioning optimization. */ - if (flag_exceptions && flag_reorder_blocks_and_partition) + if (flag_exceptions && flag_reorder_blocks_and_partition + && (USING_SJLJ_EXCEPTIONS +#ifdef TARGET_UNWIND_INFO + || 1 +#endif + )) { - warning - ("-freorder-blocks-and-partition does not work with exceptions"); + inform (input_location, + "-freorder-blocks-and-partition does not work with exceptions on this architecture"); flag_reorder_blocks_and_partition = 0; flag_reorder_blocks = 1; } - /* The optimization to partition hot and cold basic blocks into - separate sections of the .o and executable files does not currently - work correctly with DWARF debugging turned on. Until this is fixed - we will disable the optimization when DWARF debugging is set. */ - - if (flag_reorder_blocks_and_partition && write_symbols == DWARF2_DEBUG) + /* If user requested unwind info, then turn off the partitioning + optimization. */ + + if (flag_unwind_tables && ! targetm.unwind_tables_default + && flag_reorder_blocks_and_partition + && (USING_SJLJ_EXCEPTIONS +#ifdef TARGET_UNWIND_INFO + || 1 +#endif + )) { - warning - ("-freorder-blocks-and-partition does not work with -g (currently)"); + inform (input_location, + "-freorder-blocks-and-partition does not support unwind info on this architecture"); flag_reorder_blocks_and_partition = 0; flag_reorder_blocks = 1; } + + /* If the target requested unwind info, then turn off the partitioning + optimization with a different message. Likewise, if the target does not + support named sections. */ + + if (flag_reorder_blocks_and_partition + && (!targetm.have_named_sections + || (flag_unwind_tables && targetm.unwind_tables_default + && (USING_SJLJ_EXCEPTIONS +#ifdef TARGET_UNWIND_INFO + || 1 +#endif + )))) + { + inform (input_location, + "-freorder-blocks-and-partition does not work on this architecture"); + flag_reorder_blocks_and_partition = 0; + flag_reorder_blocks = 1; + } + + /* Pipelining of outer loops is only possible when general pipelining + capabilities are requested. */ + if (!flag_sel_sched_pipelining) + flag_sel_sched_pipelining_outer_loops = 0; + + if (!targetm.ira_cover_classes + && flag_ira_algorithm == IRA_ALGORITHM_CB) + { + inform (input_location, + "-fira-algorithm=CB does not work on this architecture"); + flag_ira_algorithm = IRA_ALGORITHM_PRIORITY; + } + + if (flag_conserve_stack) + { + if (!PARAM_SET_P (PARAM_LARGE_STACK_FRAME)) + PARAM_VALUE (PARAM_LARGE_STACK_FRAME) = 100; + if (!PARAM_SET_P (PARAM_STACK_FRAME_GROWTH)) + PARAM_VALUE (PARAM_STACK_FRAME_GROWTH) = 40; + } + + if (flag_lto || flag_whopr) + { +#ifdef ENABLE_LTO + flag_generate_lto = 1; + + /* When generating IL, do not operate in whole-program mode. + Otherwise, symbols will be privatized too early, causing link + errors later. */ + flag_whole_program = 0; +#else + error ("LTO support has not been enabled in this configuration"); +#endif + } + + /* Reconcile -flto and -fwhopr. Set additional flags as appropriate and + check option consistency. */ + if (flag_lto && flag_whopr) + error ("-flto and -fwhopr are mutually exclusive"); +} + +#define LEFT_COLUMN 27 + +/* Output ITEM, of length ITEM_WIDTH, in the left column, + followed by word-wrapped HELP in a second column. */ +static void +wrap_help (const char *help, + const char *item, + unsigned int item_width, + unsigned int columns) +{ + unsigned int col_width = LEFT_COLUMN; + unsigned int remaining, room, len; + + remaining = strlen (help); + + do + { + room = columns - 3 - MAX (col_width, item_width); + if (room > columns) + room = 0; + len = remaining; + + if (room < len) + { + unsigned int i; + + for (i = 0; help[i]; i++) + { + if (i >= room && len != remaining) + break; + if (help[i] == ' ') + len = i; + else if ((help[i] == '-' || help[i] == '/') + && help[i + 1] != ' ' + && i > 0 && ISALPHA (help[i - 1])) + len = i + 1; + } + } + + printf( " %-*.*s %.*s\n", col_width, item_width, item, len, help); + item_width = 0; + while (help[len] == ' ') + len++; + help += len; + remaining -= len; + } + while (remaining); +} + +/* Print help for a specific front-end, etc. */ +static void +print_filtered_help (unsigned int include_flags, + unsigned int exclude_flags, + unsigned int any_flags, + unsigned int columns) +{ + unsigned int i; + const char *help; + static char *printed = NULL; + bool found = false; + bool displayed = false; + + if (include_flags == CL_PARAMS) + { + for (i = 0; i < LAST_PARAM; i++) + { + const char *param = compiler_params[i].option; + + help = compiler_params[i].help; + if (help == NULL || *help == '\0') + { + if (exclude_flags & CL_UNDOCUMENTED) + continue; + help = undocumented_msg; + } + + /* Get the translation. */ + help = _(help); + + wrap_help (help, param, strlen (param), columns); + } + putchar ('\n'); + return; + } + + if (!printed) + printed = XCNEWVAR (char, cl_options_count); + + for (i = 0; i < cl_options_count; i++) + { + static char new_help[128]; + const struct cl_option *option = cl_options + i; + unsigned int len; + const char *opt; + const char *tab; + + if (include_flags == 0 + || ((option->flags & include_flags) != include_flags)) + { + if ((option->flags & any_flags) == 0) + continue; + } + + /* Skip unwanted switches. */ + if ((option->flags & exclude_flags) != 0) + continue; + + found = true; + /* Skip switches that have already been printed. */ + if (printed[i]) + continue; + + printed[i] = true; + + help = option->help; + if (help == NULL) + { + if (exclude_flags & CL_UNDOCUMENTED) + continue; + help = undocumented_msg; + } + + /* Get the translation. */ + help = _(help); + + /* Find the gap between the name of the + option and its descriptive text. */ + tab = strchr (help, '\t'); + if (tab) + { + len = tab - help; + opt = help; + help = tab + 1; + } + else + { + opt = option->opt_text; + len = strlen (opt); + } + + /* With the -Q option enabled we change the descriptive text associated + with an option to be an indication of its current setting. */ + if (!quiet_flag) + { + if (len < (LEFT_COLUMN + 2)) + strcpy (new_help, "\t\t"); + else + strcpy (new_help, "\t"); + + if (option->flag_var != NULL) + { + if (option->flags & CL_JOINED) + { + if (option->var_type == CLVC_STRING) + { + if (* (const char **) option->flag_var != NULL) + snprintf (new_help + strlen (new_help), + sizeof (new_help) - strlen (new_help), + * (const char **) option->flag_var); + } + else + sprintf (new_help + strlen (new_help), + "%#x", * (int *) option->flag_var); + } + else + strcat (new_help, option_enabled (i) + ? _("[enabled]") : _("[disabled]")); + } + + help = new_help; + } + + wrap_help (help, opt, len, columns); + displayed = true; + } + + if (! found) + { + unsigned int langs = include_flags & CL_LANG_ALL; + + if (langs == 0) + printf (_(" No options with the desired characteristics were found\n")); + else + { + unsigned int i; + + /* PR 31349: Tell the user how to see all of the + options supported by a specific front end. */ + for (i = 0; (1U << i) < CL_LANG_ALL; i ++) + if ((1U << i) & langs) + printf (_(" None found. Use --help=%s to show *all* the options supported by the %s front-end\n"), + lang_names[i], lang_names[i]); + } + + } + else if (! displayed) + printf (_(" All options with the desired characteristics have already been displayed\n")); + + putchar ('\n'); +} + +/* Display help for a specified type of option. + The options must have ALL of the INCLUDE_FLAGS set + ANY of the flags in the ANY_FLAGS set + and NONE of the EXCLUDE_FLAGS set. */ +static void +print_specific_help (unsigned int include_flags, + unsigned int exclude_flags, + unsigned int any_flags) +{ + unsigned int all_langs_mask = (1U << cl_lang_count) - 1; + const char * description = NULL; + const char * descrip_extra = ""; + size_t i; + unsigned int flag; + static unsigned int columns = 0; + + /* Sanity check: Make sure that we do not have more + languages than we have bits available to enumerate them. */ + gcc_assert ((1U << cl_lang_count) < CL_MIN_OPTION_CLASS); + + /* If we have not done so already, obtain + the desired maximum width of the output. */ + if (columns == 0) + { + const char *p; + + GET_ENVIRONMENT (p, "COLUMNS"); + if (p != NULL) + { + int value = atoi (p); + + if (value > 0) + columns = value; + } + + if (columns == 0) + /* Use a reasonable default. */ + columns = 80; + } + + /* Decide upon the title for the options that we are going to display. */ + for (i = 0, flag = 1; flag <= CL_MAX_OPTION_CLASS; flag <<= 1, i ++) + { + switch (flag & include_flags) + { + case 0: + break; + + case CL_TARGET: + description = _("The following options are target specific"); + break; + case CL_WARNING: + description = _("The following options control compiler warning messages"); + break; + case CL_OPTIMIZATION: + description = _("The following options control optimizations"); + break; + case CL_COMMON: + description = _("The following options are language-independent"); + break; + case CL_PARAMS: + description = _("The --param option recognizes the following as parameters"); + break; + default: + if (i >= cl_lang_count) + break; + if (exclude_flags & all_langs_mask) + description = _("The following options are specific to just the language "); + else + description = _("The following options are supported by the language "); + descrip_extra = lang_names [i]; + break; + } + } + + if (description == NULL) + { + if (any_flags == 0) + { + if (include_flags & CL_UNDOCUMENTED) + description = _("The following options are not documented"); + else if (include_flags & CL_SEPARATE) + description = _("The following options take separate arguments"); + else if (include_flags & CL_JOINED) + description = _("The following options take joined arguments"); + else + { + internal_error ("unrecognized include_flags 0x%x passed to print_specific_help", + include_flags); + return; + } + } + else + { + if (any_flags & all_langs_mask) + description = _("The following options are language-related"); + else + description = _("The following options are language-independent"); + } + } + + printf ("%s%s:\n", description, descrip_extra); + print_filtered_help (include_flags, exclude_flags, any_flags, columns); } /* Handle target- and language-independent options. Return zero to @@ -663,28 +1453,174 @@ decode_options (unsigned int argc, const char **argv) VALUE assigned to a variable, it happens automatically. */ static int -common_handle_option (size_t scode, const char *arg, int value) +common_handle_option (size_t scode, const char *arg, int value, + unsigned int lang_mask) { + static bool verbose = false; enum opt_code code = (enum opt_code) scode; switch (code) { - case OPT__help: - print_help (); - exit_after_options = true; - break; - case OPT__param: handle_param (arg); break; + case OPT_v: + verbose = true; + break; + + case OPT_fhelp: + case OPT__help: + { + unsigned int all_langs_mask = (1U << cl_lang_count) - 1; + unsigned int undoc_mask; + unsigned int i; + + undoc_mask = (verbose | extra_warnings) ? 0 : CL_UNDOCUMENTED; + /* First display any single language specific options. */ + for (i = 0; i < cl_lang_count; i++) + print_specific_help + (1U << i, (all_langs_mask & (~ (1U << i))) | undoc_mask, 0); + /* Next display any multi language specific options. */ + print_specific_help (0, undoc_mask, all_langs_mask); + /* Then display any remaining, non-language options. */ + for (i = CL_MIN_OPTION_CLASS; i <= CL_MAX_OPTION_CLASS; i <<= 1) + print_specific_help (i, undoc_mask, 0); + exit_after_options = true; + break; + } + + case OPT_ftarget_help: case OPT__target_help: - display_target_options (); + print_specific_help (CL_TARGET, CL_UNDOCUMENTED, 0); exit_after_options = true; + + /* Allow the target a chance to give the user some additional information. */ + if (targetm.target_help) + targetm.target_help (); break; + case OPT_fhelp_: + case OPT__help_: + { + const char * a = arg; + unsigned int include_flags = 0; + /* Note - by default we include undocumented options when listing + specific classes. If you only want to see documented options + then add ",^undocumented" to the --help= option. E.g.: + + --help=target,^undocumented */ + unsigned int exclude_flags = 0; + + /* Walk along the argument string, parsing each word in turn. + The format is: + arg = [^]{word}[,{arg}] + word = {optimizers|target|warnings|undocumented| + params|common|} */ + while (* a != 0) + { + static struct + { + const char * string; + unsigned int flag; + } + specifics[] = + { + { "optimizers", CL_OPTIMIZATION }, + { "target", CL_TARGET }, + { "warnings", CL_WARNING }, + { "undocumented", CL_UNDOCUMENTED }, + { "params", CL_PARAMS }, + { "joined", CL_JOINED }, + { "separate", CL_SEPARATE }, + { "common", CL_COMMON }, + { NULL, 0 } + }; + unsigned int * pflags; + const char * comma; + unsigned int lang_flag, specific_flag; + unsigned int len; + unsigned int i; + + if (* a == '^') + { + ++ a; + pflags = & exclude_flags; + } + else + pflags = & include_flags; + + comma = strchr (a, ','); + if (comma == NULL) + len = strlen (a); + else + len = comma - a; + if (len == 0) + { + a = comma + 1; + continue; + } + + /* Check to see if the string matches an option class name. */ + for (i = 0, specific_flag = 0; specifics[i].string != NULL; i++) + if (strncasecmp (a, specifics[i].string, len) == 0) + { + specific_flag = specifics[i].flag; + break; + } + + /* Check to see if the string matches a language name. + Note - we rely upon the alpha-sorted nature of the entries in + the lang_names array, specifically that shorter names appear + before their longer variants. (i.e. C before C++). That way + when we are attempting to match --help=c for example we will + match with C first and not C++. */ + for (i = 0, lang_flag = 0; i < cl_lang_count; i++) + if (strncasecmp (a, lang_names[i], len) == 0) + { + lang_flag = 1U << i; + break; + } + + if (specific_flag != 0) + { + if (lang_flag == 0) + * pflags |= specific_flag; + else + { + /* The option's argument matches both the start of a + language name and the start of an option class name. + We have a special case for when the user has + specified "--help=c", but otherwise we have to issue + a warning. */ + if (strncasecmp (a, "c", len) == 0) + * pflags |= lang_flag; + else + fnotice (stderr, + "warning: --help argument %.*s is ambiguous, please be more specific\n", + len, a); + } + } + else if (lang_flag != 0) + * pflags |= lang_flag; + else + fnotice (stderr, + "warning: unrecognized argument to --help= option: %.*s\n", + len, a); + + if (comma == NULL) + break; + a = comma + 1; + } + + if (include_flags) + print_specific_help (include_flags, exclude_flags, 0); + exit_after_options = true; + break; + } + + case OPT_fversion: case OPT__version: - print_version (stderr, ""); exit_after_options = true; break; @@ -698,27 +1634,45 @@ common_handle_option (size_t scode, const char *arg, int value) /* Currently handled in a prescan. */ break; - case OPT_W: - /* For backward compatibility, -W is the same as -Wextra. */ - set_Wextra (value); - break; - - case OPT_Wextra: - set_Wextra (value); + case OPT_Werror_: + enable_warning_as_error (arg, value, lang_mask); break; case OPT_Wlarger_than_: + /* This form corresponds to -Wlarger-than-. + Kept for backward compatibility. + Don't use it as the first argument of warning(). */ + + case OPT_Wlarger_than_eq: larger_than_size = value; warn_larger_than = value != -1; break; + case OPT_Wframe_larger_than_: + frame_larger_than_size = value; + warn_frame_larger_than = value != -1; + break; + case OPT_Wstrict_aliasing: + set_Wstrict_aliasing (value); + break; + case OPT_Wstrict_aliasing_: warn_strict_aliasing = value; break; + case OPT_Wstrict_overflow: + warn_strict_overflow = (value + ? (int) WARN_STRICT_OVERFLOW_CONDITIONAL + : 0); + break; + + case OPT_Wstrict_overflow_: + warn_strict_overflow = value; + break; + case OPT_Wunused: - set_Wunused (value); + warn_unused = value; break; case OPT_aux_info: @@ -748,6 +1702,10 @@ common_handle_option (size_t scode, const char *arg, int value) dump_base_name = arg; break; + case OPT_dumpdir: + dump_dir_name = arg; + break; + case OPT_falign_functions_: align_functions = value; break; @@ -776,6 +1734,18 @@ common_handle_option (size_t scode, const char *arg, int value) fix_register (arg, 0, 0); break; + case OPT_fdbg_cnt_: + dbg_cnt_process_opt (arg); + break; + + case OPT_fdbg_cnt_list: + dbg_cnt_list_all_counters (); + break; + + case OPT_fdebug_prefix_map_: + add_debug_prefix_map (arg); + break; + case OPT_fdiagnostics_show_location_: if (!strcmp (arg, "once")) diagnostic_prefixing_rule (global_dc) = DIAGNOSTICS_SHOW_PREFIX_ONCE; @@ -786,15 +1756,32 @@ common_handle_option (size_t scode, const char *arg, int value) return 0; break; + case OPT_fdiagnostics_show_option: + global_dc->show_option_requested = true; + break; + case OPT_fdump_: if (!dump_switch_p (arg)) return 0; break; + case OPT_fexcess_precision_: + if (!strcmp (arg, "fast")) + flag_excess_precision_cmdline = EXCESS_PRECISION_FAST; + else if (!strcmp (arg, "standard")) + flag_excess_precision_cmdline = EXCESS_PRECISION_STANDARD; + else + error ("unknown excess precision style \"%s\"", arg); + break; + case OPT_ffast_math: set_fast_math_flags (value); break; + case OPT_funsafe_math_optimizations: + set_unsafe_math_optimizations_flags (value); + break; + case OPT_ffixed_: fix_register (arg, 1, 1); break; @@ -803,21 +1790,69 @@ common_handle_option (size_t scode, const char *arg, int value) case OPT_finline_limit_eq: set_param_value ("max-inline-insns-single", value / 2); set_param_value ("max-inline-insns-auto", value / 2); - set_param_value ("max-inline-insns-rtl", value); + break; + + case OPT_finstrument_functions_exclude_function_list_: + add_comma_separated_to_vector + (&flag_instrument_functions_exclude_functions, arg); + break; + + case OPT_finstrument_functions_exclude_file_list_: + add_comma_separated_to_vector + (&flag_instrument_functions_exclude_files, arg); break; case OPT_fmessage_length_: pp_set_line_maximum_length (global_dc->printer, value); break; + case OPT_fpack_struct_: + if (value <= 0 || (value & (value - 1)) || value > 16) + error ("structure alignment must be a small power of two, not %d", value); + else + { + initial_max_fld_align = value; + maximum_field_alignment = value * BITS_PER_UNIT; + } + break; + case OPT_fpeel_loops: flag_peel_loops_set = true; break; + case OPT_fplugin_: +#ifdef ENABLE_PLUGIN + add_new_plugin (arg); +#else + error ("Plugin support is disabled. Configure with --enable-plugin."); +#endif + break; + + case OPT_fplugin_arg_: +#ifdef ENABLE_PLUGIN + parse_plugin_arg_opt (arg); +#else + error ("Plugin support is disabled. Configure with --enable-plugin."); +#endif + break; + case OPT_fprofile_arcs: profile_arc_flag_set = true; break; + case OPT_finline_functions: + flag_inline_functions_set = true; + break; + + case OPT_fprofile_dir_: + profile_data_prefix = xstrdup (arg); + break; + + case OPT_fprofile_use_: + profile_data_prefix = xstrdup (arg); + flag_profile_use = true; + value = true; + /* No break here - do -fprofile-use processing. */ case OPT_fprofile_use: if (!flag_branch_probabilities_set) flag_branch_probabilities = value; @@ -831,12 +1866,25 @@ common_handle_option (size_t scode, const char *arg, int value) flag_tracer = value; if (!flag_value_profile_transformations_set) flag_value_profile_transformations = value; -#ifdef HAVE_prefetch - if (!flag_speculative_prefetching_set) - flag_speculative_prefetching = value; -#endif + if (!flag_inline_functions_set) + flag_inline_functions = value; + if (!flag_ipa_cp_set) + flag_ipa_cp = value; + if (!flag_ipa_cp_clone_set + && value && flag_ipa_cp) + flag_ipa_cp_clone = value; + if (!flag_predictive_commoning_set) + flag_predictive_commoning = value; + if (!flag_unswitch_loops_set) + flag_unswitch_loops = value; + if (!flag_gcse_after_reload_set) + flag_gcse_after_reload = value; break; + case OPT_fprofile_generate_: + profile_data_prefix = xstrdup (arg); + value = true; + /* No break here - do -fprofile-generate processing. */ case OPT_fprofile_generate: if (!profile_arc_flag_set) profile_arc_flag = value; @@ -844,10 +1892,8 @@ common_handle_option (size_t scode, const char *arg, int value) flag_profile_values = value; if (!flag_value_profile_transformations_set) flag_value_profile_transformations = value; -#ifdef HAVE_prefetch - if (!flag_speculative_prefetching_set) - flag_speculative_prefetching = value; -#endif + if (!flag_inline_functions_set) + flag_inline_functions = value; break; case OPT_fprofile_values: @@ -865,7 +1911,7 @@ common_handle_option (size_t scode, const char *arg, int value) else if (!strcmp(arg, "protected")) default_visibility = VISIBILITY_PROTECTED; else - error ("unrecognised visibility value \"%s\"", arg); + error ("unrecognized visibility value \"%s\"", arg); } break; @@ -873,19 +1919,20 @@ common_handle_option (size_t scode, const char *arg, int value) flag_value_profile_transformations_set = true; break; - case OPT_fspeculative_prefetching: - flag_speculative_prefetching_set = true; - break; - case OPT_frandom_seed: /* The real switch is -fno-random-seed. */ if (value) return 0; - flag_random_seed = NULL; + set_random_seed (NULL); break; case OPT_frandom_seed_: - flag_random_seed = arg; + set_random_seed (arg); + break; + + case OPT_fselective_scheduling: + case OPT_fselective_scheduling2: + sel_sched_switch_set = true; break; case OPT_fsched_verbose_: @@ -906,6 +1953,37 @@ common_handle_option (size_t scode, const char *arg, int value) flag_sched_stalled_insns_dep = value; break; + case OPT_fstack_check_: + if (!strcmp (arg, "no")) + flag_stack_check = NO_STACK_CHECK; + else if (!strcmp (arg, "generic")) + /* This is the old stack checking method. */ + flag_stack_check = STACK_CHECK_BUILTIN + ? FULL_BUILTIN_STACK_CHECK + : GENERIC_STACK_CHECK; + else if (!strcmp (arg, "specific")) + /* This is the new stack checking method. */ + flag_stack_check = STACK_CHECK_BUILTIN + ? FULL_BUILTIN_STACK_CHECK + : STACK_CHECK_STATIC_BUILTIN + ? STATIC_BUILTIN_STACK_CHECK + : GENERIC_STACK_CHECK; + else + warning (0, "unknown stack check parameter \"%s\"", arg); + break; + + case OPT_fstack_check: + /* This is the same as the "specific" mode above. */ + if (value) + flag_stack_check = STACK_CHECK_BUILTIN + ? FULL_BUILTIN_STACK_CHECK + : STACK_CHECK_STATIC_BUILTIN + ? STATIC_BUILTIN_STACK_CHECK + : GENERIC_STACK_CHECK; + else + flag_stack_check = NO_STACK_CHECK; + break; + case OPT_fstack_limit: /* The real switch is -fno-stack-limit. */ if (value) @@ -927,6 +2005,10 @@ common_handle_option (size_t scode, const char *arg, int value) stack_limit_rtx = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (arg)); break; + case OPT_ftree_vectorizer_verbose_: + vect_set_verbosity_level (arg); + break; + case OPT_ftls_model_: if (!strcmp (arg, "global-dynamic")) flag_tls_default = TLS_MODEL_GLOBAL_DYNAMIC; @@ -937,27 +2019,55 @@ common_handle_option (size_t scode, const char *arg, int value) else if (!strcmp (arg, "local-exec")) flag_tls_default = TLS_MODEL_LOCAL_EXEC; else - warning ("unknown tls-model \"%s\"", arg); + warning (0, "unknown tls-model \"%s\"", arg); + break; + + case OPT_fira_algorithm_: + if (!strcmp (arg, "CB")) + flag_ira_algorithm = IRA_ALGORITHM_CB; + else if (!strcmp (arg, "priority")) + flag_ira_algorithm = IRA_ALGORITHM_PRIORITY; + else + warning (0, "unknown ira algorithm \"%s\"", arg); + break; + + case OPT_fira_region_: + if (!strcmp (arg, "one")) + flag_ira_region = IRA_REGION_ONE; + else if (!strcmp (arg, "all")) + flag_ira_region = IRA_REGION_ALL; + else if (!strcmp (arg, "mixed")) + flag_ira_region = IRA_REGION_MIXED; + else + warning (0, "unknown ira region \"%s\"", arg); + break; + + case OPT_fira_verbose_: + flag_ira_verbose = value; break; case OPT_ftracer: flag_tracer_set = true; break; - case OPT_ftree_points_to_: - if (!strcmp (arg, "andersen")) -#ifdef HAVE_BANSHEE - flag_tree_points_to = PTA_ANDERSEN; -#else - warning ("Andersen's PTA not available - libbanshee not compiled."); -#endif - else if (!strcmp (arg, "none")) - flag_tree_points_to = PTA_NONE; - else - { - warning ("`%s`: unknown points-to analysis algorithm", arg); - return 0; - } + case OPT_fipa_cp: + flag_ipa_cp_set = true; + break; + + case OPT_fipa_cp_clone: + flag_ipa_cp_clone_set = true; + break; + + case OPT_fpredictive_commoning: + flag_predictive_commoning_set = true; + break; + + case OPT_funswitch_loops: + flag_unswitch_loops_set = true; + break; + + case OPT_fgcse_after_reload: + flag_gcse_after_reload_set = true; break; case OPT_funroll_loops: @@ -972,8 +2082,12 @@ common_handle_option (size_t scode, const char *arg, int value) set_debug_level (SDB_DEBUG, false, arg); break; - case OPT_gdwarf_2: - set_debug_level (DWARF2_DEBUG, false, arg); + case OPT_gdwarf_: + if (value < 2 || value > 4) + error ("dwarf version %d is not supported", value); + else + dwarf_version = value; + set_debug_level (DWARF2_DEBUG, false, ""); break; case OPT_ggdb: @@ -994,10 +2108,6 @@ common_handle_option (size_t scode, const char *arg, int value) set_debug_level (XCOFF_DEBUG, code == OPT_gxcoff_, arg); break; - case OPT_m: - set_target_switch (arg); - break; - case OPT_o: asm_file_name = arg; break; @@ -1006,13 +2116,33 @@ common_handle_option (size_t scode, const char *arg, int value) flag_pedantic_errors = pedantic = 1; break; + case OPT_fsee: + case OPT_fcse_skip_blocks: + case OPT_floop_optimize: + case OPT_frerun_loop_opt: + case OPT_fsched2_use_traces: + case OPT_fstrength_reduce: + case OPT_ftree_store_copy_prop: + case OPT_fforce_addr: + case OPT_ftree_salias: + case OPT_ftree_store_ccp: + case OPT_Wunreachable_code: + case OPT_fargument_alias: + case OPT_fargument_noalias: + case OPT_fargument_noalias_anything: + case OPT_fargument_noalias_global: + /* These are no-ops, preserved for backward compatibility. */ + break; + + case OPT_fuse_linker_plugin: + /* No-op. Used by the driver and passed to us because it starts with f.*/ + break; + default: /* If the flag was handled in a standard way, assume the lack of processing here is intentional. */ - if (cl_options[scode].flag_var) - break; - - abort (); + gcc_assert (cl_options[scode].flag_var); + break; } return 1; @@ -1033,7 +2163,7 @@ handle_param (const char *carg) { value = integral_argument (equal + 1); if (value == -1) - error ("invalid --param value `%s'", equal + 1); + error ("invalid --param value %qs", equal + 1); else { *equal = '\0'; @@ -1044,38 +2174,20 @@ handle_param (const char *carg) free (arg); } -/* Handle -W and -Wextra. */ -static void -set_Wextra (int setting) -{ - extra_warnings = setting; - warn_unused_value = setting; - warn_unused_parameter = (setting && maybe_warn_unused_parameter); - - /* We save the value of warn_uninitialized, since if they put - -Wuninitialized on the command line, we need to generate a - warning about not using it without also specifying -O. */ - if (setting == 0) - warn_uninitialized = 0; - else if (warn_uninitialized != 1) - warn_uninitialized = 2; -} - -/* Initialize unused warning flags. */ +/* Used to set the level of strict aliasing warnings, + when no level is specified (i.e., when -Wstrict-aliasing, and not + -Wstrict-aliasing=level was given). + ONOFF is assumed to take value 1 when -Wstrict-aliasing is specified, + and 0 otherwise. After calling this function, wstrict_aliasing will be + set to the default value of -Wstrict_aliasing=level, currently 3. */ void -set_Wunused (int setting) +set_Wstrict_aliasing (int onoff) { - warn_unused_function = setting; - warn_unused_label = setting; - /* Unused function parameter warnings are reported when either - ``-Wextra -Wunused'' or ``-Wunused-parameter'' is specified. - Thus, if -Wextra has already been seen, set warn_unused_parameter; - otherwise set maybe_warn_extra_parameter, which will be picked up - by set_Wextra. */ - maybe_warn_unused_parameter = setting; - warn_unused_parameter = (setting && extra_warnings); - warn_unused_variable = setting; - warn_unused_value = setting; + gcc_assert (onoff == 0 || onoff == 1); + if (onoff != 0) + warn_strict_aliasing = 3; + else + warn_strict_aliasing = 0; } /* The following routines are useful in setting all the flags that @@ -1083,17 +2195,29 @@ set_Wunused (int setting) void set_fast_math_flags (int set) { - flag_trapping_math = !set; flag_unsafe_math_optimizations = set; + set_unsafe_math_optimizations_flags (set); flag_finite_math_only = set; flag_errno_math = !set; if (set) { flag_signaling_nans = 0; flag_rounding_math = 0; + flag_cx_limited_range = 1; } } +/* When -funsafe-math-optimizations is set the following + flags are set as well. */ +void +set_unsafe_math_optimizations_flags (int set) +{ + flag_trapping_math = !set; + flag_signed_zeros = !set; + flag_associative_math = set; + flag_reciprocal_math = set; +} + /* Return true iff flags are set as if -ffast-math. */ bool fast_math_flags_set_p (void) @@ -1101,9 +2225,22 @@ fast_math_flags_set_p (void) return (!flag_trapping_math && flag_unsafe_math_optimizations && flag_finite_math_only + && !flag_signed_zeros && !flag_errno_math); } +/* Return true iff flags are set as if -ffast-math but using the flags stored + in the struct cl_optimization structure. */ +bool +fast_math_flags_struct_set_p (struct cl_optimization *opt) +{ + return (!opt->flag_trapping_math + && opt->flag_unsafe_math_optimizations + && opt->flag_finite_math_only + && !opt->flag_signed_zeros + && !opt->flag_errno_math); +} + /* Handle a debug output -g switch. EXTENDED is true or false to support extended output (2 is special and means "-ggdb" was given). */ static void @@ -1129,7 +2266,7 @@ set_debug_level (enum debug_info_type type, int extended, const char *arg) } if (write_symbols == NO_DEBUG) - warning ("target system does not support debug output"); + warning (0, "target system does not support debug output"); } } else @@ -1146,226 +2283,166 @@ set_debug_level (enum debug_info_type type, int extended, const char *arg) if (*arg == '\0') { if (!debug_info_level) - debug_info_level = 2; + debug_info_level = DINFO_LEVEL_NORMAL; } else { - debug_info_level = integral_argument (arg); - if (debug_info_level == (unsigned int) -1) + int argval = integral_argument (arg); + if (argval == -1) error ("unrecognised debug output level \"%s\"", arg); - else if (debug_info_level > 3) + else if (argval > 3) error ("debug output level %s is too high", arg); + else + debug_info_level = (enum debug_info_level) argval; } } -/* Output --help text. */ -static void -print_help (void) +/* Return 1 if OPTION is enabled, 0 if it is disabled, or -1 if it isn't + a simple on-off switch. */ + +int +option_enabled (int opt_idx) { - size_t i; - const char *p; + const struct cl_option *option = &(cl_options[opt_idx]); - GET_ENVIRONMENT (p, "COLUMNS"); - if (p) - { - int value = atoi (p); - if (value > 0) - columns = value; - } + if (option->flag_var) + switch (option->var_type) + { + case CLVC_BOOLEAN: + return *(int *) option->flag_var != 0; - puts (_("The following options are language-independent:\n")); + case CLVC_EQUAL: + return *(int *) option->flag_var == option->var_value; - print_filtered_help (CL_COMMON); - print_param_help (); + case CLVC_BIT_CLEAR: + return (*(int *) option->flag_var & option->var_value) == 0; - for (i = 0; lang_names[i]; i++) - { - printf (_("The %s front end recognizes the following options:\n\n"), - lang_names[i]); - print_filtered_help (1U << i); - } + case CLVC_BIT_SET: + return (*(int *) option->flag_var & option->var_value) != 0; - display_target_options (); + case CLVC_STRING: + break; + } + return -1; } -/* Print the help for --param. */ -static void -print_param_help (void) -{ - size_t i; +/* Fill STATE with the current state of option OPTION. Return true if + there is some state to store. */ - puts (_("The --param option recognizes the following as parameters:\n")); +bool +get_option_state (int option, struct cl_option_state *state) +{ + if (cl_options[option].flag_var == 0) + return false; - for (i = 0; i < LAST_PARAM; i++) + switch (cl_options[option].var_type) { - const char *help = compiler_params[i].help; - const char *param = compiler_params[i].option; - - if (help == NULL || *help == '\0') - help = undocumented_msg; + case CLVC_BOOLEAN: + case CLVC_EQUAL: + state->data = cl_options[option].flag_var; + state->size = sizeof (int); + break; - /* Get the translation. */ - help = _(help); + case CLVC_BIT_CLEAR: + case CLVC_BIT_SET: + state->ch = option_enabled (option); + state->data = &state->ch; + state->size = 1; + break; - wrap_help (help, param, strlen (param)); + case CLVC_STRING: + state->data = *(const char **) cl_options[option].flag_var; + if (state->data == 0) + state->data = ""; + state->size = strlen ((const char *) state->data) + 1; + break; } - - putchar ('\n'); + return true; } -/* Print help for a specific front-end, etc. */ -static void -print_filtered_help (unsigned int flag) +/* Set *OPTION according to VALUE and ARG. */ + +void +set_option (const struct cl_option *option, int value, const char *arg) { - unsigned int i, len, filter, indent = 0; - bool duplicates = false; - const char *help, *opt, *tab; - static char *printed; + if (!option->flag_var) + return; - if (flag == CL_COMMON) - { - filter = flag; - if (!printed) - printed = xmalloc (cl_options_count); - memset (printed, 0, cl_options_count); - } - else + switch (option->var_type) { - /* Don't print COMMON options twice. */ - filter = flag | CL_COMMON; - - for (i = 0; i < cl_options_count; i++) - { - if ((cl_options[i].flags & filter) != flag) - continue; + case CLVC_BOOLEAN: + *(int *) option->flag_var = value; + break; - /* Skip help for internal switches. */ - if (cl_options[i].flags & CL_UNDOCUMENTED) - continue; + case CLVC_EQUAL: + *(int *) option->flag_var = (value + ? option->var_value + : !option->var_value); + break; - /* Skip switches that have already been printed, mark them to be - listed later. */ - if (printed[i]) - { - duplicates = true; - indent = print_switch (cl_options[i].opt_text, indent); - } - } + case CLVC_BIT_CLEAR: + case CLVC_BIT_SET: + if ((value != 0) == (option->var_type == CLVC_BIT_SET)) + *(int *) option->flag_var |= option->var_value; + else + *(int *) option->flag_var &= ~option->var_value; + if (option->flag_var == &target_flags) + target_flags_explicit |= option->var_value; + break; - if (duplicates) - { - putchar ('\n'); - putchar ('\n'); - } + case CLVC_STRING: + *(const char **) option->flag_var = arg; + break; } +} - for (i = 0; i < cl_options_count; i++) - { - if ((cl_options[i].flags & filter) != flag) - continue; - - /* Skip help for internal switches. */ - if (cl_options[i].flags & CL_UNDOCUMENTED) - continue; - - /* Skip switches that have already been printed. */ - if (printed[i]) - continue; - - printed[i] = true; - - help = cl_options[i].help; - if (!help) - help = undocumented_msg; - /* Get the translation. */ - help = _(help); +/* Callback function, called when -Werror= enables a warning. */ - tab = strchr (help, '\t'); - if (tab) - { - len = tab - help; - opt = help; - help = tab + 1; - } - else - { - opt = cl_options[i].opt_text; - len = strlen (opt); - } +static void (*warning_as_error_callback) (int) = NULL; - wrap_help (help, opt, len); - } +/* Register a callback for enable_warning_as_error calls. */ - putchar ('\n'); +void +register_warning_as_error_callback (void (*callback) (int)) +{ + gcc_assert (warning_as_error_callback == NULL || callback == NULL); + warning_as_error_callback = callback; } -/* Output ITEM, of length ITEM_WIDTH, in the left column, followed by - word-wrapped HELP in a second column. */ -static unsigned int -print_switch (const char *text, unsigned int indent) -{ - unsigned int len = strlen (text) + 1; /* trailing comma */ +/* Enable a warning option as an error. This is used by -Werror= and + also by legacy Werror-implicit-function-declaration. */ - if (indent) +void +enable_warning_as_error (const char *arg, int value, unsigned int lang_mask) +{ + char *new_option; + int option_index; + + new_option = XNEWVEC (char, strlen (arg) + 2); + new_option[0] = 'W'; + strcpy (new_option + 1, arg); + option_index = find_opt (new_option, lang_mask); + if (option_index == N_OPTS) { - putchar (','); - if (indent + len > columns) - { - putchar ('\n'); - putchar (' '); - indent = 1; - } + error ("-Werror=%s: No option -%s", arg, new_option); } else - putchar (' '); - - putchar (' '); - fputs (text, stdout); - - return indent + len + 1; -} - -/* Output ITEM, of length ITEM_WIDTH, in the left column, followed by - word-wrapped HELP in a second column. */ -static void -wrap_help (const char *help, const char *item, unsigned int item_width) -{ - unsigned int col_width = 27; - unsigned int remaining, room, len; - - remaining = strlen (help); - - do { - room = columns - 3 - MAX (col_width, item_width); - if (room > columns) - room = 0; - len = remaining; + const diagnostic_t kind = value ? DK_ERROR : DK_WARNING; - if (room < len) + diagnostic_classify_diagnostic (global_dc, option_index, kind); + if (kind == DK_ERROR) { - unsigned int i; + const struct cl_option * const option = cl_options + option_index; - for (i = 0; help[i]; i++) - { - if (i >= room && len != remaining) - break; - if (help[i] == ' ') - len = i; - else if ((help[i] == '-' || help[i] == '/') - && help[i + 1] != ' ' - && i > 0 && ISALPHA (help[i - 1])) - len = i + 1; - } - } + /* -Werror=foo implies -Wfoo. */ + if (option->var_type == CLVC_BOOLEAN && option->flag_var) + *(int *) option->flag_var = 1; - printf( " %-*.*s %.*s\n", col_width, item_width, item, len, help); - item_width = 0; - while (help[len] == ' ') - len++; - help += len; - remaining -= len; + if (warning_as_error_callback) + warning_as_error_callback (option_index); + } } - while (remaining); + free (new_option); }