PR driver/88911 reports an issue where the user couldn't remember the spelling
of the "-dumpspecs" option, and attempted various similar spellings, but many
of them failed to contain a suggestion of the correct spelling:

  $ gcc q.c -dump-spec
  cc1: warning: unrecognized gcc debugging option: u
  cc1: warning: unrecognized gcc debugging option: m
  cc1: warning: unrecognized gcc debugging option: -
  cc1: warning: unrecognized gcc debugging option: s
  cc1: warning: unrecognized gcc debugging option: e
  cc1: warning: unrecognized gcc debugging option: c
  $ gcc q.c -dump-specs
  cc1: warning: unrecognized gcc debugging option: u
  cc1: warning: unrecognized gcc debugging option: m
  cc1: warning: unrecognized gcc debugging option: -
  cc1: warning: unrecognized gcc debugging option: s
  cc1: warning: unrecognized gcc debugging option: e
  cc1: warning: unrecognized gcc debugging option: c
  cc1: warning: unrecognized gcc debugging option: s
  $ gcc q.c -fdump-spec
  cc1: error: unrecognized command line option '-fdump-spec'
  $ gcc q.c -fdump-specs
  cc1: error: unrecognized command line option '-fdump-specs'
  $ gcc q.c -fdumpspecs
  gcc: error: unrecognized command line option '-fdumpspecs'; did you
  mean '-dumpspecs'?
  [Aha!]

There are two issues here:

(a) unmatched options beginning with "-d" are treated as part of the
"-d" option, leading to a warning from decode_d_option, but no
suggestion.

(b) options beginning with "-fdump-" are also passed to a special
handler, and this doesn't offer suggestions for unmatched options
either.

This patch uses option_proposer::suggest_option to add suggestions
in both places, leading to useful suggestions for all of the cases
given above.  For the case of "-d" it only offers a suggestion for
the first unrecognized character.  I also added quotes around the
character in the message, and indicate the full option for context,
so that the first example above becomes:

  $ gcc q.c -dump-spec
  cc1: warning: unrecognized gcc debugging option: 'u' (as part of 
'-dump-spec'); did you mean '-dumpspecs'?
  cc1: warning: unrecognized gcc debugging option: 'm' (as part of '-dump-spec')
  cc1: warning: unrecognized gcc debugging option: '-' (as part of '-dump-spec')
  cc1: warning: unrecognized gcc debugging option: 's' (as part of '-dump-spec')
  cc1: warning: unrecognized gcc debugging option: 'e' (as part of '-dump-spec')
  cc1: warning: unrecognized gcc debugging option: 'c' (as part of '-dump-spec')

Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu.

Is this patch OK for trunk?
(it's not a regression, but it's fairly self-contained, so would this be
acceptable now, or should I queue it for when stage 1 reopens?)

gcc/ChangeLog:
        PR driver/88911
        * opts-global.c: Include "opt-suggestions.h".
        (handle_common_deferred_options) <OPT_fdump_>: If the argument is
        unrecognized, attempt to provide a hint.
        * opts.c: Include "opt-suggestions.h".
        (common_handle_option) <OPT_d>: Pass original option argument text
        to decode_d_option.
        (decode_d_option): Add parameter "orig_arg".  Use it to provide a
        hint within the first unrecognized character.  Wrap the character
        in quotes, and indicate the original argument it belongs to.

gcc/testsuite/ChangeLog:
        PR driver/88911
        * gcc.dg/spellcheck-options-pr88911-1.c: New test.
        * gcc.dg/spellcheck-options-pr88911-2.c: New test.
        * gcc.dg/spellcheck-options-pr88911-3.c: New test.
        * gcc.dg/spellcheck-options-pr88911-4.c: New test.
        * gcc.dg/spellcheck-options-pr88911-5.c: New test.
---
 gcc/opts-global.c                                  | 17 +++++++-
 gcc/opts.c                                         | 45 +++++++++++++++++++---
 .../gcc.dg/spellcheck-options-pr88911-1.c          |  8 ++++
 .../gcc.dg/spellcheck-options-pr88911-2.c          |  3 ++
 .../gcc.dg/spellcheck-options-pr88911-3.c          |  3 ++
 .../gcc.dg/spellcheck-options-pr88911-4.c          |  3 ++
 .../gcc.dg/spellcheck-options-pr88911-5.c          |  3 ++
 7 files changed, 76 insertions(+), 6 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/spellcheck-options-pr88911-1.c
 create mode 100644 gcc/testsuite/gcc.dg/spellcheck-options-pr88911-2.c
 create mode 100644 gcc/testsuite/gcc.dg/spellcheck-options-pr88911-3.c
 create mode 100644 gcc/testsuite/gcc.dg/spellcheck-options-pr88911-4.c
 create mode 100644 gcc/testsuite/gcc.dg/spellcheck-options-pr88911-5.c

