Offer suggestions for unrecognized sanitizer options (PR driver/78877)
authorDavid Malcolm <dmalcolm@redhat.com>
Wed, 11 Jan 2017 17:25:40 +0000 (17:25 +0000)
committerDavid Malcolm <dmalcolm@gcc.gnu.org>
Wed, 11 Jan 2017 17:25:40 +0000 (17:25 +0000)
gcc/ChangeLog:
PR driver/78877
* opts.c: Include "spellcheck.h"
(struct string_fragment): New struct.
(struct edit_distance_traits<const string_fragment &>): New
struct.
(get_closest_sanitizer_option): New function.
(parse_sanitizer_options): Offer suggestions for unrecognized arguments.

gcc/testsuite/ChangeLog:
PR driver/78877
* gcc.dg/spellcheck-options-14.c: New test case.
* gcc.dg/spellcheck-options-15.c: New test case.
* gcc.dg/spellcheck-options-16.c: New test case.
* gcc.dg/spellcheck-options-17.c: New test case.

From-SVN: r244325

gcc/ChangeLog
gcc/opts.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/spellcheck-options-14.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/spellcheck-options-15.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/spellcheck-options-16.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/spellcheck-options-17.c [new file with mode: 0644]

index c9a1762..db74169 100644 (file)
@@ -1,3 +1,13 @@
+2017-01-11  David Malcolm  <dmalcolm@redhat.com>
+
+       PR driver/78877
+       * opts.c: Include "spellcheck.h"
+       (struct string_fragment): New struct.
+       (struct edit_distance_traits<const string_fragment &>): New
+       struct.
+       (get_closest_sanitizer_option): New function.
+       (parse_sanitizer_options): Offer suggestions for unrecognized arguments.
+
 2017-01-11  Jakub Jelinek  <jakub@redhat.com>
 
        * dwarf2out.c (DWARF_COMPILE_UNIT_HEADER_SIZE): For DWARF5 decrease
index c5a14e4..5f573a1 100644 (file)
@@ -30,6 +30,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "opts-diagnostic.h"
 #include "insn-attr-common.h"
 #include "common/common-target.h"
+#include "spellcheck.h"
 
 static void set_Wstrict_aliasing (struct gcc_options *opts, int onoff);
 
@@ -1511,6 +1512,65 @@ const struct sanitizer_opts_s sanitizer_opts[] =
   { NULL, 0U, 0UL, false }
 };
 
+/* A struct for describing a run of chars within a string.  */
+
+struct string_fragment
+{
+  string_fragment (const char *start, size_t len)
+  : m_start (start), m_len (len) {}
+
+  const char *m_start;
+  size_t m_len;
+};
+
+/* Specialization of edit_distance_traits for string_fragment,
+   for use by get_closest_sanitizer_option.  */
+
+template <>
+struct edit_distance_traits<const string_fragment &>
+{
+  static size_t get_length (const string_fragment &fragment)
+  {
+    return fragment.m_len;
+  }
+
+  static const char *get_string (const string_fragment &fragment)
+  {
+    return fragment.m_start;
+  }
+};
+
+/* Given ARG, an unrecognized sanitizer option, return the best
+   matching sanitizer option, or NULL if there isn't one.
+   CODE is OPT_fsanitize_ or OPT_fsanitize_recover_.
+   VALUE is non-zero for the regular form of the option, zero
+   for the "no-" form (e.g. "-fno-sanitize-recover=").  */
+
+static const char *
+get_closest_sanitizer_option (const string_fragment &arg,
+                             enum opt_code code, int value)
+{
+  best_match <const string_fragment &, const char*> bm (arg);
+  for (int i = 0; sanitizer_opts[i].name != NULL; ++i)
+    {
+      /* -fsanitize=all is not valid, so don't offer it.  */
+      if (sanitizer_opts[i].flag == ~0U
+         && code == OPT_fsanitize_
+         && value)
+       continue;
+
+      /* For -fsanitize-recover= (and not -fno-sanitize-recover=),
+        don't offer the non-recoverable options.  */
+      if (!sanitizer_opts[i].can_recover
+         && code == OPT_fsanitize_recover_
+         && value)
+       continue;
+
+      bm.consider (sanitizer_opts[i].name);
+    }
+  return bm.get_best_meaningful_candidate ();
+}
+
 /* Parse comma separated sanitizer suboptions from P for option SCODE,
    adjust previous FLAGS and return new ones.  If COMPLAIN is false,
    don't issue diagnostics.  */
@@ -1572,8 +1632,25 @@ parse_sanitizer_options (const char *p, location_t loc, int scode,
          }
 
       if (! found && complain)
