From patchwork Fri Jun 11 18:28:10 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Joseph Myers X-Patchwork-Id: 55346 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) by ozlabs.org (Postfix) with SMTP id E11E8B7D87 for ; Sat, 12 Jun 2010 04:28:24 +1000 (EST) Received: (qmail 25497 invoked by alias); 11 Jun 2010 18:28:22 -0000 Received: (qmail 25305 invoked by uid 22791); 11 Jun 2010 18:28:19 -0000 X-SWARE-Spam-Status: No, hits=-1.1 required=5.0 tests=AWL, BAYES_05, TW_CP, TW_RG, T_RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org Received: from mail.codesourcery.com (HELO mail.codesourcery.com) (38.113.113.100) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Fri, 11 Jun 2010 18:28:13 +0000 Received: (qmail 28756 invoked from network); 11 Jun 2010 18:28:12 -0000 Received: from unknown (HELO digraph.polyomino.org.uk) (joseph@127.0.0.2) by mail.codesourcery.com with ESMTPA; 11 Jun 2010 18:28:12 -0000 Received: from jsm28 (helo=localhost) by digraph.polyomino.org.uk with local-esmtp (Exim 4.69) (envelope-from ) id 1ON8xe-0004gi-H5 for gcc-patches@gcc.gnu.org; Fri, 11 Jun 2010 18:28:10 +0000 Date: Fri, 11 Jun 2010 18:28:10 +0000 (UTC) From: "Joseph S. Myers" To: gcc-patches@gcc.gnu.org Subject: Split up option decoding code Message-ID: MIME-Version: 1.0 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org In the process of sharing option processing machinery between the driver and the compilers proper to improve multilib selection, I expect an intermediate stage where the basic machinery is shared but much of the logic associated with individual options isn't; the logic for individual options can then be shared incrementally (parts of it, e.g. anything setting up trees or RTL in response to options, not being needed in the driver at all) until everything needed for multilib selection is shared. This patch moves towards that stage by separating the code that converts part of the argv array into an option and its operand from the code that processes the option further to change state in the compiler; the former goes in opts-common.c (much of the latter will go there eventually as well). My plan is to follow this up by having an initial pass converting the argv array to an array of cl_decoded_option structures, with subsequent passes in both the driver and the compilers proper working on that structure. There are several existing passes over argv, and these passes often do not work reliably in the presence of option arguments that look like options themselves, so this will improve consistency in option handling between the driver and the compiler proper and within each of those. The driver's use of common machinery can then start with decode_cmdline_option using SWITCH_TAKES_ARG and WORD_SWITCH_TAKES_ARG for unknown options so that an accurate array is produced in the driver (and used by prune_options), before actually adding driver options (and then miscellaneous options from specs) to the .opt files so that it uses the machinery more usefully to convert options to features. I expect also to convert the translate_options code in gcc.c to something better integrated with .opt files. Bootstrapped with no regressions on x86_64-unknown-linux-gnu. OK to commit? 2010-06-11 Joseph Myers * opts-common.c: Include options.h. (integral_argument): Move from opts.c. (decode_cmdline_option): New. Based on read_cmdline_option. * opts.c (integral_argument): Move to opts-common.c. (read_cmdline_option): Move most contents to decode_cmdline_option. Use %qs in diagnostics. * opts.h (CL_ERR_DISABLED, CL_ERR_MISSING_ARG, CL_ERR_WRONG_LANG, CL_ERR_UINT_ARG, struct cl_decoded_option, integral_argument, decode_cmdline_option): New. testsuite: 2010-06-11 Joseph Myers * gcc.dg/funroll-loops-all.c: Update expected error. Index: opts-common.c =================================================================== --- opts-common.c (revision 160599) +++ opts-common.c (working copy) @@ -1,5 +1,5 @@ /* Command line option handling. - Copyright (C) 2006, 2007, 2008 Free Software Foundation, Inc. + Copyright (C) 2006, 2007, 2008, 2010 Free Software Foundation, Inc. This file is part of GCC. @@ -22,6 +22,7 @@ along with GCC; see the file COPYING3. #include "intl.h" #include "coretypes.h" #include "opts.h" +#include "options.h" /* Perform a binary search to find which option the command-line INPUT matches. Returns its index in the option array, and N_OPTS @@ -107,6 +108,138 @@ find_opt (const char *input, int lang_ma return match_wrong_lang; } +/* If ARG is a non-negative integer made up solely of digits, return its + value, otherwise return -1. */ + +int +integral_argument (const char *arg) +{ + const char *p = arg; + + while (*p && ISDIGIT (*p)) + p++; + + if (*p == '\0') + return atoi (arg); + + return -1; +} + +/* Decode the switch beginning at ARGV for the language indicated by + LANG_MASK, into the structure *DECODED. Returns the number of + switches consumed. */ + +unsigned int +decode_cmdline_option (const char **argv, unsigned int lang_mask, + struct cl_decoded_option *decoded) +{ + size_t opt_index; + const char *opt, *arg = 0; + char *dup = 0; + int value = 1; + unsigned int result = 1; + const struct cl_option *option; + int errors = 0; + + opt = argv[0]; + + 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 = 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) + goto done; + + option = &cl_options[opt_index]; + + /* Reject negative form of switches that don't take negatives as + unrecognized. */ + if (!value && (option->flags & CL_REJECT_NEGATIVE)) + { + opt_index = cl_options_count; + goto done; + } + + /* Check to see if the option is disabled for this configuration. */ + if (option->flags & CL_DISABLED) + errors |= CL_ERR_DISABLED; + + /* Sort out any argument the switch takes. */ + if (option->flags & CL_JOINED) + { + /* Have arg point to the original switch. This is because + some code, such as disable_builtin_function, expects its + argument to be persistent until the program exits. */ + arg = argv[0] + cl_options[opt_index].opt_len + 1; + if (!value) + arg += strlen ("no-"); + + if (*arg == '\0' && !(option->flags & CL_MISSING_OK)) + { + if (option->flags & CL_SEPARATE) + { + arg = argv[1]; + result = 2; + if (arg == NULL) + result = 1; + } + else + /* Missing argument. */ + arg = NULL; + } + } + else if (option->flags & CL_SEPARATE) + { + arg = argv[1]; + result = 2; + if (arg == NULL) + result = 1; + } + + /* Check if this is a switch for a different front end. */ + if (!(option->flags & (lang_mask | CL_COMMON | CL_TARGET))) + errors |= CL_ERR_WRONG_LANG; + 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. */ + errors |= CL_ERR_WRONG_LANG; + + if (arg == NULL && (option->flags & (CL_JOINED | CL_SEPARATE))) + errors |= CL_ERR_MISSING_ARG; + + /* If the switch takes an integer, convert it. */ + if (arg && (option->flags & CL_UINTEGER)) + { + value = integral_argument (arg); + if (value == -1) + errors |= CL_ERR_UINT_ARG; + } + + done: + if (dup) + free (dup); + decoded->opt_index = opt_index; + decoded->arg = arg; + decoded->value = value; + decoded->errors = errors; + return result; +} + /* Return true if NEXT_OPT_IDX cancels OPT_IDX. Return false if the next one is the same as ORIG_NEXT_OPT_IDX. */ Index: testsuite/gcc.dg/funroll-loops-all.c =================================================================== --- testsuite/gcc.dg/funroll-loops-all.c (revision 160599) +++ testsuite/gcc.dg/funroll-loops-all.c (working copy) @@ -1,4 +1,4 @@ /* PR 17594 */ /* { dg-do compile } */ /* { dg-options "-funroll-loops-all" } */ -/* { dg-error "unrecognized command line option \"-funroll-loops-all\"" "" { target *-*-* } 0 } */ +/* { dg-error "unrecognized command line option '-funroll-loops-all'" "" { target *-*-* } 0 } */ Index: opts.c =================================================================== --- opts.c (revision 160599) +++ opts.c (working copy) @@ -381,22 +381,6 @@ static void complain_wrong_lang (const c static void set_debug_level (enum debug_info_type type, int extended, const char *arg); -/* If ARG is a non-negative integer made up solely of digits, return its - value, otherwise return -1. */ -static int -integral_argument (const char *arg) -{ - const char *p = arg; - - while (*p && ISDIGIT (*p)) - p++; - - if (*p == '\0') - return atoi (arg); - - return -1; -} - /* Return a malloced slash-separated list of languages in MASK. */ static char * write_langs (unsigned int mask) @@ -536,131 +520,61 @@ handle_option (int opt_index, int value, static unsigned int read_cmdline_option (const char **argv, unsigned int lang_mask) { - size_t opt_index; - const char *opt, *arg = 0; - char *dup = 0; - int value = 1; - unsigned int result = 0; + struct cl_decoded_option decoded; + unsigned int result; + const char *opt; const struct cl_option *option; opt = argv[0]; - 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 = 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. */ + result = decode_cmdline_option (argv, lang_mask, &decoded); + if (decoded.opt_index == cl_options_count) + { + if (opt[1] == 'W' && opt[2] == 'n' && opt[3] == 'o' && opt[4] == '-') + /* We don't generate warnings for unknown -Wno-* options + unless we issue diagnostics. */ postpone_unknown_option_warning (argv[0]); - result = 1; - goto done; - } + else + error ("unrecognized command line option %qs", opt); + return result; } - if (opt_index == cl_options_count) - goto done; - - option = &cl_options[opt_index]; - - /* Reject negative form of switches that don't take negatives as - unrecognized. */ - if (!value && (option->flags & CL_REJECT_NEGATIVE)) - goto done; - - /* We've recognized this switch. */ - result = 1; + option = &cl_options[decoded.opt_index]; - /* Check to see if the option is disabled for this configuration. */ - if (option->flags & CL_DISABLED) + if (decoded.errors & CL_ERR_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) - { - /* Have arg point to the original switch. This is because - some code, such as disable_builtin_function, expects its - argument to be persistent until the program exits. */ - arg = argv[0] + cl_options[opt_index].opt_len + 1; - if (!value) - arg += strlen ("no-"); - - if (*arg == '\0' && !(option->flags & CL_MISSING_OK)) - { - if (option->flags & CL_SEPARATE) - { - arg = argv[1]; - result = 2; - } - else - /* Missing argument. */ - arg = NULL; - } - } - else if (option->flags & CL_SEPARATE) - { - arg = argv[1]; - result = 2; - } - - /* 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 | CL_TARGET))) + if (decoded.errors & CL_ERR_WRONG_LANG) { 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)) + + if (decoded.errors & CL_ERR_MISSING_ARG) { - /* Complain for target flag language mismatches if any languages - are specified. */ - complain_wrong_lang (argv[0], option, lang_mask); + if (!lang_hooks.missing_argument (opt, decoded.opt_index)) + error ("missing argument to %qs", opt); goto done; } - if (arg == NULL && (option->flags & (CL_JOINED | CL_SEPARATE))) + if (decoded.errors & CL_ERR_UINT_ARG) { - if (!lang_hooks.missing_argument (opt, opt_index)) - error ("missing argument to \"%s\"", opt); + error ("argument to %qs should be a non-negative integer", + option->opt_text); goto done; } - /* If the switch takes an integer, convert it. */ - if (arg && (option->flags & CL_UINTEGER)) - { - value = integral_argument (arg); - if (value == -1) - { - error ("argument to \"%s\" should be a non-negative integer", - option->opt_text); - goto done; - } - } + gcc_assert (!decoded.errors); - if (!handle_option (opt_index, value, arg, lang_mask, DK_UNSPECIFIED)) - result = 0; + if (!handle_option (decoded.opt_index, decoded.value, decoded.arg, + lang_mask, DK_UNSPECIFIED)) + error ("unrecognized command line option %qs", opt); done: - if (dup) - free (dup); return result; } @@ -780,12 +694,6 @@ read_cmdline_options (unsigned int argc, } n = read_cmdline_option (argv + i, lang_mask); - - if (!n) - { - n = 1; - error ("unrecognized command line option \"%s\"", opt); - } } } Index: opts.h =================================================================== --- opts.h (revision 160599) +++ opts.h (working copy) @@ -1,5 +1,5 @@ /* Command line option handling. - Copyright (C) 2002, 2003, 2004, 2005, 2007, 2008 + Copyright (C) 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. This file is part of GCC. @@ -90,6 +90,34 @@ extern const unsigned int cl_lang_count; #define CL_UINTEGER (1 << 29) /* Argument is an integer >=0. */ #define CL_UNDOCUMENTED (1 << 30) /* Do not output with --help. */ +/* Possible ways in which a command-line option may be erroneous. + These do not include not being known at all; an option index of + cl_options_count is used for that. */ + +#define CL_ERR_DISABLED (1 << 0) /* Disabled in this configuration. */ +#define CL_ERR_MISSING_ARG (1 << 1) /* Argument required but missing. */ +#define CL_ERR_WRONG_LANG (1 << 2) /* Option for wrong language. */ +#define CL_ERR_UINT_ARG (1 << 3) /* Bad unsigned integer argument. */ + +/* Structure describing the result of decoding an option. */ + +struct cl_decoded_option +{ + /* The index of this option, or cl_options_count if not known. */ + size_t opt_index; + + /* The string argument, or NULL if none. */ + const char *arg; + + /* For a boolean option, 1 for the true case and 0 for the "no-" + case. For an unsigned integer option, the value of the + argument. 1 in all other cases. */ + int value; + + /* Any flags describing errors detected in this option. */ + int errors; +}; + /* Input file names. */ extern const char **in_fnames; @@ -99,6 +127,10 @@ extern const char **in_fnames; extern unsigned num_in_fnames; size_t find_opt (const char *input, int lang_mask); +extern int integral_argument (const char *arg); +extern unsigned int decode_cmdline_option (const char **argv, + unsigned int lang_mask, + struct cl_decoded_option *decoded); extern void prune_options (int *argcp, char ***argvp); extern void decode_options (unsigned int argc, const char **argv); extern int option_enabled (int opt_idx);