diff --git a/gcc/opts-global.c b/gcc/opts-global.c
index 1c24c85..cc30341 100644
--- a/gcc/opts-global.c
+++ b/gcc/opts-global.c
@@ -39,6 +39,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "attribs.h"
 #include "asan.h"
 #include "file-prefix-map.h" /* add_*_prefix_map()  */
+#include "opt-suggestions.h"
 
 typedef const char *const_char_p; /* For DEF_VEC_P.  */
 
@@ -372,7 +373,21 @@ handle_common_deferred_options (void)
 
        case OPT_fdump_:
          if (!g->get_dumps ()->dump_switch_p (opt->arg))
-           error ("unrecognized command line option %<-fdump-%s%>", opt->arg);
+           {
+             option_proposer prop;
+             /* option_proposer::suggest_option expects the leading dash
+                to have been stripped from its argument, so we rebuild
+                the arg without one.  */
+             char *orig_arg = xasprintf ("fdump-%s", opt->arg);
+             if (const char *hint = prop.suggest_option (orig_arg))
+               error ("unrecognized command line option %<-%s%>"
+                      "; did you mean %<-%s%>?",
+                      orig_arg, hint);
+             else
+               error ("unrecognized command line option %<-%s%>",
+                      orig_arg);
+             free (orig_arg);
+           }
          break;
 
         case OPT_fopt_info_:
diff --git a/gcc/opts.c b/gcc/opts.c
index a4be6ae..0722549 100644
--- a/gcc/opts.c
+++ b/gcc/opts.c
@@ -31,6 +31,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "insn-attr-common.h"
 #include "common/common-target.h"
 #include "spellcheck.h"
+#include "opt-suggestions.h"
 
 static void set_Wstrict_aliasing (struct gcc_options *opts, int onoff);
 
@@ -195,7 +196,8 @@ static void set_debug_level (enum debug_info_type type, int 
extended,
                             struct gcc_options *opts_set,
                             location_t loc);
 static void set_fast_math_flags (struct gcc_options *opts, int set);