-       error_at (loc, "unrecognized argument to -fsanitize%s= option: %q.*s",
-                 code == OPT_fsanitize_ ? "" : "-recover", (int) len, p);
+       {
+         const char *hint
+           = get_closest_sanitizer_option (string_fragment (p, len),
+                                           code, value);
+
+         if (hint)
+           error_at (loc,
+                     "unrecognized argument to -f%ssanitize%s= option: %q.*s;"
+                     " did you mean %qs",
+                     value ? "" : "no-",
+                     code == OPT_fsanitize_ ? "" : "-recover",
+                     (int) len, p, hint);
+         else
+           error_at (loc,
+                     "unrecognized argument to -f%ssanitize%s= option: %q.*s",
+                     value ? "" : "no-",
+                     code == OPT_fsanitize_ ? "" : "-recover",
+                     (int) len, p);
+       }
 
       if (comma == NULL)
        break;
index 2bc2120..a4987ca 100644 (file)
@@ -1,3 +1,11 @@
+2017-01-11  David Malcolm  <dmalcolm@redhat.com>
+
+       PR driver/78877
+       * gcc.dg/spellcheck-options-14.c: New test case.
+       * gcc.dg/spellcheck-options-15.c: New test case.
+       * gcc.dg/spellcheck-options-16.c: New test case.
+       * gcc.dg/spellcheck-options-17.c: New test case.
+
 2017-01-11  Martin Liska  <mliska@suse.cz>
 
        * gcc.dg/tree-ssa/flatten-3.c: Add -fno-ipa-icf to dg-options.
diff --git a/gcc/testsuite/gcc.dg/spellcheck-options-14.c b/gcc/testsuite/gcc.dg/spellcheck-options-14.c
new file mode 100644 (file)
index 0000000..5582460
--- /dev/null
@@ -0,0 +1,8 @@
+/* Verify that we offer suggestions for misspelled sanitizer options
+   (PR driver/78877).  */
+
+/* { dg-do compile } */
+/* { dg-options "-fsanitize=addres,nul,this-is-not-a-sanitizer-option" } */
+/* { dg-error "unrecognized argument to -fsanitize= option: .addres.; did you mean .address." "" { target *-*-* } 0 } */
+/* { dg-error "unrecognized argument to -fsanitize= option: .nul.; did you mean .null." "" { target *-*-* } 0 } */
+/* { dg-error "unrecognized argument to -fsanitize= option: .this-is-not-a-sanitizer-option." "" { target *-*-* } 0 } */
diff --git a/gcc/testsuite/gcc.dg/spellcheck-options-15.c b/gcc/testsuite/gcc.dg/spellcheck-options-15.c
new file mode 100644 (file)
index 0000000..089e698
--- /dev/null
@@ -0,0 +1,7 @@
+/* Verify that we don't offer -fsanitize=all as a suggestion for misspelled
+   sanitizer options (PR driver/78877).  */
+
+/* { dg-do compile } */
+/* { dg-options "-fsanitize=al" } */
+/* { dg-bogus "did you mean" "" { target *-*-* } 0 } */
+/* { dg-error "unrecognized argument to -fsanitize= option: .al." "" { target *-*-* } 0 } */
diff --git a/gcc/testsuite/gcc.dg/spellcheck-options-16.c b/gcc/testsuite/gcc.dg/spellcheck-options-16.c
new file mode 100644 (file)
index 0000000..7019576
--- /dev/null
@@ -0,0 +1,9 @@
+/* Verify that we don't offer non-recoverable options as suggestions
+   for misspelled -fsanitize-recover= arguments (PR driver/78877).  */
+
+/* { dg-do compile } */
+/* { dg-options "-fsanitize-recover=threed" } */
+/* Ensure we don't offer non-recoverable "-fsanitize-recover=thread"
+   as a suggestion.  */
+/* { dg-bogus "did you mean" "" { target *-*-* } 0 } */
+/* { dg-error "unrecognized argument to -fsanitize-recover= option: .threed." "" { target *-*-* } 0 } */
diff --git a/gcc/testsuite/gcc.dg/spellcheck-options-17.c b/gcc/testsuite/gcc.dg/spellcheck-options-17.c
new file mode 100644 (file)
index 0000000..1012dca
--- /dev/null
@@ -0,0 +1,3 @@
+/* { dg-do compile } */
+/* { dg-options "-fno-sanitize=threed" } */
+/* { dg-error "unrecognized argument to -fno-sanitize= option: .threed.; did you mean .thread." "" { target *-*-* } 0 } */