@@ -215,7 +215,7 @@ static inline void process_marked_switch
static const char *process_brace_body (const char *, const char *, const char *, int, int);
static const struct spec_function *lookup_spec_function (const char *);
static const char *eval_spec_function (const char *, const char *);
-static const char *handle_spec_function (const char *);
+static const char *handle_spec_function (const char *, bool *);
static char *save_string (const char *, int);
static void set_collect_gcc_options (void);
static int do_spec_1 (const char *, int, const char *);
@@ -253,6 +253,7 @@ static const char *convert_filename (con
static const char *getenv_spec_function (int, const char **);
static const char *if_exists_spec_function (int, const char **);
static const char *if_exists_else_spec_function (int, const char **);
+static const char *sanitize_spec_function (int, const char **);
static const char *replace_outfile_spec_function (int, const char **);
static const char *remove_outfile_spec_function (int, const char **);
static const char *version_compare_spec_function (int, const char **);
@@ -432,6 +433,10 @@ or with constant text in a single argume
than the OR.
If %* appears in X, all of the alternatives must be starred, and
only the first matching alternative is substituted.
+ %{%:function(args):X}
+ Call function named FUNCTION with args ARGS. If the function
+ returns non-NULL, then X is substituted, if it returns
+ NULL, it isn't substituted.
%{S:X; if S was given to GCC, substitutes X;
T:Y; else if T was given to GCC, substitutes Y;
:D} else substitutes D. There can be as many clauses as you need.
@@ -708,17 +713,17 @@ proper position among the other output f
/* Linker command line options for -fsanitize= early on the command line. */
#ifndef SANITIZER_EARLY_SPEC
#define SANITIZER_EARLY_SPEC "\
-%{!nostdlib:%{!nodefaultlibs:%{fsanitize=address:" LIBASAN_EARLY_SPEC "} \
- %{fsanitize=thread:" LIBTSAN_EARLY_SPEC "}}}"
+%{!nostdlib:%{!nodefaultlibs:%{%:sanitize(address):" LIBASAN_EARLY_SPEC "} \
+ %{%:sanitize(thread):" LIBTSAN_EARLY_SPEC "}}}"
#endif
/* Linker command line options for -fsanitize= late on the command line. */
#ifndef SANITIZER_SPEC
#define SANITIZER_SPEC "\
-%{!nostdlib:%{!nodefaultlibs:%{fsanitize=address:" LIBASAN_SPEC "\
+%{!nostdlib:%{!nodefaultlibs:%{%:sanitize(address):" LIBASAN_SPEC "\
%{static:%ecannot specify -static with -fsanitize=address}\
- %{fsanitize=thread:%e-fsanitize=address is incompatible with -fsanitize=thread}}\
- %{fsanitize=thread:" LIBTSAN_SPEC "\
+ %{%:sanitize(thread):%e-fsanitize=address is incompatible with -fsanitize=thread}}\
+ %{%:sanitize(thread):" LIBTSAN_SPEC "\
%{!pie:%{!shared:%e-fsanitize=thread linking must be done with -pie or -shared}}}}}"
#endif
@@ -1323,6 +1328,7 @@ static const struct spec_function static
{ "getenv", getenv_spec_function },
{ "if-exists", if_exists_spec_function },
{ "if-exists-else", if_exists_else_spec_function },
+ { "sanitize", sanitize_spec_function },
{ "replace-outfile", replace_outfile_spec_function },
{ "remove-outfile", remove_outfile_spec_function },
{ "version-compare", version_compare_spec_function },
@@ -5273,7 +5279,7 @@ do_spec_1 (const char *spec, int inswitc
break;
case ':':
- p = handle_spec_function (p);
+ p = handle_spec_function (p, NULL);
if (p == 0)
return -1;
break;
@@ -5509,10 +5515,13 @@ eval_spec_function (const char *func, co
ARGS is processed as a spec in a separate context and split into an
argument vector in the normal fashion. The function returns a string
containing a spec which we then process in the caller's context, or
- NULL if no processing is required. */
+ NULL if no processing is required.
+
+ If RETVAL_NONNULL is not NULL, then store a bool whether function
+ returned non-NULL. */
static const char *
-handle_spec_function (const char *p)
+handle_spec_function (const char *p, bool *retval_nonnull)
{
char *func, *args;
const char *endp, *funcval;
@@ -5558,6 +5567,8 @@ handle_spec_function (const char *p)
funcval = eval_spec_function (func, args);
if (funcval != NULL && do_spec_1 (funcval, 0, NULL) < 0)
p = NULL;
+ if (retval_nonnull)
+ *retval_nonnull = funcval != NULL;
free (func);
free (args);
@@ -5701,19 +5712,28 @@ handle_braces (const char *p)
p++, a_is_negated = true;
SKIP_WHITE();
- if (*p == '.')
- p++, a_is_suffix = true;
- else if (*p == ',')
- p++, a_is_spectype = true;
-
- atom = p;
- while (ISIDNUM(*p) || *p == '-' || *p == '+' || *p == '='
- || *p == ',' || *p == '.' || *p == '@')
- p++;
- end_atom = p;
+ if (*p == '%' && p[1] == ':')
+ {
+ atom = NULL;
+ end_atom = NULL;
+ p = handle_spec_function (p + 2, &a_matched);
+ }
+ else
+ {
+ if (*p == '.')
+ p++, a_is_suffix = true;
+ else if (*p == ',')
+ p++, a_is_spectype = true;
+
+ atom = p;
+ while (ISIDNUM(*p) || *p == '-' || *p == '+' || *p == '='
+ || *p == ',' || *p == '.' || *p == '@')
+ p++;
+ end_atom = p;
- if (*p == '*')
- p++, a_is_starred = 1;
+ if (*p == '*')
+ p++, a_is_starred = 1;
+ }
SKIP_WHITE();
switch (*p)
@@ -5738,7 +5758,7 @@ handle_braces (const char *p)
if (ordered_set)
goto invalid;
- if (atom == end_atom)
+ if (atom && atom == end_atom)
{
if (!n_way_choice || disj_matched || *p == '|'
|| a_is_negated || a_is_suffix || a_is_spectype
@@ -5763,7 +5783,9 @@ handle_braces (const char *p)
match. */
if (!disj_matched && !n_way_matched)
{
- if (a_is_suffix)
+ if (atom == NULL)
+ /* a_matched is already set by handle_spec_function. */;
+ else if (a_is_suffix)
a_matched = input_suffix_matches (atom, end_atom);
else if (a_is_spectype)
a_matched = input_spec_matches (atom, end_atom);
@@ -8060,6 +8082,27 @@ if_exists_else_spec_function (int argc,
return argv[1];
}
+/* sanitize built-in spec function.
+
+ This returns non-NULL, if sanitizing address, thread or
+ any of the undefined behavior sanitizers. */
+
+static const char *
+sanitize_spec_function (int argc, const char **argv)
+{
+ if (argc != 1)
+ return NULL;
+
+ if (strcmp (argv[0], "address") == 0)
+ return (flag_sanitize & SANITIZE_ADDRESS) ? "" : NULL;
+ if (strcmp (argv[0], "thread") == 0)
+ return (flag_sanitize & SANITIZE_THREAD) ? "" : NULL;
+ if (strcmp (argv[0], "undefined") == 0)
+ return (flag_sanitize & SANITIZE_UNDEFINED) ? "" : NULL;
+
+ return NULL;
+}
+
/* replace-outfile built-in spec function.
This looks for the first argument in the outfiles array's name and
@@ -855,6 +855,6 @@ Common Ignore
Does nothing. Preserved for backward compatibility.
fsanitize=
-Common Report Joined
+Common Driver Report Joined
Select what to sanitize
@@ -178,7 +178,7 @@ extern GTY(()) int darwin_ms_struct;
%{L*} %(link_libgcc) %o %{fprofile-arcs|fprofile-generate*|coverage:-lgcov} \
%{fopenmp|ftree-parallelize-loops=*: \
%{static|static-libgcc|static-libstdc++|static-libgfortran: libgomp.a%s; : -lgomp } } \
- %{fsanitize=address: -lasan } \
+ %{%:sanitize(address): -lasan } \
%{fgnu-tm: \
%{static|static-libgcc|static-libstdc++|static-libgfortran: libitm.a%s; : -litm } } \
%{!nostdlib:%{!nodefaultlibs:\
@@ -85,7 +85,7 @@
LINUX_TARGET_LINK_SPEC " " ANDROID_LINK_SPEC)
#undef ASAN_CC1_SPEC
-#define ASAN_CC1_SPEC "%{fsanitize=*:-funwind-tables}"
+#define ASAN_CC1_SPEC "%{%:sanitize(address):-funwind-tables}"
#undef CC1_SPEC
#define CC1_SPEC \