-static void decode_d_option (const char *arg, struct gcc_options *opts,
+static void decode_d_option (const char *arg, const char *orig_arg,
+                            struct gcc_options *opts,
                             location_t loc, diagnostic_context *dc);
 static void set_unsafe_math_optimizations_flags (struct gcc_options *opts,
                                                 int set);
@@ -2345,7 +2347,7 @@ common_handle_option (struct gcc_options *opts,
       break;
 
     case OPT_d:
-      decode_d_option (arg, opts, loc, dc);
+      decode_d_option (arg, decoded->orig_option_with_args_text, opts, loc, 
dc);
       break;
 
     case OPT_fcall_used_:
@@ -2999,14 +3001,18 @@ setup_core_dumping (diagnostic_context *dc)
 }
 
 /* Parse a -d<ARG> command line switch for OPTS, location LOC,
-   diagnostic context DC.  */
+   diagnostic context DC, where ORIG_ARG was the original text
+   of the switch.  */
 
 static void
-decode_d_option (const char *arg, struct gcc_options *opts,
+decode_d_option (const char *arg, const char *orig_arg,
+                struct gcc_options *opts,
                 location_t loc, diagnostic_context *dc)
 {
   int c;
 
+  bool emitted_unrecognized = false;
+
   while (*arg)
     switch (c = *arg++)
       {
@@ -3037,7 +3043,36 @@ decode_d_option (const char *arg, struct gcc_options 
*opts,
        break;
 
       default:
-         warning_at (loc, 0, "unrecognized gcc debugging option: %c", c);
+       {
+         /* Perhaps the user misspelled one of the other options beginning
+            with "-d" (e.g. -dumpspecs).
+            The first time we emit such a warning, attempt to suggest such
+            an option.  */
+         char *hint = NULL;
+         if (!emitted_unrecognized)
+           {
+             option_proposer prop;
+             emitted_unrecognized = true;
+             /* option_proposer::suggest_option expects the leading dash
+                to have been stripped from its argument, so we advance
+                one character.  */
+             gcc_assert (orig_arg[0] == '-');
+             if (const char *h = prop.suggest_option (orig_arg + 1))
+               hint = xstrdup (h);
+           }
+         if (hint)
+           {
+             warning_at (loc, 0,
+                         "unrecognized gcc debugging option: %qc"
+                         " (as part of %qs);"
+                         " did you mean %<-%s%>?", c, orig_arg, hint);
+             free (hint);
+           }
+         else
+           warning_at (loc, 0,
+                       "unrecognized gcc debugging option: %qc"
+                       " (as part of %qs)", c, orig_arg);
+       }
        break;
       }
 }
diff --git a/gcc/testsuite/gcc.dg/spellcheck-options-pr88911-1.c 
b/gcc/testsuite/gcc.dg/spellcheck-options-pr88911-1.c
new file mode 100644
index 0000000..45462e2
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/spellcheck-options-pr88911-1.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-dump-spec" } */
+/* { dg-warning "unrecognized gcc debugging option: 'u' \\(as part of 
'-dump-spec'\\); did you mean '-dumpspecs'?"  "" { target *-*-* } 0 } */
+/* { dg-warning "unrecognized gcc debugging option: 'm' \\(as part of 
'-dump-spec'\\)"  "" { target *-*-* } 0 } */
+/* { dg-warning "unrecognized gcc debugging option: '-' \\(as part of 
'-dump-spec'\\)"  "" { target *-*-* } 0 } */
+/* { dg-warning "unrecognized gcc debugging option: 's' \\(as part of 
'-dump-spec'\\)"  "" { target *-*-* } 0 } */
+/* { dg-warning "unrecognized gcc debugging option: 'e' \\(as part of 
'-dump-spec'\\)"  "" { target *-*-* } 0 } */
+/* { dg-warning "unrecognized gcc debugging option: 'c' \\(as part of 
'-dump-spec'\\)"  "" { target *-*-* } 0 } */
diff --git a/gcc/testsuite/gcc.dg/spellcheck-options-pr88911-2.c 
b/gcc/testsuite/gcc.dg/spellcheck-options-pr88911-2.c
new file mode 100644
index 0000000..c764dc9
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/spellcheck-options-pr88911-2.c
@@ -0,0 +1,3 @@
+/* { dg-do compile } */
+/* { dg-options "-fdump-spec" } */
+/* { dg-error "unrecognized command line option '-fdump-spec'; did you mean 
'-dumpspecs'?"  "" { target *-*-* } 0 } */
diff --git a/gcc/testsuite/gcc.dg/spellcheck-options-pr88911-3.c 
b/gcc/testsuite/gcc.dg/spellcheck-options-pr88911-3.c
new file mode 100644
index 0000000..4034721
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/spellcheck-options-pr88911-3.c
@@ -0,0 +1,3 @@
+/* { dg-do compile } */
+/* { dg-options "-fdump-specs" } */
+/* { dg-error "unrecognized command line option '-fdump-specs'; did you mean 
'-dumpspecs'?"  "" { target *-*-* } 0 } */
diff --git a/gcc/testsuite/gcc.dg/spellcheck-options-pr88911-4.c 
b/gcc/testsuite/gcc.dg/spellcheck-options-pr88911-4.c
new file mode 100644
index 0000000..3270bbf
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/spellcheck-options-pr88911-4.c
@@ -0,0 +1,3 @@
+/* { dg-do compile } */
+/* { dg-options "-d3" } */
+/* { dg-warning "unrecognized gcc debugging option: '3' \\(as part of 
'-d3'\\)"  "" { target *-*-* } 0 } */
diff --git a/gcc/testsuite/gcc.dg/spellcheck-options-pr88911-5.c 
b/gcc/testsuite/gcc.dg/spellcheck-options-pr88911-5.c
new file mode 100644
index 0000000..6f9cf03
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/spellcheck-options-pr88911-5.c
@@ -0,0 +1,3 @@
+/* { dg-do compile } */
+/* { dg-options "-fdump-something-not-recognized" } */
+/* { dg-error "unrecognized command line option 
'-fdump-something-not-recognized"  "" { target *-*-* } 0 } */
-- 
1.8.5.3

Reply via email to