+/* -f{,no-}sanitize{,-recover}= suboptions. */
+const struct sanitizer_opts_s sanitizer_opts[] =
+{
+#define SANITIZER_OPT(name, flags) { #name, flags, sizeof #name - 1 }
+ SANITIZER_OPT (address, SANITIZE_ADDRESS | SANITIZE_USER_ADDRESS),
+ SANITIZER_OPT (kernel-address, SANITIZE_ADDRESS | SANITIZE_KERNEL_ADDRESS),
+ SANITIZER_OPT (thread, SANITIZE_THREAD),
+ SANITIZER_OPT (leak, SANITIZE_LEAK),
+ SANITIZER_OPT (shift, SANITIZE_SHIFT),
+ SANITIZER_OPT (integer-divide-by-zero, SANITIZE_DIVIDE),
+ SANITIZER_OPT (undefined, SANITIZE_UNDEFINED),
+ SANITIZER_OPT (unreachable, SANITIZE_UNREACHABLE),
+ SANITIZER_OPT (vla-bound, SANITIZE_VLA),
+ SANITIZER_OPT (return, SANITIZE_RETURN),
+ SANITIZER_OPT (null, SANITIZE_NULL),
+ SANITIZER_OPT (signed-integer-overflow, SANITIZE_SI_OVERFLOW),
+ SANITIZER_OPT (bool, SANITIZE_BOOL),
+ SANITIZER_OPT (enum, SANITIZE_ENUM),
+ SANITIZER_OPT (float-divide-by-zero, SANITIZE_FLOAT_DIVIDE),
+ SANITIZER_OPT (float-cast-overflow, SANITIZE_FLOAT_CAST),
+ SANITIZER_OPT (bounds, SANITIZE_BOUNDS),
+ SANITIZER_OPT (bounds-strict, SANITIZE_BOUNDS | SANITIZE_BOUNDS_STRICT),
+ SANITIZER_OPT (alignment, SANITIZE_ALIGNMENT),
+ SANITIZER_OPT (nonnull-attribute, SANITIZE_NONNULL_ATTRIBUTE),
+ SANITIZER_OPT (returns-nonnull-attribute, SANITIZE_RETURNS_NONNULL_ATTRIBUTE),
+ SANITIZER_OPT (object-size, SANITIZE_OBJECT_SIZE),
+ SANITIZER_OPT (vptr, SANITIZE_VPTR),
+ SANITIZER_OPT (all, ~0),
+#undef SANITIZER_OPT
+ { NULL, 0, 0 }
+};
+
+/* 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. */
+
+unsigned int
+parse_sanitizer_options (const char *p, location_t loc, int scode,
+ unsigned int flags, int value, bool complain)
+{
+ enum opt_code code = (enum opt_code) scode;
+ while (*p != 0)
+ {
+ size_t len, i;
+ bool found = false;
+ const char *comma = strchr (p, ',');
+
+ if (comma == NULL)
+ len = strlen (p);
+ else
+ len = comma - p;
+ if (len == 0)
+ {
+ p = comma + 1;
+ continue;
+ }
+
+ /* Check to see if the string matches an option class name. */
+ for (i = 0; sanitizer_opts[i].name != NULL; ++i)
+ if (len == sanitizer_opts[i].len
+ && memcmp (p, sanitizer_opts[i].name, len) == 0)
+ {
+ /* Handle both -fsanitize and -fno-sanitize cases. */
+ if (value && sanitizer_opts[i].flag == ~0U)
+ {
+ if (code == OPT_fsanitize_)
+ {
+ if (complain)
+ error_at (loc, "-fsanitize=all option is not valid");
+ }
+ else
+ flags |= ~(SANITIZE_USER_ADDRESS | SANITIZE_THREAD
+ | SANITIZE_LEAK);
+ }
+ else if (value)
+ flags |= sanitizer_opts[i].flag;
+ else
+ flags &= ~sanitizer_opts[i].flag;
+ found = true;
+ break;
+ }
+
+ if (! found && complain)
+ error_at (loc, "unrecognized argument to -fsanitize%s= option: %q.*s",
+ code == OPT_fsanitize_ ? "" : "-recover", (int) len, p);
+
+ if (comma == NULL)
+ break;
+ p = comma + 1;
+ }
+ return flags;
+}
+