X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=gcc%2Fgcc.c;h=d956c36b151eea45681aa650c39c522f85be359f;hb=c72f37e6aef8ddef3b27bdc981c77f6702337702;hp=86077f8cf321ad1ed3a3897b1259ddc06d71eeca;hpb=3c27ce4cd4de1b9fd7d4e39d3bd56b6a75115537;p=gcc.git diff --git a/gcc/gcc.c b/gcc/gcc.c index 86077f8cf32..d956c36b151 100644 --- a/gcc/gcc.c +++ b/gcc/gcc.c @@ -1,5 +1,5 @@ /* Compiler driver program that can handle many languages. - Copyright (C) 1987-2013 Free Software Foundation, Inc. + Copyright (C) 1987-2015 Free Software Foundation, Inc. This file is part of GCC. @@ -105,6 +105,9 @@ static int verbose_only_flag; static int print_subprocess_help; +/* Linker suffix passed to -fuse-ld=... */ +static const char *use_ld; + /* Whether we should report subprocess execution times to a file. */ FILE *report_times_to_file = NULL; @@ -154,6 +157,11 @@ static const char *const spec_version = DEFAULT_TARGET_VERSION; /* The target machine. */ static const char *spec_machine = DEFAULT_TARGET_MACHINE; +static const char *spec_host_machine = DEFAULT_REAL_TARGET_MACHINE; + +/* List of offload targets. */ + +static char *offload_targets = NULL; /* Nonzero if cross-compiling. When -b is used, the value comes from the `specs' file. */ @@ -215,7 +223,7 @@ static inline void process_marked_switches (void); 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 *); @@ -250,9 +258,11 @@ static void init_gcc_specs (struct obstack *, const char *, const char *, static const char *convert_filename (const char *, int, int); #endif +static void try_generate_repro (const char **argv); 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 **); @@ -387,7 +397,8 @@ or with constant text in a single argument. %2 process CC1PLUS_SPEC as a spec. %* substitute the variable part of a matched option. (See below.) Note that each comma in the substituted string is replaced by - a single space. + a single space. A space is appended after the last substition + unless there is more text in current sequence. %= 2 */ +#if HAVE_AS_COMPRESS_DEBUG == 0 +/* No assembler support. Ignore silently. */ +#define ASM_COMPRESS_DEBUG_SPEC \ + " %{gz*:} " +#elif HAVE_AS_COMPRESS_DEBUG == 1 +/* GNU style, GNU as options. */ +#define ASM_COMPRESS_DEBUG_SPEC \ + " %{gz|gz=zlib-gnu:" AS_COMPRESS_DEBUG_OPTION "}" \ + " %{gz=none:" AS_NO_COMPRESS_DEBUG_OPTION "}" \ + " %{gz=zlib:%e-gz=zlib is not supported in this configuration} " +#elif HAVE_AS_COMPRESS_DEBUG == 2 +/* ELF gABI style. */ +#define ASM_COMPRESS_DEBUG_SPEC \ + " %{gz|gz=zlib:" AS_COMPRESS_DEBUG_OPTION "=zlib}" \ + " %{gz=none:" AS_COMPRESS_DEBUG_OPTION "=none}" \ + " %{gz=zlib-gnu:" AS_COMPRESS_DEBUG_OPTION "=zlib-gnu} " +#else +#error Unknown value for HAVE_AS_COMPRESS_DEBUG. +#endif +#endif /* HAVE_LD_COMPRESS_DEBUG >= 2 */ + /* Define ASM_DEBUG_SPEC to be a spec suitable for translating '-g' to the assembler. */ #ifndef ASM_DEBUG_SPEC @@ -627,7 +702,7 @@ proper position among the other output files. */ && defined(HAVE_AS_GDWARF2_DEBUG_FLAG) && defined(HAVE_AS_GSTABS_DEBUG_FLAG) # define ASM_DEBUG_SPEC \ (PREFERRED_DEBUGGING_TYPE == DBX_DEBUG \ - ? "%{!g0:%{gdwarf-2*:--gdwarf2}%{!gdwarf-2*:%{g*:--gstabs}}}" ASM_MAP \ + ? "%{!g0:%{gdwarf*:--gdwarf2}%{!gdwarf*:%{g*:--gstabs}}}" ASM_MAP \ : "%{!g0:%{gstabs*:--gstabs}%{!gstabs*:%{g*:--gdwarf2}}}" ASM_MAP) # else # if defined(DBX_DEBUGGING_INFO) && defined(HAVE_AS_GSTABS_DEBUG_FLAG) @@ -653,9 +728,12 @@ proper position among the other output files. */ #ifndef LINK_SSP_SPEC #ifdef TARGET_LIBC_PROVIDES_SSP -#define LINK_SSP_SPEC "%{fstack-protector:}" +#define LINK_SSP_SPEC "%{fstack-protector|fstack-protector-all" \ + "|fstack-protector-strong|fstack-protector-explicit:}" #else -#define LINK_SSP_SPEC "%{fstack-protector|fstack-protector-all:-lssp_nonshared -lssp}" +#define LINK_SSP_SPEC "%{fstack-protector|fstack-protector-all" \ + "|fstack-protector-strong|fstack-protector-explicit" \ + ":-lssp_nonshared -lssp}" #endif #endif @@ -684,7 +762,7 @@ proper position among the other output files. */ #if HAVE_LTO_PLUGIN > 0 /* The linker used has full plugin support, use LTO plugin by default. */ #if HAVE_LTO_PLUGIN == 2 -#define PLUGIN_COND "!fno-use-linker-plugin:%{flto|flto=*|fuse-linker-plugin" +#define PLUGIN_COND "!fno-use-linker-plugin:%{!fno-lto" #define PLUGIN_COND_CLOSE "}" #else /* The linker used has limited plugin support, use LTO plugin with explicit @@ -708,17 +786,34 @@ proper position among the other output files. */ /* 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 "} \ + %{%:sanitize(leak):" LIBLSAN_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:" LIBTSAN_SPEC "\ - %{!pie:%{!shared:%e-fsanitize=thread linking must be done with -pie or -shared}}}}}" + %{%:sanitize(thread):" LIBTSAN_SPEC "\ + %{static:%ecannot specify -static with -fsanitize=thread}}\ + %{%:sanitize(undefined):" LIBUBSAN_SPEC "}\ + %{%:sanitize(leak):" LIBLSAN_SPEC "}}}" +#endif + +/* This is the spec to use, once the code for creating the vtable + verification runtime library, libvtv.so, has been created. Currently + the vtable verification runtime functions are in libstdc++, so we use + the spec just below this one. */ +#ifndef VTABLE_VERIFICATION_SPEC +#define VTABLE_VERIFICATION_SPEC "\ +%{!nostdlib:%{fvtable-verify=std: -lvtv -u_vtable_map_vars_start -u_vtable_map_vars_end}\ + %{fvtable-verify=preinit: -lvtv -u_vtable_map_vars_start -u_vtable_map_vars_end}}" +#endif + +#ifndef CHKP_SPEC +#define CHKP_SPEC "" #endif /* -u* was put back because both BSD and SysV seem to support it. */ @@ -736,12 +831,14 @@ proper position among the other output files. */ %(linker) " \ LINK_PLUGIN_SPEC \ "%{flto|flto=*:%alloc_p) - free (CONST_CAST(char *, old_spec)); + free (CONST_CAST (char *, old_spec)); sl->user_p = user_p; sl->alloc_p = true; @@ -1616,17 +1719,15 @@ typedef const char *const_char_p; /* For DEF_VEC_P. */ static vec argbuf; -/* Position in the argbuf vector containing the name of the output file - (the value associated with the "-o" flag). */ - -static int have_o_argbuf_index = 0; - /* Were the options -c, -S or -E passed. */ static int have_c = 0; /* Was the option -o passed. */ static int have_o = 0; +/* Pointer to output file name passed in with -o. */ +static const char *output_file = 0; + /* This is the list of suffixes and codes (%g/%u/%U/%j) and the associated temp file. If the HOST_BIT_BUCKET is used for %j, no entry is made for it here. */ @@ -1676,8 +1777,6 @@ store_arg (const char *arg, int delete_always, int delete_failure) { argbuf.safe_push (arg); - if (strcmp (arg, "-o") == 0) - have_o_argbuf_index = argbuf.length (); if (delete_always || delete_failure) { const char *p; @@ -1802,7 +1901,8 @@ read_specs (const char *filename, bool main_p, bool user_p) p1++; if (*p1++ != '<' || p[-2] != '>') - fatal_error ("specs %%include syntax malformed after " + fatal_error (input_location, + "specs %%include syntax malformed after " "%ld characters", (long) (p1 - buffer + 1)); @@ -1822,7 +1922,8 @@ read_specs (const char *filename, bool main_p, bool user_p) p1++; if (*p1++ != '<' || p[-2] != '>') - fatal_error ("specs %%include syntax malformed after " + fatal_error (input_location, + "specs %%include syntax malformed after " "%ld characters", (long) (p1 - buffer + 1)); @@ -1848,7 +1949,8 @@ read_specs (const char *filename, bool main_p, bool user_p) p1++; if (! ISALPHA ((unsigned char) *p1)) - fatal_error ("specs %%rename syntax malformed after " + fatal_error (input_location, + "specs %%rename syntax malformed after " "%ld characters", (long) (p1 - buffer)); @@ -1857,7 +1959,8 @@ read_specs (const char *filename, bool main_p, bool user_p) p2++; if (*p2 != ' ' && *p2 != '\t') - fatal_error ("specs %%rename syntax malformed after " + fatal_error (input_location, + "specs %%rename syntax malformed after " "%ld characters", (long) (p2 - buffer)); @@ -1867,7 +1970,8 @@ read_specs (const char *filename, bool main_p, bool user_p) p2++; if (! ISALPHA ((unsigned char) *p2)) - fatal_error ("specs %%rename syntax malformed after " + fatal_error (input_location, + "specs %%rename syntax malformed after " "%ld characters", (long) (p2 - buffer)); @@ -1877,7 +1981,8 @@ read_specs (const char *filename, bool main_p, bool user_p) p3++; if (p3 != p - 1) - fatal_error ("specs %%rename syntax malformed after " + fatal_error (input_location, + "specs %%rename syntax malformed after " "%ld characters", (long) (p3 - buffer)); *p3 = '\0'; @@ -1887,14 +1992,16 @@ read_specs (const char *filename, bool main_p, bool user_p) break; if (!sl) - fatal_error ("specs %s spec was not found to be renamed", p1); + fatal_error (input_location, + "specs %s spec was not found to be renamed", p1); if (strcmp (p1, p2) == 0) continue; for (newsl = specs; newsl; newsl = newsl->next) if (strcmp (newsl->name, p2) == 0) - fatal_error ("%s: attempt to rename spec %qs to " + fatal_error (input_location, + "%s: attempt to rename spec %qs to " "already defined spec %qs", filename, p1, p2); @@ -1915,7 +2022,8 @@ read_specs (const char *filename, bool main_p, bool user_p) continue; } else - fatal_error ("specs unknown %% command after %ld characters", + fatal_error (input_location, + "specs unknown %% command after %ld characters", (long) (p1 - buffer)); } @@ -1926,7 +2034,8 @@ read_specs (const char *filename, bool main_p, bool user_p) /* The colon shouldn't be missing. */ if (*p1 != ':') - fatal_error ("specs file malformed after %ld characters", + fatal_error (input_location, + "specs file malformed after %ld characters", (long) (p1 - buffer)); /* Skip back over trailing whitespace. */ @@ -1939,7 +2048,8 @@ read_specs (const char *filename, bool main_p, bool user_p) /* Find the next line. */ p = skip_whitespace (p1 + 1); if (p[1] == 0) - fatal_error ("specs file malformed after %ld characters", + fatal_error (input_location, + "specs file malformed after %ld characters", (long) (p - buffer)); p1 = p; @@ -1991,7 +2101,7 @@ read_specs (const char *filename, bool main_p, bool user_p) } if (link_command_spec == 0) - fatal_error ("spec file has no spec for linking"); + fatal_error (input_location, "spec file has no spec for linking"); } /* Record the names of temporary files we tell compilers to write, @@ -2448,7 +2558,7 @@ find_a_file (const struct path_prefix *pprefix, const char *name, int mode, #endif #ifdef DEFAULT_LINKER - if (! strcmp(name, "ld") && access (DEFAULT_LINKER, mode) == 0) + if (! strcmp (name, "ld") && access (DEFAULT_LINKER, mode) == 0) return xstrdup (DEFAULT_LINKER); #endif @@ -2536,7 +2646,7 @@ add_sysrooted_prefix (struct path_prefix *pprefix, const char *prefix, int require_machine_suffix, int os_multilib) { if (!IS_ABSOLUTE_PATH (prefix)) - fatal_error ("system path %qs is not absolute", prefix); + fatal_error (input_location, "system path %qs is not absolute", prefix); if (target_system_root) { @@ -2624,7 +2734,7 @@ execute (void) if (arg && strcmp (arg, "|") == 0) { /* each command. */ #if defined (__MSDOS__) || defined (OS2) || defined (VMS) - fatal_error ("-pipe not supported"); + fatal_error (input_location, "-pipe not supported"); #endif argbuf[i] = 0; /* Termination of command args. */ @@ -2747,7 +2857,7 @@ execute (void) ? PEX_RECORD_TIMES : 0), progname, temp_filename); if (pex == NULL) - fatal_error ("pex_init failed: %m"); + fatal_error (input_location, "pex_init failed: %m"); for (i = 0; i < n_commands; i++) { @@ -2763,7 +2873,7 @@ execute (void) if (errmsg != NULL) { if (err == 0) - fatal_error (errmsg); + fatal_error (input_location, errmsg); else { errno = err; @@ -2771,7 +2881,7 @@ execute (void) } } - if (string != commands[i].prog) + if (i && string != commands[i].prog) free (CONST_CAST (char *, string)); } @@ -2786,13 +2896,13 @@ execute (void) statuses = (int *) alloca (n_commands * sizeof (int)); if (!pex_get_status (pex, n_commands, statuses)) - fatal_error ("failed to get exit status: %m"); + fatal_error (input_location, "failed to get exit status: %m"); if (report_times || report_times_to_file) { times = (struct pex_time *) alloca (n_commands * sizeof (struct pex_time)); if (!pex_get_times (pex, n_commands, times)) - fatal_error ("failed to get process times: %m"); + fatal_error (input_location, "failed to get process times: %m"); } pex_free (pex); @@ -2818,12 +2928,22 @@ execute (void) } else #endif - internal_error ("%s (program %s)", - strsignal (WTERMSIG (status)), commands[i].prog); + internal_error_no_backtrace ("%s (program %s)", + strsignal (WTERMSIG (status)), + commands[i].prog); } else if (WIFEXITED (status) && WEXITSTATUS (status) >= MIN_FATAL_STATUS) { + /* For ICEs in cc1, cc1obj, cc1plus see if it is + reproducible or not. */ + const char *p; + if (flag_report_bug + && WEXITSTATUS (status) == ICE_EXIT_CODE + && i == 0 + && (p = strrchr (commands[0].argv[0], DIR_SEPARATOR)) + && ! strncmp (p + 1, "cc1", 3)) + try_generate_repro (commands[0].argv); if (WEXITSTATUS (status) > greatest_status) greatest_status = WEXITSTATUS (status); ret_code = -1; @@ -2881,6 +3001,9 @@ execute (void) } } + if (commands[0].argv[0] != commands[0].prog) + free (CONST_CAST (char *, commands[0].argv[0])); + return ret_code; } } @@ -3260,6 +3383,103 @@ driver_wrong_lang_callback (const struct cl_decoded_option *decoded, static const char *spec_lang = 0; static int last_language_n_infiles; +/* Parse -foffload option argument. */ + +static void +handle_foffload_option (const char *arg) +{ + const char *c, *cur, *n, *next, *end; + char *target; + + /* If option argument starts with '-' then no target is specified and we + do not need to parse it. */ + if (arg[0] == '-') + return; + + end = strchr (arg, '='); + if (end == NULL) + end = strchr (arg, '\0'); + cur = arg; + + while (cur < end) + { + next = strchr (cur, ','); + if (next == NULL) + next = end; + next = (next > end) ? end : next; + + target = XNEWVEC (char, next - cur + 1); + memcpy (target, cur, next - cur); + target[next - cur] = '\0'; + + /* If 'disable' is passed to the option, stop parsing the option and clean + the list of offload targets. */ + if (strcmp (target, "disable") == 0) + { + free (offload_targets); + offload_targets = xstrdup (""); + break; + } + + /* Check that GCC is configured to support the offload target. */ + c = OFFLOAD_TARGETS; + while (c) + { + n = strchr (c, ','); + if (n == NULL) + n = strchr (c, '\0'); + + if (next - cur == n - c && strncmp (target, c, n - c) == 0) + break; + + c = *n ? n + 1 : NULL; + } + + if (!c) + fatal_error (input_location, + "GCC is not configured to support %s as offload target", + target); + + if (!offload_targets) + { + offload_targets = target; + target = NULL; + } + else + { + /* Check that the target hasn't already presented in the list. */ + c = offload_targets; + do + { + n = strchr (c, ':'); + if (n == NULL) + n = strchr (c, '\0'); + + if (next - cur == n - c && strncmp (c, target, n - c) == 0) + break; + + c = n + 1; + } + while (*n); + + /* If duplicate is not found, append the target to the list. */ + if (c > n) + { + size_t offload_targets_len = strlen (offload_targets); + offload_targets + = XRESIZEVEC (char, offload_targets, + offload_targets_len + next - cur + 2); + if (offload_targets_len) + offload_targets[offload_targets_len++] = ':'; + memcpy (offload_targets + offload_targets_len, target, next - cur); + } + } + + cur = next + 1; + XDELETEVEC (target); + } +} + /* Handle a driver option; arguments and return value as for handle_option. */ @@ -3364,6 +3584,14 @@ driver_handle_option (struct gcc_options *opts, do_save = false; break; + case OPT_fuse_ld_bfd: + use_ld = ".bfd"; + break; + + case OPT_fuse_ld_gold: + use_ld = ".gold"; + break; + case OPT_fcompare_debug_second: compare_debug_second = 1; break; @@ -3402,6 +3630,10 @@ driver_handle_option (struct gcc_options *opts, save_switch (compare_debug_replacement_opt, 0, NULL, validated, true); return true; + case OPT_fdiagnostics_color_: + diagnostic_color_init (dc, value); + break; + case OPT_Wa_: { int prev, j; @@ -3504,7 +3736,7 @@ driver_handle_option (struct gcc_options *opts, || strcmp (arg, "object") == 0) save_temps_flag = SAVE_TEMPS_OBJ; else - fatal_error ("%qs is an unknown -save-temps option", + fatal_error (input_location, "%qs is an unknown -save-temps option", decoded->orig_option_with_args_text); break; @@ -3607,6 +3839,7 @@ driver_handle_option (struct gcc_options *opts, #if defined(HAVE_TARGET_EXECUTABLE_SUFFIX) || defined(HAVE_TARGET_OBJECT_SUFFIX) arg = convert_filename (arg, ! have_c, 0); #endif + output_file = arg; /* Save the output name in case -save-temps=obj was used. */ save_temps_prefix = xstrdup (arg); /* On some systems, ld cannot handle "-o" without a space. So @@ -3624,6 +3857,14 @@ driver_handle_option (struct gcc_options *opts, validated = true; break; + case OPT_fwpa: + flag_wpa = ""; + break; + + case OPT_foffload_: + handle_foffload_option (arg); + break; + default: /* Various driver options need no special processing at this point, having been handled in a prescan above or being @@ -3942,6 +4183,19 @@ process_command (unsigned int decoded_options_count, CL_DRIVER, &handlers, global_dc); } + if (output_file + && strcmp (output_file, "-") != 0 + && strcmp (output_file, HOST_BIT_BUCKET) != 0) + { + int i; + for (i = 0; i < n_infiles; i++) + if ((!infiles[i].language || infiles[i].language[0] != '*') + && canonical_filename_eq (infiles[i].name, output_file)) + fatal_error (input_location, + "input file %qs is the same as output file", + output_file); + } + /* If -save-temps=obj and -o name, create the prefix to use for %b. Otherwise just make -save-temps=obj the same as -save-temps=cwd. */ if (save_temps_flag == SAVE_TEMPS_OBJ && save_temps_prefix != NULL) @@ -4012,15 +4266,15 @@ process_command (unsigned int decoded_options_count, } gcc_assert (!IS_ABSOLUTE_PATH (tooldir_base_prefix)); - tooldir_prefix2 = concat (tooldir_base_prefix, spec_machine, + tooldir_prefix2 = concat (tooldir_base_prefix, spec_host_machine, dir_separator_str, NULL); /* Look for tools relative to the location from which the driver is running, or, if that is not available, the configured prefix. */ tooldir_prefix = concat (gcc_exec_prefix ? gcc_exec_prefix : standard_exec_prefix, - spec_machine, dir_separator_str, - spec_version, dir_separator_str, tooldir_prefix2, NULL); + spec_host_machine, dir_separator_str, spec_version, + accel_dir_suffix, dir_separator_str, tooldir_prefix2, NULL); free (tooldir_prefix2); add_prefix (&exec_prefixes, @@ -4419,10 +4673,12 @@ do_self_spec (const char *spec) /* Specs should only generate options, not input files. */ if (strcmp (decoded_options[j].arg, "-") != 0) - fatal_error ("switch %qs does not start with %<-%>", + fatal_error (input_location, + "switch %qs does not start with %<-%>", decoded_options[j].arg); else - fatal_error ("spec-generated switch is just %<-%>"); + fatal_error (input_location, + "spec-generated switch is just %<-%>"); break; case OPT_fcompare_debug_second: @@ -4445,6 +4701,8 @@ do_self_spec (const char *spec) } } + free (decoded_options); + alloc_switch (); switches[n_switches].part1 = 0; } @@ -4513,19 +4771,20 @@ create_at_file (char **argv) int status; if (f == NULL) - fatal_error ("could not open temporary response file %s", + fatal_error (input_location, "could not open temporary response file %s", temp_file); status = writeargv (argv, f); if (status) - fatal_error ("could not write to temporary response file %s", + fatal_error (input_location, + "could not write to temporary response file %s", temp_file); status = fclose (f); if (EOF == status) - fatal_error ("could not close temporary response file %s", + fatal_error (input_location, "could not close temporary response file %s", temp_file); store_arg (at_argument, 0, 0); @@ -4648,7 +4907,7 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part) switch (c = *p++) { case 0: - fatal_error ("spec %qs invalid", spec); + fatal_error (input_location, "spec %qs invalid", spec); case 'b': if (save_temps_length) @@ -4797,14 +5056,15 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part) p += 2; /* We don't support extra suffix characters after %O. */ if (*p == '.' || ISALNUM ((unsigned char) *p)) - fatal_error ("spec %qs has invalid %<%%0%c%>", spec, *p); + fatal_error (input_location, + "spec %qs has invalid %<%%0%c%>", spec, *p); if (suffix_length == 0) suffix = TARGET_OBJECT_SUFFIX; else { saved_suffix = XNEWVEC (char, suffix_length - + strlen (TARGET_OBJECT_SUFFIX)); + + strlen (TARGET_OBJECT_SUFFIX) + 1); strncpy (saved_suffix, suffix, suffix_length); strcpy (saved_suffix + suffix_length, TARGET_OBJECT_SUFFIX); @@ -5116,7 +5376,8 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part) unsigned int cur_index = argbuf.length (); /* Handle the {...} following the %W. */ if (*p != '{') - fatal_error ("spec %qs has invalid %<%%W%c%>", spec, *p); + fatal_error (input_location, + "spec %qs has invalid %<%%W%c%>", spec, *p); p = handle_braces (p + 1); if (p == 0) return -1; @@ -5138,7 +5399,8 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part) /* Skip past the option value and make a copy. */ if (*p != '{') - fatal_error ("spec %qs has invalid %<%%x%c%>", spec, *p); + fatal_error (input_location, + "spec %qs has invalid %<%%x%c%>", spec, *p); while (*p++ != '}') ; string = save_string (p1 + 1, p - p1 - 2); @@ -5271,7 +5533,7 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part) break; case ':': - p = handle_spec_function (p); + p = handle_spec_function (p, NULL); if (p == 0) return -1; break; @@ -5333,7 +5595,17 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part) { if (soft_matched_part[0]) do_spec_1 (soft_matched_part, 1, NULL); - do_spec_1 (" ", 0, NULL); + /* Only insert a space after the substitution if it is at the + end of the current sequence. So if: + + "%{foo=*:bar%*}%{foo=*:one%*two}" + + matches -foo=hello then it will produce: + + barhello onehellotwo + */ + if (*p == 0 || *p == '}') + do_spec_1 (" ", 0, NULL); } else /* Catch the case where a spec string contains something like @@ -5440,11 +5712,11 @@ eval_spec_function (const char *func, const char *args) const char *save_suffix_subst; int save_growing_size; - void *save_growing_value; + void *save_growing_value = NULL; sf = lookup_spec_function (func); if (sf == NULL) - fatal_error ("unknown spec function %qs", func); + fatal_error (input_location, "unknown spec function %qs", func); /* Push the spec processing context. */ save_argbuf = argbuf; @@ -5474,7 +5746,7 @@ eval_spec_function (const char *func, const char *args) alloc_args (); if (do_spec_2 (args) < 0) - fatal_error ("error in args to spec function %qs", func); + fatal_error (input_location, "error in args to spec function %qs", func); /* argbuf_index is an index for the next argument to be inserted, and so contains the count of the args already inserted. */ @@ -5507,10 +5779,13 @@ eval_spec_function (const char *func, const char *args) 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; @@ -5525,10 +5800,10 @@ handle_spec_function (const char *p) break; /* Only allow [A-Za-z0-9], -, and _ in function names. */ if (!ISALNUM (*endp) && !(*endp == '-' || *endp == '_')) - fatal_error ("malformed spec function name"); + fatal_error (input_location, "malformed spec function name"); } if (*endp != '(') /* ) */ - fatal_error ("no arguments for spec function"); + fatal_error (input_location, "no arguments for spec function"); func = save_string (p, endp - p); p = ++endp; @@ -5547,7 +5822,7 @@ handle_spec_function (const char *p) } /* ( */ if (*endp != ')') - fatal_error ("malformed spec function arguments"); + fatal_error (input_location, "malformed spec function arguments"); args = save_string (p, endp - p); p = ++endp; @@ -5556,6 +5831,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); @@ -5694,26 +5971,35 @@ handle_braces (const char *p) a_is_negated = false; a_is_spectype = false; - SKIP_WHITE(); + SKIP_WHITE (); if (*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; + SKIP_WHITE (); + 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(); + SKIP_WHITE (); switch (*p) { case '&': case '}': @@ -5736,7 +6022,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 @@ -5761,7 +6047,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); @@ -5808,7 +6096,7 @@ handle_braces (const char *p) return p; invalid: - fatal_error ("braced spec %qs is invalid at %qc", orig, *p); + fatal_error (input_location, "braced spec %qs is invalid at %qc", orig, *p); #undef SKIP_WHITE } @@ -5896,7 +6184,7 @@ process_brace_body (const char *p, const char *atom, const char *end_atom, return p; invalid: - fatal_error ("braced spec body %qs is invalid", body); + fatal_error (input_location, "braced spec body %qs is invalid", body); } /* Return 0 iff switch number SWITCHNUM is obsoleted by a later switch @@ -6016,13 +6304,13 @@ give_switch (int switchnum, int omit_first_word) while (length-- && !IS_DIR_SEPARATOR (arg[length])) if (arg[length] == '.') { - (CONST_CAST(char *, arg))[length] = 0; + (CONST_CAST (char *, arg))[length] = 0; dot = 1; break; } do_spec_1 (arg, 1, NULL); if (dot) - (CONST_CAST(char *, arg))[length] = '.'; + (CONST_CAST (char *, arg))[length] = '.'; do_spec_1 (suffix_subst, 1, NULL); } else @@ -6034,6 +6322,359 @@ give_switch (int switchnum, int omit_first_word) switches[switchnum].validated = true; } +/* Print GCC configuration (e.g. version, thread model, target, + configuration_arguments) to a given FILE. */ + +static void +print_configuration (FILE *file) +{ + int n; + const char *thrmod; + + fnotice (file, "Target: %s\n", spec_machine); + fnotice (file, "Configured with: %s\n", configuration_arguments); + +#ifdef THREAD_MODEL_SPEC + /* We could have defined THREAD_MODEL_SPEC to "%*" by default, + but there's no point in doing all this processing just to get + thread_model back. */ + obstack_init (&obstack); + do_spec_1 (THREAD_MODEL_SPEC, 0, thread_model); + obstack_1grow (&obstack, '\0'); + thrmod = XOBFINISH (&obstack, const char *); +#else + thrmod = thread_model; +#endif + + fnotice (file, "Thread model: %s\n", thrmod); + + /* compiler_version is truncated at the first space when initialized + from version string, so truncate version_string at the first space + before comparing. */ + for (n = 0; version_string[n]; n++) + if (version_string[n] == ' ') + break; + + if (! strncmp (version_string, compiler_version, n) + && compiler_version[n] == 0) + fnotice (file, "gcc version %s %s\n", version_string, + pkgversion_string); + else + fnotice (file, "gcc driver version %s %sexecuting gcc version %s\n", + version_string, pkgversion_string, compiler_version); + +} + +#define RETRY_ICE_ATTEMPTS 3 + +/* Returns true if FILE1 and FILE2 contain equivalent data, 0 otherwise. */ + +static bool +files_equal_p (char *file1, char *file2) +{ + struct stat st1, st2; + off_t n, len; + int fd1, fd2; + const int bufsize = 8192; + char *buf = XNEWVEC (char, bufsize); + + fd1 = open (file1, O_RDONLY); + fd2 = open (file2, O_RDONLY); + + if (fd1 < 0 || fd2 < 0) + goto error; + + if (fstat (fd1, &st1) < 0 || fstat (fd2, &st2) < 0) + goto error; + + if (st1.st_size != st2.st_size) + goto error; + + for (n = st1.st_size; n; n -= len) + { + len = n; + if ((int) len > bufsize / 2) + len = bufsize / 2; + + if (read (fd1, buf, len) != (int) len + || read (fd2, buf + bufsize / 2, len) != (int) len) + { + goto error; + } + + if (memcmp (buf, buf + bufsize / 2, len) != 0) + goto error; + } + + free (buf); + close (fd1); + close (fd2); + + return 1; + +error: + free (buf); + close (fd1); + close (fd2); + return 0; +} + +/* Check that compiler's output doesn't differ across runs. + TEMP_STDOUT_FILES and TEMP_STDERR_FILES are arrays of files, containing + stdout and stderr for each compiler run. Return true if all of + TEMP_STDOUT_FILES and TEMP_STDERR_FILES are equivalent. */ + +static bool +check_repro (char **temp_stdout_files, char **temp_stderr_files) +{ + int i; + for (i = 0; i < RETRY_ICE_ATTEMPTS - 2; ++i) + { + if (!files_equal_p (temp_stdout_files[i], temp_stdout_files[i + 1]) + || !files_equal_p (temp_stderr_files[i], temp_stderr_files[i + 1])) + { + fnotice (stderr, "The bug is not reproducible, so it is" + " likely a hardware or OS problem.\n"); + break; + } + } + return i == RETRY_ICE_ATTEMPTS - 2; +} + +enum attempt_status { + ATTEMPT_STATUS_FAIL_TO_RUN, + ATTEMPT_STATUS_SUCCESS, + ATTEMPT_STATUS_ICE +}; + + +/* Run compiler with arguments NEW_ARGV to reproduce the ICE, storing stdout + to OUT_TEMP and stderr to ERR_TEMP. If APPEND is TRUE, append to OUT_TEMP + and ERR_TEMP instead of truncating. If EMIT_SYSTEM_INFO is TRUE, also write + GCC configuration into to ERR_TEMP. Return ATTEMPT_STATUS_FAIL_TO_RUN if + compiler failed to run, ATTEMPT_STATUS_ICE if compiled ICE-ed and + ATTEMPT_STATUS_SUCCESS otherwise. */ + +static enum attempt_status +run_attempt (const char **new_argv, const char *out_temp, + const char *err_temp, int emit_system_info, int append) +{ + + if (emit_system_info) + { + FILE *file_out = fopen (err_temp, "a"); + print_configuration (file_out); + fputs ("\n", file_out); + fclose (file_out); + } + + int exit_status; + const char *errmsg; + struct pex_obj *pex; + int err; + int pex_flags = PEX_USE_PIPES | PEX_LAST; + enum attempt_status status = ATTEMPT_STATUS_FAIL_TO_RUN; + + if (append) + pex_flags |= PEX_STDOUT_APPEND | PEX_STDERR_APPEND; + + pex = pex_init (PEX_USE_PIPES, new_argv[0], NULL); + if (!pex) + fatal_error (input_location, "pex_init failed: %m"); + + errmsg = pex_run (pex, pex_flags, new_argv[0], + CONST_CAST2 (char *const *, const char **, &new_argv[1]), out_temp, + err_temp, &err); + if (errmsg != NULL) + { + if (err == 0) + fatal_error (input_location, errmsg); + else + { + errno = err; + pfatal_with_name (errmsg); + } + } + + if (!pex_get_status (pex, 1, &exit_status)) + goto out; + + switch (WEXITSTATUS (exit_status)) + { + case ICE_EXIT_CODE: + status = ATTEMPT_STATUS_ICE; + break; + + case SUCCESS_EXIT_CODE: + status = ATTEMPT_STATUS_SUCCESS; + break; + + default: + ; + } + +out: + pex_free (pex); + return status; +} + +/* This routine reads lines from IN file, adds C++ style comments + at the begining of each line and writes result into OUT. */ + +static void +insert_comments (const char *file_in, const char *file_out) +{ + FILE *in = fopen (file_in, "rb"); + FILE *out = fopen (file_out, "wb"); + char line[256]; + + bool add_comment = true; + while (fgets (line, sizeof (line), in)) + { + if (add_comment) + fputs ("// ", out); + fputs (line, out); + add_comment = strchr (line, '\n') != NULL; + } + + fclose (in); + fclose (out); +} + +/* This routine adds preprocessed source code into the given ERR_FILE. + To do this, it adds "-E" to NEW_ARGV and execute RUN_ATTEMPT routine to + add information in report file. RUN_ATTEMPT should return + ATTEMPT_STATUS_SUCCESS, in other case we cannot generate the report. */ + +static void +do_report_bug (const char **new_argv, const int nargs, + char **out_file, char **err_file) +{ + int i, status; + int fd = open (*out_file, O_RDWR | O_APPEND); + if (fd < 0) + return; + write (fd, "\n//", 3); + for (i = 0; i < nargs; i++) + { + write (fd, " ", 1); + write (fd, new_argv[i], strlen (new_argv[i])); + } + write (fd, "\n\n", 2); + close (fd); + new_argv[nargs] = "-E"; + new_argv[nargs + 1] = NULL; + + status = run_attempt (new_argv, *out_file, *err_file, 0, 1); + + if (status == ATTEMPT_STATUS_SUCCESS) + { + fnotice (stderr, "Preprocessed source stored into %s file," + " please attach this to your bugreport.\n", *out_file); + /* Make sure it is not deleted. */ + free (*out_file); + *out_file = NULL; + } +} + +/* Try to reproduce ICE. If bug is reproducible, generate report .err file + containing GCC configuration, backtrace, compiler's command line options + and preprocessed source code. */ + +static void +try_generate_repro (const char **argv) +{ + int i, nargs, out_arg = -1, quiet = 0, attempt; + const char **new_argv; + char *temp_files[RETRY_ICE_ATTEMPTS * 2]; + char **temp_stdout_files = &temp_files[0]; + char **temp_stderr_files = &temp_files[RETRY_ICE_ATTEMPTS]; + + if (gcc_input_filename == NULL || ! strcmp (gcc_input_filename, "-")) + return; + + for (nargs = 0; argv[nargs] != NULL; ++nargs) + /* Only retry compiler ICEs, not preprocessor ones. */ + if (! strcmp (argv[nargs], "-E")) + return; + else if (argv[nargs][0] == '-' && argv[nargs][1] == 'o') + { + if (out_arg == -1) + out_arg = nargs; + else + return; + } + /* If the compiler is going to output any time information, + it might varry between invocations. */ + else if (! strcmp (argv[nargs], "-quiet")) + quiet = 1; + else if (! strcmp (argv[nargs], "-ftime-report")) + return; + + if (out_arg == -1 || !quiet) + return; + + memset (temp_files, '\0', sizeof (temp_files)); + new_argv = XALLOCAVEC (const char *, nargs + 4); + memcpy (new_argv, argv, (nargs + 1) * sizeof (const char *)); + new_argv[nargs++] = "-frandom-seed=0"; + new_argv[nargs++] = "-fdump-noaddr"; + new_argv[nargs] = NULL; + if (new_argv[out_arg][2] == '\0') + new_argv[out_arg + 1] = "-"; + else + new_argv[out_arg] = "-o-"; + + int status; + for (attempt = 0; attempt < RETRY_ICE_ATTEMPTS; ++attempt) + { + int emit_system_info = 0; + int append = 0; + temp_stdout_files[attempt] = make_temp_file (".out"); + temp_stderr_files[attempt] = make_temp_file (".err"); + + if (attempt == RETRY_ICE_ATTEMPTS - 1) + { + append = 1; + emit_system_info = 1; + } + + status = run_attempt (new_argv, temp_stdout_files[attempt], + temp_stderr_files[attempt], emit_system_info, + append); + + if (status != ATTEMPT_STATUS_ICE) + { + fnotice (stderr, "The bug is not reproducible, so it is" + " likely a hardware or OS problem.\n"); + goto out; + } + } + + if (!check_repro (temp_stdout_files, temp_stderr_files)) + goto out; + + { + /* Insert commented out backtrace into report file. */ + char **stderr_commented = &temp_stdout_files[RETRY_ICE_ATTEMPTS - 1]; + insert_comments (temp_stderr_files[RETRY_ICE_ATTEMPTS - 1], + *stderr_commented); + + /* In final attempt we append compiler options and preprocesssed code to last + generated .out file with configuration and backtrace. */ + char **output = &temp_stdout_files[RETRY_ICE_ATTEMPTS - 1]; + do_report_bug (new_argv, nargs, stderr_commented, output); + } + +out: + for (i = 0; i < RETRY_ICE_ATTEMPTS * 2; i++) + if (temp_files[i]) + { + unlink (temp_stdout_files[i]); + free (temp_stdout_files[i]); + } +} + /* Search for a file named NAME trying various prefixes including the user's -B prefix and some standard ones. Return the absolute file name found. If nothing is found, return NAME. */ @@ -6246,55 +6887,95 @@ compare_files (char *cmpfile[]) return ret; } -extern int main (int, char **); +/* driver::main is implemented as a series of driver:: method calls. */ int -main (int argc, char **argv) +driver::main (int argc, char **argv) { - size_t i; - int value; - int linker_was_run = 0; - int lang_n_infiles = 0; - int num_linker_inputs = 0; - char *explicit_link_files; - char *specs_file; - char *lto_wrapper_file; - const char *p; - struct user_specs *uptr; - char **old_argv = argv; - struct cl_decoded_option *decoded_options; - unsigned int decoded_options_count; + bool early_exit; + + set_progname (argv[0]); + expand_at_files (&argc, &argv); + decode_argv (argc, const_cast (argv)); + global_initializations (); + build_multilib_strings (); + set_up_specs (); + putenv_COLLECT_GCC (argv[0]); + maybe_putenv_COLLECT_LTO_WRAPPER (); + maybe_putenv_OFFLOAD_TARGETS (); + handle_unrecognized_options (); + + if (!maybe_print_and_exit ()) + return 0; + + early_exit = prepare_infiles (); + if (early_exit) + return get_exit_code (); + + do_spec_on_infiles (); + maybe_run_linker (argv[0]); + final_actions (); + return get_exit_code (); +} + +/* Locate the final component of argv[0] after any leading path, and set + the program name accordingly. */ - p = argv[0] + strlen (argv[0]); - while (p != argv[0] && !IS_DIR_SEPARATOR (p[-1])) +void +driver::set_progname (const char *argv0) const +{ + const char *p = argv0 + strlen (argv0); + while (p != argv0 && !IS_DIR_SEPARATOR (p[-1])) --p; progname = p; xmalloc_set_program_name (progname); +} + +/* Expand any @ files within the command-line args, + setting at_file_supplied if any were expanded. */ + +void +driver::expand_at_files (int *argc, char ***argv) const +{ + char **old_argv = *argv; - expandargv (&argc, &argv); + expandargv (argc, argv); /* Determine if any expansions were made. */ - if (argv != old_argv) + if (*argv != old_argv) at_file_supplied = true; +} + +/* Decode the command-line arguments from argc/argv into the + decoded_options array. */ +void +driver::decode_argv (int argc, const char **argv) +{ /* Register the language-independent parameters. */ global_init_params (); finish_params (); init_options_struct (&global_options, &global_options_set); - decode_cmdline_options_to_array (argc, CONST_CAST2 (const char **, char **, - argv), + decode_cmdline_options_to_array (argc, argv, CL_DRIVER, &decoded_options, &decoded_options_count); +} + +/* Perform various initializations and setup. */ +void +driver::global_initializations () +{ /* Unlock the stdio streams. */ unlock_std_streams (); gcc_init_libintl (); diagnostic_initialize (global_dc, 0); + diagnostic_color_init (global_dc); #ifdef GCC_DRIVER_HOST_INITIALIZATION /* Perform host dependent initialization when needed. */ @@ -6302,7 +6983,7 @@ main (int argc, char **argv) #endif if (atexit (delete_temp_files) != 0) - fatal_error ("atexit failed"); + fatal_error (input_location, "atexit failed"); if (signal (SIGINT, SIG_IGN) != SIG_IGN) signal (SIGINT, fatal_signal); @@ -6330,10 +7011,16 @@ main (int argc, char **argv) alloc_args (); obstack_init (&obstack); +} - /* Build multilib_select, et. al from the separate lines that make up each - multilib selection. */ +/* Build multilib_select, et. al from the separate lines that make up each + multilib selection. */ + +void +driver::build_multilib_strings () const +{ { + const char *p; const char *const *q = multilib_raw; int need_space; @@ -6366,7 +7053,7 @@ main (int argc, char **argv) multilib_reuse = XOBFINISH (&multilib_obstack, const char *); need_space = FALSE; - for (i = 0; i < ARRAY_SIZE (multilib_defaults_raw); i++) + for (size_t i = 0; i < ARRAY_SIZE (multilib_defaults_raw); i++) { if (need_space) obstack_1grow (&multilib_obstack, ' '); @@ -6379,6 +7066,16 @@ main (int argc, char **argv) obstack_1grow (&multilib_obstack, 0); multilib_defaults = XOBFINISH (&multilib_obstack, const char *); } +} + +/* Set up the spec-handling machinery. */ + +void +driver::set_up_specs () const +{ + const char *spec_machine_suffix; + char *specs_file; + size_t i; #ifdef INIT_ENVIRONMENT /* Set up any other necessary machine specific environment variables. */ @@ -6400,8 +7097,8 @@ main (int argc, char **argv) /* Read specs from a file if there is one. */ - machine_suffix = concat (spec_machine, dir_separator_str, - spec_version, dir_separator_str, NULL); + machine_suffix = concat (spec_host_machine, dir_separator_str, spec_version, + accel_dir_suffix, dir_separator_str, NULL); just_machine_suffix = concat (spec_machine, dir_separator_str, NULL); specs_file = find_a_file (&startfile_prefixes, "specs", R_OK, true); @@ -6411,13 +7108,18 @@ main (int argc, char **argv) else init_spec (); - /* We need to check standard_exec_prefix/just_machine_suffix/specs +#ifdef ACCEL_COMPILER + spec_machine_suffix = machine_suffix; +#else + spec_machine_suffix = just_machine_suffix; +#endif + + /* We need to check standard_exec_prefix/spec_machine_suffix/specs for any override of as, ld and libraries. */ specs_file = (char *) alloca (strlen (standard_exec_prefix) - + strlen (just_machine_suffix) + sizeof ("specs")); - + + strlen (spec_machine_suffix) + sizeof ("specs")); strcpy (specs_file, standard_exec_prefix); - strcat (specs_file, just_machine_suffix); + strcat (specs_file, spec_machine_suffix); strcat (specs_file, "specs"); if (access (specs_file, R_OK) == 0) read_specs (specs_file, true, false); @@ -6538,7 +7240,7 @@ main (int argc, char **argv) /* Process any user specified specs in the order given on the command line. */ - for (uptr = user_specs_head; uptr; uptr = uptr->next) + for (struct user_specs *uptr = user_specs_head; uptr; uptr = uptr->next) { char *filename = find_a_file (&startfile_prefixes, uptr->filename, R_OK, true); @@ -6599,8 +7301,9 @@ main (int argc, char **argv) /* If we have a GCC_EXEC_PREFIX envvar, modify it for cpp's sake. */ if (gcc_exec_prefix) - gcc_exec_prefix = concat (gcc_exec_prefix, spec_machine, dir_separator_str, - spec_version, dir_separator_str, NULL); + gcc_exec_prefix = concat (gcc_exec_prefix, spec_host_machine, + dir_separator_str, spec_version, + accel_dir_suffix, dir_separator_str, NULL); /* Now we have the specs. Set the `valid' bits for switches that match anything in any spec. */ @@ -6610,16 +7313,27 @@ main (int argc, char **argv) /* Now that we have the switches and the specs, set the subdirectory based on the options. */ set_multilib_dir (); +} - /* Set up to remember the pathname of gcc and any options - needed for collect. We use argv[0] instead of progname because - we need the complete pathname. */ +/* Set up to remember the pathname of gcc and any options + needed for collect. We use argv[0] instead of progname because + we need the complete pathname. */ + +void +driver::putenv_COLLECT_GCC (const char *argv0) const +{ obstack_init (&collect_obstack); obstack_grow (&collect_obstack, "COLLECT_GCC=", sizeof ("COLLECT_GCC=") - 1); - obstack_grow (&collect_obstack, argv[0], strlen (argv[0]) + 1); + obstack_grow (&collect_obstack, argv0, strlen (argv0) + 1); xputenv (XOBFINISH (&collect_obstack, char *)); +} + +/* Set up to remember the pathname of the lto wrapper. */ - /* Set up to remember the pathname of the lto wrapper. */ +void +driver::maybe_putenv_COLLECT_LTO_WRAPPER () const +{ + char *lto_wrapper_file; if (have_c) lto_wrapper_file = NULL; @@ -6638,14 +7352,47 @@ main (int argc, char **argv) xputenv (XOBFINISH (&collect_obstack, char *)); } - /* Reject switches that no pass was interested in. */ +} + +/* Set up to remember the names of offload targets. */ - for (i = 0; (int) i < n_switches; i++) +void +driver::maybe_putenv_OFFLOAD_TARGETS () const +{ + const char *targets = offload_targets; + + /* If no targets specified by -foffload, use all available targets. */ + if (!targets) + targets = OFFLOAD_TARGETS; + + if (strlen (targets) > 0) + { + obstack_grow (&collect_obstack, "OFFLOAD_TARGET_NAMES=", + sizeof ("OFFLOAD_TARGET_NAMES=") - 1); + obstack_grow (&collect_obstack, targets, + strlen (targets) + 1); + xputenv (XOBFINISH (&collect_obstack, char *)); + } + + free (offload_targets); +} + +/* Reject switches that no pass was interested in. */ + +void +driver::handle_unrecognized_options () const +{ + for (size_t i = 0; (int) i < n_switches; i++) if (! switches[i].validated) error ("unrecognized command line option %<-%s%>", switches[i].part1); +} - /* Obey some of the options. */ +/* Handle the various -print-* options, returning 0 if the driver + should exit, or nonzero if the driver should continue. */ +int +driver::maybe_print_and_exit () const +{ if (print_search_dirs) { printf (_("install: %s%s\n"), @@ -6666,6 +7413,38 @@ main (int argc, char **argv) if (print_prog_name) { + if (use_ld != NULL && ! strcmp (print_prog_name, "ld")) + { + /* Append USE_LD to to the default linker. */ +#ifdef DEFAULT_LINKER + char *ld; +# ifdef HAVE_HOST_EXECUTABLE_SUFFIX + int len = (sizeof (DEFAULT_LINKER) + - sizeof (HOST_EXECUTABLE_SUFFIX)); + ld = NULL; + if (len > 0) + { + char *default_linker = xstrdup (DEFAULT_LINKER); + /* Strip HOST_EXECUTABLE_SUFFIX if DEFAULT_LINKER contains + HOST_EXECUTABLE_SUFFIX. */ + if (! strcmp (&default_linker[len], HOST_EXECUTABLE_SUFFIX)) + { + default_linker[len] = '\0'; + ld = concat (default_linker, use_ld, + HOST_EXECUTABLE_SUFFIX, NULL); + } + } + if (ld == NULL) +# endif + ld = concat (DEFAULT_LINKER, use_ld, NULL); + if (access (ld, X_OK) == 0) + { + printf ("%s\n", ld); + return (0); + } +#endif + print_prog_name = concat (print_prog_name, use_ld, NULL); + } char *newname = find_a_file (&exec_prefixes, print_prog_name, X_OK, 0); printf ("%s\n", (newname ? newname : print_prog_name)); return (0); @@ -6728,7 +7507,8 @@ main (int argc, char **argv) else /* The error status indicates that only one set of fixed headers should be built. */ - fatal_error ("not configured with sysroot headers suffix"); + fatal_error (input_location, + "not configured with sysroot headers suffix"); } if (print_help_list) @@ -6755,7 +7535,7 @@ main (int argc, char **argv) { printf (_("%s %s%s\n"), progname, pkgversion_string, version_string); - printf ("Copyright %s 2013 Free Software Foundation, Inc.\n", + printf ("Copyright %s 2015 Free Software Foundation, Inc.\n", _("(C)")); fputs (_("This is free software; see the source for copying conditions. There is NO\n\ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"), @@ -6771,50 +7551,29 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n" if (verbose_flag) { - int n; - const char *thrmod; - - fnotice (stderr, "Target: %s\n", spec_machine); - fnotice (stderr, "Configured with: %s\n", configuration_arguments); - -#ifdef THREAD_MODEL_SPEC - /* We could have defined THREAD_MODEL_SPEC to "%*" by default, - but there's no point in doing all this processing just to get - thread_model back. */ - obstack_init (&obstack); - do_spec_1 (THREAD_MODEL_SPEC, 0, thread_model); - obstack_1grow (&obstack, '\0'); - thrmod = XOBFINISH (&obstack, const char *); -#else - thrmod = thread_model; -#endif - - fnotice (stderr, "Thread model: %s\n", thrmod); - - /* compiler_version is truncated at the first space when initialized - from version string, so truncate version_string at the first space - before comparing. */ - for (n = 0; version_string[n]; n++) - if (version_string[n] == ' ') - break; - - if (! strncmp (version_string, compiler_version, n) - && compiler_version[n] == 0) - fnotice (stderr, "gcc version %s %s\n", version_string, - pkgversion_string); - else - fnotice (stderr, "gcc driver version %s %sexecuting gcc version %s\n", - version_string, pkgversion_string, compiler_version); - + print_configuration (stderr); if (n_infiles == 0) return (0); } + return 1; +} + +/* Figure out what to do with each input file. + Return true if we need to exit early from "main", false otherwise. */ + +bool +driver::prepare_infiles () +{ + size_t i; + int lang_n_infiles = 0; + if (n_infiles == added_libraries) - fatal_error ("no input files"); + fatal_error (input_location, "no input files"); if (seen_error ()) - goto out; + /* Early exit needed from main. */ + return true; /* Make a place to record the compiler output file names that correspond to the input files. */ @@ -6860,7 +7619,19 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n" } if (!combine_inputs && have_c && have_o && lang_n_infiles > 1) - fatal_error ("cannot specify -o with -c, -S or -E with multiple files"); + fatal_error (input_location, + "cannot specify -o with -c, -S or -E with multiple files"); + + /* No early exit needed from main; we can continue. */ + return false; +} + +/* Run the spec machinery on each input file. */ + +void +driver::do_spec_on_infiles () const +{ + size_t i; for (i = 0; (int) i < n_infiles; i++) { @@ -6896,6 +7667,8 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n" } else { + int value; + if (compare_debug) { free (debug_check_temp_file[0]); @@ -6997,6 +7770,16 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n" if (lang_specific_pre_link ()) errorcount++; } +} + +/* If we have to run the linker, do it now. */ + +void +driver::maybe_run_linker (const char *argv0) const +{ + size_t i; + int linker_was_run = 0; + int num_linker_inputs; /* Determine if there are any linker input files. */ num_linker_inputs = 0; @@ -7043,12 +7826,13 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n" LTOPLUGINSONAME, R_OK, false); if (!temp_spec) - fatal_error ("-fuse-linker-plugin, but %s not found", + fatal_error (input_location, + "-fuse-linker-plugin, but %s not found", LTOPLUGINSONAME); linker_plugin_file_spec = convert_white_space (temp_spec); } #endif - lto_gcc_spec = argv[0]; + lto_gcc_spec = argv0; } /* Rebuild the COMPILER_PATH and LIBRARY_PATH environment variables @@ -7063,7 +7847,7 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n" " to the linker.\n\n")); fflush (stdout); } - value = do_spec (link_command_spec); + int value = do_spec (link_command_spec); if (value < 0) errorcount = 1; linker_was_run = (tmp != execution_count); @@ -7078,7 +7862,13 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n" && !(infiles[i].language && infiles[i].language[0] == '*')) warning (0, "%s: linker input file unused because linking not done", outfiles[i]); +} + +/* The end of "main". */ +void +driver::final_actions () const +{ /* Delete some or all of the temporary files we made. */ if (seen_error ()) @@ -7090,8 +7880,13 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n" printf (("\nFor bug reporting instructions, please see:\n")); printf ("%s\n", bug_report_url); } +} - out: +/* Determine what the exit code of the driver should be. */ + +int +driver::get_exit_code () const +{ return (signal_count != 0 ? 2 : seen_error () ? (pass_exit_codes ? greatest_status : 1) : 0); @@ -7344,7 +8139,7 @@ used_arg (const char *p, int len) if (*q == '\0') { invalid_matches: - fatal_error ("multilib spec %qs is invalid", + fatal_error (input_location, "multilib spec %qs is invalid", multilib_matches); } q++; @@ -7394,7 +8189,7 @@ used_arg (const char *p, int len) { const char *r; - for (q = multilib_options; *q != '\0'; q++) + for (q = multilib_options; *q != '\0'; *q && q++) { while (*q == ' ') q++; @@ -7538,7 +8333,7 @@ set_multilib_dir (void) if (*p == '\0') { invalid_exclusions: - fatal_error ("multilib exclusions %qs is invalid", + fatal_error (input_location, "multilib exclusions %qs is invalid", multilib_exclusions); } @@ -7602,7 +8397,7 @@ set_multilib_dir (void) if (*p == '\0') { invalid_select: - fatal_error ("multilib select %qs %qs is invalid", + fatal_error (input_location, "multilib select %qs %qs is invalid", multilib_select, multilib_reuse); } ++p; @@ -7694,10 +8489,15 @@ set_multilib_dir (void) q2++; if (*q2 == ':') ml_end = q2; - new_multilib_os_dir = XNEWVEC (char, ml_end - q); - memcpy (new_multilib_os_dir, q + 1, ml_end - q - 1); - new_multilib_os_dir[ml_end - q - 1] = '\0'; - multilib_os_dir = *new_multilib_os_dir ? new_multilib_os_dir : "."; + if (ml_end - q == 1) + multilib_os_dir = xstrdup ("."); + else + { + new_multilib_os_dir = XNEWVEC (char, ml_end - q); + memcpy (new_multilib_os_dir, q + 1, ml_end - q - 1); + new_multilib_os_dir[ml_end - q - 1] = '\0'; + multilib_os_dir = new_multilib_os_dir; + } if (q2 < end && *q2 == ':') { @@ -7758,7 +8558,8 @@ print_multilib_info (void) if (*p == '\0') { invalid_select: - fatal_error ("multilib select %qs is invalid", multilib_select); + fatal_error (input_location, + "multilib select %qs is invalid", multilib_select); } ++p; @@ -7797,7 +8598,8 @@ print_multilib_info (void) if (*e == '\0') { invalid_exclusion: - fatal_error ("multilib exclusion %qs is invalid", + fatal_error (input_location, + "multilib exclusion %qs is invalid", multilib_exclusions); } @@ -8003,7 +8805,8 @@ getenv_spec_function (int argc, const char **argv) value = getenv (argv[0]); if (!value) - fatal_error ("environment variable %qs not defined", argv[0]); + fatal_error (input_location, + "environment variable %qs not defined", argv[0]); /* We have to escape every character of the environment variable so they are not interpreted as active spec characters. A @@ -8058,6 +8861,33 @@ if_exists_else_spec_function (int argc, const char **argv) 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_USER_ADDRESS) ? "" : NULL; + if (strcmp (argv[0], "kernel-address") == 0) + return (flag_sanitize & SANITIZE_KERNEL_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 | SANITIZE_NONDEFAULT)) + && !flag_sanitize_undefined_trap_on_error) ? "" : NULL; + if (strcmp (argv[0], "leak") == 0) + return ((flag_sanitize + & (SANITIZE_ADDRESS | SANITIZE_LEAK | SANITIZE_THREAD)) + == SANITIZE_LEAK) ? "" : NULL; + return NULL; +} + /* replace-outfile built-in spec function. This looks for the first argument in the outfiles array's name and @@ -8115,12 +8945,12 @@ compare_version_strings (const char *v1, const char *v2) abort (); rresult = regexec (&r, v1, 0, NULL, 0); if (rresult == REG_NOMATCH) - fatal_error ("invalid version number %qs", v1); + fatal_error (input_location, "invalid version number %qs", v1); else if (rresult != 0) abort (); rresult = regexec (&r, v2, 0, NULL, 0); if (rresult == REG_NOMATCH) - fatal_error ("invalid version number %qs", v2); + fatal_error (input_location, "invalid version number %qs", v2); else if (rresult != 0) abort (); @@ -8163,13 +8993,13 @@ version_compare_spec_function (int argc, const char **argv) bool result; if (argc < 3) - fatal_error ("too few arguments to %%:version-compare"); + fatal_error (input_location, "too few arguments to %%:version-compare"); if (argv[0][0] == '\0') abort (); if ((argv[0][1] == '<' || argv[0][1] == '>') && argv[0][0] != '!') nargs = 2; if (argc != nargs + 3) - fatal_error ("too many arguments to %%:version-compare"); + fatal_error (input_location, "too many arguments to %%:version-compare"); switch_len = strlen (argv[nargs + 1]); for (i = 0; i < n_switches; i++) @@ -8210,7 +9040,8 @@ version_compare_spec_function (int argc, const char **argv) break; default: - fatal_error ("unknown operator %qs in %%:version-compare", argv[0]); + fatal_error (input_location, + "unknown operator %qs in %%:version-compare", argv[0]); } if (! result) return NULL; @@ -8316,7 +9147,7 @@ get_random_number (void) } #endif - return ret ^ getpid(); + return ret ^ getpid (); } /* %:compare-debug-dump-opt spec function. Save the last argument, @@ -8333,7 +9164,8 @@ compare_debug_dump_opt_spec_function (int arg, static char random_seed[HOST_BITS_PER_WIDE_INT / 4 + 3]; if (arg != 0) - fatal_error ("too many arguments to %%:compare-debug-dump-opt"); + fatal_error (input_location, + "too many arguments to %%:compare-debug-dump-opt"); do_spec_2 ("%{fdump-final-insns=*:%*}"); do_spec_1 (" ", 0, NULL); @@ -8405,7 +9237,8 @@ compare_debug_self_opt_spec_function (int arg, const char **argv ATTRIBUTE_UNUSED) { if (arg != 0) - fatal_error ("too many arguments to %%:compare-debug-self-opt"); + fatal_error (input_location, + "too many arguments to %%:compare-debug-self-opt"); if (compare_debug >= 0) return NULL; @@ -8440,17 +9273,19 @@ compare_debug_auxbase_opt_spec_function (int arg, int len; if (arg == 0) - fatal_error ("too few arguments to %%:compare-debug-auxbase-opt"); + fatal_error (input_location, + "too few arguments to %%:compare-debug-auxbase-opt"); if (arg != 1) - fatal_error ("too many arguments to %%:compare-debug-auxbase-opt"); + fatal_error (input_location, + "too many arguments to %%:compare-debug-auxbase-opt"); if (compare_debug >= 0) return NULL; len = strlen (argv[0]); if (len < 3 || strcmp (argv[0] + len - 3, ".gk") != 0) - fatal_error ("argument to %%:compare-debug-auxbase-opt " + fatal_error (input_location, "argument to %%:compare-debug-auxbase-opt " "does not end in .gk"); if (debug_auxbase_opt) @@ -8524,11 +9359,11 @@ replace_extension_spec_func (int argc, const char **argv) int i; if (argc != 2) - fatal_error ("too few arguments to %%:replace-extension"); + fatal_error (input_location, "too few arguments to %%:replace-extension"); name = xstrdup (argv[0]); - for (i = strlen(name) - 1; i >= 0; i--) + for (i = strlen (name) - 1; i >= 0; i--) if (IS_DIR_SEPARATOR (name[i])) break; @@ -8589,3 +9424,39 @@ convert_white_space (char *orig) else return orig; } + +/* PR jit/64810. + Targets can provide configure-time default options in + OPTION_DEFAULT_SPECS. The jit needs to access these, but + they are expressed in the spec language. + + Run just enough of the driver to be able to expand these + specs, and then call the callback CB on each + such option. The options strings are *without* a leading + '-' character e.g. ("march=x86-64"). Finally, clean up. */ + +void +driver_get_configure_time_options (void (*cb) (const char *option, + void *user_data), + void *user_data) +{ + size_t i; + + obstack_init (&obstack); + gcc_obstack_init (&opts_obstack); + n_switches = 0; + + for (i = 0; i < ARRAY_SIZE (option_default_specs); i++) + do_option_spec (option_default_specs[i].name, + option_default_specs[i].spec); + + for (i = 0; (int) i < n_switches; i++) + { + gcc_assert (switches[i].part1); + (*cb) (switches[i].part1, user_data); + } + + obstack_free (&opts_obstack, NULL); + obstack_free (&obstack, NULL); + n_switches = 0; +}