This patch simplifies (!!!) the logic governing the naming of dump files and auxiliary output files in the driver, in the compiler, and in the LTO wrapper. No changes are made to the naming of primary outputs, there are often ways to restore past behavior, and a number of inconsistencies are fixed. Some internal options are removed (-auxbase and -auxbase-strip), sensible existing uses of -dumpdir and -dumpbase options remain unchanged, additional useful cases are added, making for what is still admittedly quite complex. Extensive documentation and testcases provide numerous examples, from normal to corner cases. The most visible changes are: - aux and dump files now always go in the same directory, that defaults to the directory of the primary output, but that can be overridden with -dumpdir, -save-temps=*, or, preserving past behavior, with a -dumpbase with a directory component. - driver and compiler now have the same notion of naming of auxiliary outputs, e.g. .dwo files will no longer be in one location while the debug info suggests they are elsewhere, and -save-temps and .dwo auxiliary outputs now go in the same location as .su, .ci and coverage data, with consistent naming. - explicitly-specified primary output names guide not only the location of aux and dump outputs: the output base name is also used in their base name, as a prefix when also linking (e.g. foo.c bar.c -o foobar creates foobar-foo.dwo and foobar-bar.dwo with -gsplit-dwarf), or as the base name instead of the input name (foo.c -c -o whatever.o creates whatever.su rather than foo.su with -fstack-usage). The preference for the input file base name, quite useful for our testsuite, can be restored with -dumpbase "". When compiling and linking tests in the testsuite with additional inputs, we now use this flag. Files named in dejagnu board ldflags, libs, and ldscripts are now quoted in the gcc testsuite with -Wl, so that they are not counted as additional inputs by the compiler driver. - naming a -dumpbase when compiling multiple sources used to cause dumps from later compiles to overwrite those of earlier ones; it is now used as a prefix when compiling multiple sources, like an executable name above. - the dumpbase, explicitly specified or computed from output or input names, now also governs the naming of aux outputs; since aux outputs usually replaced the suffix from the input name, while dump outputs append their own additional suffixes, a -dumpbase-ext option is introduced to enable a chosen suffix to be dropped from dumpbase to form aux output names. - LTO dump and aux outputs were quite a mess, sometimes leaking temporary output names into -save-temps output names, sometimes conversely generating desirable aux outputs in temporary locations. They now obey the same logic of compiler aux and dump outputs, landing in the expected location and taking the linker output name or an explicit dumpbase overrider into account. - Naming of -fdump-final-insns outputs now follows the dump file naming logic for the .gkd files, and the .gk dump files generated in the second -fcompare-debug compilation get the .gk inserted before the suffix that -dumpbase-ext drops in aux outputs. gcc/ChangeLog: * common.opt (aux_base_name): Define. (dumpbase, dumpdir): Mark as Driver options. (-dumpbase, -dumpdir): Likewise. (dumpbase-ext, -dumpbase-ext): New. (auxbase, auxbase-strip): Drop. * doc/invoke.texi (-dumpbase, -dumpbase-ext, -dumpdir): Document. (-o): Introduce the notion of primary output, mention it influences auxiliary and dump output names as well, add examples. (-save-temps): Adjust, move examples into -dump*. (-save-temps=cwd, -save-temps=obj): Likewise. (-fdump-final-insns): Adjust. * dwarf2out.c (gen_producer_string): Drop auxbase and auxbase_strip; add dumpbase_ext. * gcc.c (enum save_temps): Add SAVE_TEMPS_DUMP. (save_temps_prefix, save_temps_length): Drop. (save_temps_overrides_dumpdir): New. (dumpdir, dumpbase, dumpbase_ext): New. (dumpdir_length, dumpdir_trailing_dash_added): New. (outbase, outbase_length): New. (The Specs Language): Introduce %". Adjust %b and %B. (ASM_FINAL_SPEC): Use %b.dwo for an aux output name always. Precede object file with %w when it's the primary output. (cpp_debug_options): Do not pass on incoming -dumpdir, -dumpbase and -dumpbase-ext options; recompute them with %:dumps. (cc1_options): Drop auxbase with and without compare-debug; use cpp_debug_options instead of dumpbase. Mark asm output with %w when it's the primary output. (static_spec_functions): Drop %:compare-debug-auxbase-opt and %:replace-exception. Add %:dumps. (driver_handle_option): Implement -save-temps=*/-dumpdir mutual overriding logic. Save dumpdir, dumpbase and dumpbase-ext options. Do not save output_file in save_temps_prefix. (adds_single_suffix_p): New. (single_input_file_index): New. (process_command): Combine output dir, output base name, and dumpbase into dumpdir and outbase. (set_collect_gcc_options): Pass a possibly-adjusted -dumpdir. (do_spec_1): Optionally dumpdir instead of save_temps_prefix, and outbase instead of input_basename in %b, %B and in -save-temps aux files. Handle empty argument %". (driver::maybe_run_linker): Adjust dumpdir and auxbase. (compare_debug_dump_opt_spec_function): Adjust gkd dump file naming. Spec-quote the computed -fdump-final-insns file name. (debug_auxbase_opt): Drop. (compare_debug_self_opt_spec_function): Drop auxbase-strip computation. (compare_debug_auxbase_opt_spec_function): Drop. (not_actual_file_p): New. (replace_extension_spec_func): Drop. (dumps_spec_func): New. (convert_white_space): Split-out parts into... (quote_string, whitespace_to_convert_p): ... these. New. (quote_spec_char_p, quote_spec, quote_spec_arg): New. (driver::finalize): Release and reset new variables; drop removed ones. * lto-wrapper.c (HAVE_TARGET_EXECUTABLE_SUFFIX): Define if... (TARGET_EXECUTABLE_SUFFIX): ... is defined; define this to the empty string otherwise. (DUMPBASE_SUFFIX): Drop leading period. (debug_objcopy): Use concat. (run_gcc): Recognize -save-temps=* as -save-temps too. Obey -dumpdir. Pass on empty dumpdir and dumpbase with a directory component. Simplify temp file names. * opts.c (finish_options): Drop aux base name handling. (common_handle_option): Drop auxbase-strip handling. * toplev.c (print_switch_values): Drop auxbase, add dumpbase-ext. (process_options): Derive aux_base_name from dump_base_name and dump_base_ext. (lang_dependent_init): Compute dump_base_ext along with dump_base_name. Disable stack usage and callgraph-info during lto generation and compare-debug recompilation. gcc/fortran/ChangeLog: * options.c (gfc_get_option_string): Drop auxbase, add dumpbase_ext. gcc/ada/ChangeLog: * gcc-interface/lang-specs.h: Drop auxbase and auxbase-strip. Use %:dumps instead of -dumpbase. Add %w for implicit .s primary output. * switch.adb (Is_Internal_GCC_Switch): Recognize dumpdir and dumpbase-ext. Drop auxbase and auxbase-strip. lto-plugin/ChangeLog: * lto-plugin.c (skip_in_suffix): New. (exec_lto_wrapper): Use skip_in_suffix and concat to build non-temporary output names. (onload): Look for -dumpdir in COLLECT_GCC_OPTIONS, and override link_output_name with it. contrib/ChangeLog: * compare-debug: Adjust for .gkd files named as dump files, with the source suffix rather than the object suffix. gcc/testsuite/ChangeLog: * gcc.misc-tests/outputs.exp: New. * gcc.misc-tests/outputs-0.c: New. * gcc.misc-tests/outputs-1.c: New. * gcc.misc-tests/outputs-2.c: New. * lib/gcc-defs.exp (gcc_adjusted_linker_flags): New. (gcc_adjust_linker_flags): New. (dg-additional-files-options): Call it. Pass -dumpbase "" when there are additional sources. * lib/profopt.exp (profopt-execute): Pass the executable suffix with -dumpbase-ext. * lib/scandump.exp (dump-base): Mention -dumpbase "" use. * lib/scanltranstree.exp: Adjust dump suffix expectation. * lib/scanwpaipa.exp: Likewise.
901 lines
24 KiB
C
901 lines
24 KiB
C
/* Parse and display command line options.
|
|
Copyright (C) 2000-2020 Free Software Foundation, Inc.
|
|
Contributed by Andy Vaught
|
|
|
|
This file is part of GCC.
|
|
|
|
GCC is free software; you can redistribute it and/or modify it under
|
|
the terms of the GNU General Public License as published by the Free
|
|
Software Foundation; either version 3, or (at your option) any later
|
|
version.
|
|
|
|
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with GCC; see the file COPYING3. If not see
|
|
<http://www.gnu.org/licenses/>. */
|
|
|
|
#include "config.h"
|
|
#include "system.h"
|
|
#include "coretypes.h"
|
|
#include "target.h"
|
|
#include "tree.h"
|
|
#include "gfortran.h"
|
|
#include "diagnostic.h" /* For global_dc. */
|
|
#include "opts.h"
|
|
#include "toplev.h" /* For save_decoded_options. */
|
|
#include "cpp.h"
|
|
#include "langhooks.h"
|
|
|
|
gfc_option_t gfc_option;
|
|
|
|
#define SET_FLAG(flag, condition, on_value, off_value) \
|
|
do \
|
|
{ \
|
|
if (condition) \
|
|
flag = (on_value); \
|
|
else \
|
|
flag = (off_value); \
|
|
} while (0)
|
|
|
|
#define SET_BITFLAG2(m) m
|
|
|
|
#define SET_BITFLAG(flag, condition, value) \
|
|
SET_BITFLAG2 (SET_FLAG (flag, condition, (flag | (value)), (flag & ~(value))))
|
|
|
|
|
|
/* Set flags that control warnings and errors for different
|
|
Fortran standards to their default values. Keep in sync with
|
|
libgfortran/runtime/compile_options.c (init_compile_options). */
|
|
|
|
static void
|
|
set_default_std_flags (void)
|
|
{
|
|
gfc_option.allow_std = GFC_STD_F95_OBS | GFC_STD_F95_DEL
|
|
| GFC_STD_F2003 | GFC_STD_F2008 | GFC_STD_F95 | GFC_STD_F77
|
|
| GFC_STD_F2008_OBS | GFC_STD_GNU | GFC_STD_LEGACY
|
|
| GFC_STD_F2018 | GFC_STD_F2018_DEL | GFC_STD_F2018_OBS;
|
|
gfc_option.warn_std = GFC_STD_F2018_DEL | GFC_STD_F95_DEL | GFC_STD_LEGACY;
|
|
}
|
|
|
|
/* Set (or unset) the DEC extension flags. */
|
|
|
|
static void
|
|
set_dec_flags (int value)
|
|
{
|
|
/* Set (or unset) other DEC compatibility extensions. */
|
|
SET_BITFLAG (flag_dollar_ok, value, value);
|
|
SET_BITFLAG (flag_cray_pointer, value, value);
|
|
SET_BITFLAG (flag_dec_structure, value, value);
|
|
SET_BITFLAG (flag_dec_intrinsic_ints, value, value);
|
|
SET_BITFLAG (flag_dec_static, value, value);
|
|
SET_BITFLAG (flag_dec_math, value, value);
|
|
SET_BITFLAG (flag_dec_include, value, value);
|
|
SET_BITFLAG (flag_dec_format_defaults, value, value);
|
|
SET_BITFLAG (flag_dec_blank_format_item, value, value);
|
|
SET_BITFLAG (flag_dec_char_conversions, value, value);
|
|
}
|
|
|
|
/* Finalize DEC flags. */
|
|
|
|
static void
|
|
post_dec_flags (int value)
|
|
{
|
|
/* Don't warn for legacy code if -fdec is given; however, setting -fno-dec
|
|
does not force these warnings. We make one final determination on this
|
|
at the end because -std= is always set first; thus, we can avoid
|
|
clobbering the user's desired standard settings in gfc_handle_option
|
|
e.g. when -fdec and -fno-dec are both given. */
|
|
if (value)
|
|
{
|
|
gfc_option.allow_std |= GFC_STD_F95_OBS | GFC_STD_F95_DEL
|
|
| GFC_STD_GNU | GFC_STD_LEGACY;
|
|
gfc_option.warn_std &= ~(GFC_STD_LEGACY | GFC_STD_F95_DEL);
|
|
}
|
|
}
|
|
|
|
/* Enable (or disable) -finit-local-zero. */
|
|
|
|
static void
|
|
set_init_local_zero (int value)
|
|
{
|
|
gfc_option.flag_init_integer_value = 0;
|
|
gfc_option.flag_init_character_value = (char)0;
|
|
|
|
SET_FLAG (gfc_option.flag_init_integer, value, GFC_INIT_INTEGER_ON,
|
|
GFC_INIT_INTEGER_OFF);
|
|
SET_FLAG (gfc_option.flag_init_logical, value, GFC_INIT_LOGICAL_FALSE,
|
|
GFC_INIT_LOGICAL_OFF);
|
|
SET_FLAG (gfc_option.flag_init_character, value, GFC_INIT_CHARACTER_ON,
|
|
GFC_INIT_CHARACTER_OFF);
|
|
SET_FLAG (flag_init_real, value, GFC_INIT_REAL_ZERO, GFC_INIT_REAL_OFF);
|
|
}
|
|
|
|
/* Return language mask for Fortran options. */
|
|
|
|
unsigned int
|
|
gfc_option_lang_mask (void)
|
|
{
|
|
return CL_Fortran;
|
|
}
|
|
|
|
/* Initialize options structure OPTS. */
|
|
|
|
void
|
|
gfc_init_options_struct (struct gcc_options *opts)
|
|
{
|
|
opts->x_flag_errno_math = 0;
|
|
opts->frontend_set_flag_errno_math = true;
|
|
opts->x_flag_associative_math = -1;
|
|
opts->frontend_set_flag_associative_math = true;
|
|
}
|
|
|
|
/* Get ready for options handling. Keep in sync with
|
|
libgfortran/runtime/compile_options.c (init_compile_options). */
|
|
|
|
void
|
|
gfc_init_options (unsigned int decoded_options_count,
|
|
struct cl_decoded_option *decoded_options)
|
|
{
|
|
gfc_source_file = NULL;
|
|
gfc_option.module_dir = NULL;
|
|
gfc_option.source_form = FORM_UNKNOWN;
|
|
gfc_option.max_continue_fixed = 255;
|
|
gfc_option.max_continue_free = 255;
|
|
gfc_option.max_identifier_length = GFC_MAX_SYMBOL_LEN;
|
|
gfc_option.max_errors = 25;
|
|
|
|
gfc_option.flag_preprocessed = 0;
|
|
gfc_option.flag_d_lines = -1;
|
|
set_init_local_zero (0);
|
|
|
|
gfc_option.fpe = 0;
|
|
/* All except GFC_FPE_INEXACT. */
|
|
gfc_option.fpe_summary = GFC_FPE_INVALID | GFC_FPE_DENORMAL
|
|
| GFC_FPE_ZERO | GFC_FPE_OVERFLOW
|
|
| GFC_FPE_UNDERFLOW;
|
|
gfc_option.rtcheck = 0;
|
|
|
|
/* ??? Wmissing-include-dirs is disabled by default in C/C++ but
|
|
enabled by default in Fortran. Ideally, we should express this
|
|
in .opt, but that is not supported yet. */
|
|
SET_OPTION_IF_UNSET (&global_options, &global_options_set,
|
|
cpp_warn_missing_include_dirs, 1);
|
|
|
|
set_dec_flags (0);
|
|
|
|
set_default_std_flags ();
|
|
|
|
/* Initialize cpp-related options. */
|
|
gfc_cpp_init_options (decoded_options_count, decoded_options);
|
|
gfc_diagnostics_init ();
|
|
}
|
|
|
|
|
|
/* Determine the source form from the filename extension. We assume
|
|
case insensitivity. */
|
|
|
|
static gfc_source_form
|
|
form_from_filename (const char *filename)
|
|
{
|
|
static const struct
|
|
{
|
|
const char *extension;
|
|
gfc_source_form form;
|
|
}
|
|
exttype[] =
|
|
{
|
|
{
|
|
".f90", FORM_FREE}
|
|
,
|
|
{
|
|
".f95", FORM_FREE}
|
|
,
|
|
{
|
|
".f03", FORM_FREE}
|
|
,
|
|
{
|
|
".f08", FORM_FREE}
|
|
,
|
|
{
|
|
".f", FORM_FIXED}
|
|
,
|
|
{
|
|
".for", FORM_FIXED}
|
|
,
|
|
{
|
|
".ftn", FORM_FIXED}
|
|
,
|
|
{
|
|
"", FORM_UNKNOWN}
|
|
}; /* sentinel value */
|
|
|
|
gfc_source_form f_form;
|
|
const char *fileext;
|
|
int i;
|
|
|
|
/* Find end of file name. Note, filename is either a NULL pointer or
|
|
a NUL terminated string. */
|
|
i = 0;
|
|
while (filename[i] != '\0')
|
|
i++;
|
|
|
|
/* Find last period. */
|
|
while (i >= 0 && (filename[i] != '.'))
|
|
i--;
|
|
|
|
/* Did we see a file extension? */
|
|
if (i < 0)
|
|
return FORM_UNKNOWN; /* Nope */
|
|
|
|
/* Get file extension and compare it to others. */
|
|
fileext = &(filename[i]);
|
|
|
|
i = -1;
|
|
f_form = FORM_UNKNOWN;
|
|
do
|
|
{
|
|
i++;
|
|
if (strcasecmp (fileext, exttype[i].extension) == 0)
|
|
{
|
|
f_form = exttype[i].form;
|
|
break;
|
|
}
|
|
}
|
|
while (exttype[i].form != FORM_UNKNOWN);
|
|
|
|
return f_form;
|
|
}
|
|
|
|
|
|
/* Finalize commandline options. */
|
|
|
|
bool
|
|
gfc_post_options (const char **pfilename)
|
|
{
|
|
const char *filename = *pfilename, *canon_source_file = NULL;
|
|
char *source_path;
|
|
int i;
|
|
|
|
/* Finalize DEC flags. */
|
|
post_dec_flags (flag_dec);
|
|
|
|
/* Excess precision other than "fast" requires front-end
|
|
support. */
|
|
if (flag_excess_precision == EXCESS_PRECISION_STANDARD)
|
|
sorry ("%<-fexcess-precision=standard%> for Fortran");
|
|
flag_excess_precision = EXCESS_PRECISION_FAST;
|
|
|
|
/* Fortran allows associative math - but we cannot reassociate if
|
|
we want traps or signed zeros. Cf. also flag_protect_parens. */
|
|
if (flag_associative_math == -1)
|
|
flag_associative_math = (!flag_trapping_math && !flag_signed_zeros);
|
|
|
|
if (flag_protect_parens == -1)
|
|
flag_protect_parens = !optimize_fast;
|
|
|
|
/* -Ofast sets implies -fstack-arrays unless an explicit size is set for
|
|
stack arrays. */
|
|
if (flag_stack_arrays == -1 && flag_max_stack_var_size == -2)
|
|
flag_stack_arrays = optimize_fast;
|
|
|
|
/* By default, disable (re)allocation during assignment for -std=f95,
|
|
and enable it for F2003/F2008/GNU/Legacy. */
|
|
if (flag_realloc_lhs == -1)
|
|
{
|
|
if (gfc_option.allow_std & GFC_STD_F2003)
|
|
flag_realloc_lhs = 1;
|
|
else
|
|
flag_realloc_lhs = 0;
|
|
}
|
|
|
|
/* -fbounds-check is equivalent to -fcheck=bounds */
|
|
if (flag_bounds_check)
|
|
gfc_option.rtcheck |= GFC_RTCHECK_BOUNDS;
|
|
|
|
if (flag_compare_debug)
|
|
flag_dump_fortran_original = 0;
|
|
|
|
/* Make -fmax-errors visible to gfortran's diagnostic machinery. */
|
|
if (global_options_set.x_flag_max_errors)
|
|
gfc_option.max_errors = flag_max_errors;
|
|
|
|
/* Verify the input file name. */
|
|
if (!filename || strcmp (filename, "-") == 0)
|
|
{
|
|
filename = "";
|
|
}
|
|
|
|
if (gfc_option.flag_preprocessed)
|
|
{
|
|
/* For preprocessed files, if the first tokens are of the form # NUM.
|
|
handle the directives so we know the original file name. */
|
|
gfc_source_file = gfc_read_orig_filename (filename, &canon_source_file);
|
|
if (gfc_source_file == NULL)
|
|
gfc_source_file = filename;
|
|
else
|
|
*pfilename = gfc_source_file;
|
|
}
|
|
else
|
|
gfc_source_file = filename;
|
|
|
|
if (canon_source_file == NULL)
|
|
canon_source_file = gfc_source_file;
|
|
|
|
/* Adds the path where the source file is to the list of include files. */
|
|
|
|
i = strlen (canon_source_file);
|
|
while (i > 0 && !IS_DIR_SEPARATOR (canon_source_file[i]))
|
|
i--;
|
|
|
|
if (i != 0)
|
|
{
|
|
source_path = (char *) alloca (i + 1);
|
|
memcpy (source_path, canon_source_file, i);
|
|
source_path[i] = 0;
|
|
gfc_add_include_path (source_path, true, true, true);
|
|
}
|
|
else
|
|
gfc_add_include_path (".", true, true, true);
|
|
|
|
if (canon_source_file != gfc_source_file)
|
|
free (CONST_CAST (char *, canon_source_file));
|
|
|
|
/* Decide which form the file will be read in as. */
|
|
|
|
if (gfc_option.source_form != FORM_UNKNOWN)
|
|
gfc_current_form = gfc_option.source_form;
|
|
else
|
|
{
|
|
gfc_current_form = form_from_filename (filename);
|
|
|
|
if (gfc_current_form == FORM_UNKNOWN)
|
|
{
|
|
gfc_current_form = FORM_FREE;
|
|
main_input_filename = filename;
|
|
gfc_warning_now (0, "Reading file %qs as free form",
|
|
(filename[0] == '\0') ? "<stdin>" : filename);
|
|
}
|
|
}
|
|
|
|
/* If the user specified -fd-lines-as-{code|comments} verify that we're
|
|
in fixed form. */
|
|
if (gfc_current_form == FORM_FREE)
|
|
{
|
|
if (gfc_option.flag_d_lines == 0)
|
|
gfc_warning_now (0, "%<-fd-lines-as-comments%> has no effect "
|
|
"in free form");
|
|
else if (gfc_option.flag_d_lines == 1)
|
|
gfc_warning_now (0, "%<-fd-lines-as-code%> has no effect in free form");
|
|
|
|
if (warn_line_truncation == -1)
|
|
warn_line_truncation = 1;
|
|
|
|
/* Enable -Werror=line-truncation when -Werror and -Wno-error have
|
|
not been set. */
|
|
if (warn_line_truncation && !global_options_set.x_warnings_are_errors
|
|
&& (global_dc->classify_diagnostic[OPT_Wline_truncation] ==
|
|
DK_UNSPECIFIED))
|
|
diagnostic_classify_diagnostic (global_dc, OPT_Wline_truncation,
|
|
DK_ERROR, UNKNOWN_LOCATION);
|
|
}
|
|
else
|
|
{
|
|
/* With -fdec, set -fd-lines-as-comments by default in fixed form. */
|
|
if (flag_dec && gfc_option.flag_d_lines == -1)
|
|
gfc_option.flag_d_lines = 0;
|
|
|
|
if (warn_line_truncation == -1)
|
|
warn_line_truncation = 0;
|
|
}
|
|
|
|
/* If -pedantic, warn about the use of GNU extensions. */
|
|
if (pedantic && (gfc_option.allow_std & GFC_STD_GNU) != 0)
|
|
gfc_option.warn_std |= GFC_STD_GNU;
|
|
/* -std=legacy -pedantic is effectively -std=gnu. */
|
|
if (pedantic && (gfc_option.allow_std & GFC_STD_LEGACY) != 0)
|
|
gfc_option.warn_std |= GFC_STD_F95_OBS | GFC_STD_F95_DEL | GFC_STD_LEGACY;
|
|
|
|
/* If the user didn't explicitly specify -f(no)-second-underscore we
|
|
use it if we're trying to be compatible with f2c, and not
|
|
otherwise. */
|
|
if (flag_second_underscore == -1)
|
|
flag_second_underscore = flag_f2c;
|
|
|
|
if (!flag_automatic && flag_max_stack_var_size != -2
|
|
&& flag_max_stack_var_size != 0)
|
|
gfc_warning_now (0, "Flag %<-fno-automatic%> overwrites %<-fmax-stack-var-size=%d%>",
|
|
flag_max_stack_var_size);
|
|
else if (!flag_automatic && flag_recursive)
|
|
gfc_warning_now (OPT_Woverwrite_recursive, "Flag %<-fno-automatic%> "
|
|
"overwrites %<-frecursive%>");
|
|
else if (!flag_automatic && flag_openmp)
|
|
gfc_warning_now (0, "Flag %<-fno-automatic%> overwrites %<-frecursive%> implied by "
|
|
"%<-fopenmp%>");
|
|
else if (flag_max_stack_var_size != -2 && flag_recursive)
|
|
gfc_warning_now (0, "Flag %<-frecursive%> overwrites %<-fmax-stack-var-size=%d%>",
|
|
flag_max_stack_var_size);
|
|
else if (flag_max_stack_var_size != -2 && flag_openmp)
|
|
gfc_warning_now (0, "Flag %<-fmax-stack-var-size=%d%> overwrites %<-frecursive%> "
|
|
"implied by %<-fopenmp%>", flag_max_stack_var_size);
|
|
|
|
/* Implement -frecursive as -fmax-stack-var-size=-1. */
|
|
if (flag_recursive)
|
|
flag_max_stack_var_size = -1;
|
|
|
|
/* Implied -frecursive; implemented as -fmax-stack-var-size=-1. */
|
|
if (flag_max_stack_var_size == -2 && flag_openmp && flag_automatic)
|
|
{
|
|
flag_recursive = 1;
|
|
flag_max_stack_var_size = -1;
|
|
}
|
|
|
|
/* Set flag_stack_arrays correctly. */
|
|
if (flag_stack_arrays == -1)
|
|
flag_stack_arrays = 0;
|
|
|
|
/* Set default. */
|
|
if (flag_max_stack_var_size == -2)
|
|
flag_max_stack_var_size = 65536;
|
|
|
|
/* Implement -fno-automatic as -fmax-stack-var-size=0. */
|
|
if (!flag_automatic)
|
|
flag_max_stack_var_size = 0;
|
|
|
|
/* If the user did not specify an inline matmul limit, inline up to the BLAS
|
|
limit or up to 30 if no external BLAS is specified. */
|
|
|
|
if (flag_inline_matmul_limit < 0)
|
|
{
|
|
if (flag_external_blas)
|
|
flag_inline_matmul_limit = flag_blas_matmul_limit;
|
|
else
|
|
flag_inline_matmul_limit = 30;
|
|
}
|
|
|
|
/* Optimization implies front end optimization, unless the user
|
|
specified it directly. */
|
|
|
|
if (flag_frontend_optimize == -1)
|
|
flag_frontend_optimize = optimize && !optimize_debug;
|
|
|
|
/* Same for front end loop interchange. */
|
|
|
|
if (flag_frontend_loop_interchange == -1)
|
|
flag_frontend_loop_interchange = optimize;
|
|
|
|
/* Do inline packing by default if optimizing, but not if
|
|
optimizing for size. */
|
|
if (flag_inline_arg_packing == -1)
|
|
flag_inline_arg_packing = optimize && !optimize_size;
|
|
|
|
if (flag_max_array_constructor < 65535)
|
|
flag_max_array_constructor = 65535;
|
|
|
|
if (flag_fixed_line_length != 0 && flag_fixed_line_length < 7)
|
|
gfc_fatal_error ("Fixed line length must be at least seven");
|
|
|
|
if (flag_free_line_length != 0 && flag_free_line_length < 4)
|
|
gfc_fatal_error ("Free line length must be at least three");
|
|
|
|
if (flag_max_subrecord_length > MAX_SUBRECORD_LENGTH)
|
|
gfc_fatal_error ("Maximum subrecord length cannot exceed %d",
|
|
MAX_SUBRECORD_LENGTH);
|
|
|
|
gfc_cpp_post_options ();
|
|
|
|
if (gfc_option.allow_std & GFC_STD_F2008)
|
|
lang_hooks.name = "GNU Fortran2008";
|
|
else if (gfc_option.allow_std & GFC_STD_F2003)
|
|
lang_hooks.name = "GNU Fortran2003";
|
|
|
|
return gfc_cpp_preprocess_only ();
|
|
}
|
|
|
|
|
|
static void
|
|
gfc_handle_module_path_options (const char *arg)
|
|
{
|
|
|
|
if (gfc_option.module_dir != NULL)
|
|
gfc_fatal_error ("gfortran: Only one %<-J%> option allowed");
|
|
|
|
gfc_option.module_dir = XCNEWVEC (char, strlen (arg) + 2);
|
|
strcpy (gfc_option.module_dir, arg);
|
|
|
|
gfc_add_include_path (gfc_option.module_dir, true, false, true);
|
|
|
|
strcat (gfc_option.module_dir, "/");
|
|
}
|
|
|
|
|
|
/* Handle options -ffpe-trap= and -ffpe-summary=. */
|
|
|
|
static void
|
|
gfc_handle_fpe_option (const char *arg, bool trap)
|
|
{
|
|
int result, pos = 0, n;
|
|
/* precision is a backwards compatibility alias for inexact. */
|
|
static const char * const exception[] = { "invalid", "denormal", "zero",
|
|
"overflow", "underflow",
|
|
"inexact", "precision", NULL };
|
|
static const int opt_exception[] = { GFC_FPE_INVALID, GFC_FPE_DENORMAL,
|
|
GFC_FPE_ZERO, GFC_FPE_OVERFLOW,
|
|
GFC_FPE_UNDERFLOW, GFC_FPE_INEXACT,
|
|
GFC_FPE_INEXACT,
|
|
0 };
|
|
|
|
/* As the default for -ffpe-summary= is nonzero, set it to 0. */
|
|
if (!trap)
|
|
gfc_option.fpe_summary = 0;
|
|
|
|
while (*arg)
|
|
{
|
|
while (*arg == ',')
|
|
arg++;
|
|
|
|
while (arg[pos] && arg[pos] != ',')
|
|
pos++;
|
|
|
|
result = 0;
|
|
if (!trap && strncmp ("none", arg, pos) == 0)
|
|
{
|
|
gfc_option.fpe_summary = 0;
|
|
arg += pos;
|
|
pos = 0;
|
|
continue;
|
|
}
|
|
else if (!trap && strncmp ("all", arg, pos) == 0)
|
|
{
|
|
gfc_option.fpe_summary = GFC_FPE_INVALID | GFC_FPE_DENORMAL
|
|
| GFC_FPE_ZERO | GFC_FPE_OVERFLOW
|
|
| GFC_FPE_UNDERFLOW | GFC_FPE_INEXACT;
|
|
arg += pos;
|
|
pos = 0;
|
|
continue;
|
|
}
|
|
else
|
|
for (n = 0; exception[n] != NULL; n++)
|
|
{
|
|
if (exception[n] && strncmp (exception[n], arg, pos) == 0)
|
|
{
|
|
if (trap)
|
|
gfc_option.fpe |= opt_exception[n];
|
|
else
|
|
gfc_option.fpe_summary |= opt_exception[n];
|
|
arg += pos;
|
|
pos = 0;
|
|
result = 1;
|
|
break;
|
|
}
|
|
}
|
|
if (!result && !trap)
|
|
gfc_fatal_error ("Argument to %<-ffpe-trap%> is not valid: %s", arg);
|
|
else if (!result)
|
|
gfc_fatal_error ("Argument to %<-ffpe-summary%> is not valid: %s", arg);
|
|
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
gfc_handle_runtime_check_option (const char *arg)
|
|
{
|
|
int result, pos = 0, n;
|
|
static const char * const optname[] = { "all", "bounds", "array-temps",
|
|
"recursion", "do", "pointer",
|
|
"mem", "bits", NULL };
|
|
static const int optmask[] = { GFC_RTCHECK_ALL, GFC_RTCHECK_BOUNDS,
|
|
GFC_RTCHECK_ARRAY_TEMPS,
|
|
GFC_RTCHECK_RECURSION, GFC_RTCHECK_DO,
|
|
GFC_RTCHECK_POINTER, GFC_RTCHECK_MEM,
|
|
GFC_RTCHECK_BITS, 0 };
|
|
|
|
while (*arg)
|
|
{
|
|
while (*arg == ',')
|
|
arg++;
|
|
|
|
while (arg[pos] && arg[pos] != ',')
|
|
pos++;
|
|
|
|
result = 0;
|
|
for (n = 0; optname[n] != NULL; n++)
|
|
{
|
|
if (optname[n] && strncmp (optname[n], arg, pos) == 0)
|
|
{
|
|
gfc_option.rtcheck |= optmask[n];
|
|
arg += pos;
|
|
pos = 0;
|
|
result = 1;
|
|
break;
|
|
}
|
|
else if (optname[n] && pos > 3 && gfc_str_startswith (arg, "no-")
|
|
&& strncmp (optname[n], arg+3, pos-3) == 0)
|
|
{
|
|
gfc_option.rtcheck &= ~optmask[n];
|
|
arg += pos;
|
|
pos = 0;
|
|
result = 1;
|
|
break;
|
|
}
|
|
}
|
|
if (!result)
|
|
gfc_fatal_error ("Argument to %<-fcheck%> is not valid: %s", arg);
|
|
}
|
|
}
|
|
|
|
|
|
/* Handle command-line options. Returns 0 if unrecognized, 1 if
|
|
recognized and handled. */
|
|
|
|
bool
|
|
gfc_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value,
|
|
int kind ATTRIBUTE_UNUSED, location_t loc ATTRIBUTE_UNUSED,
|
|
const struct cl_option_handlers *handlers ATTRIBUTE_UNUSED)
|
|
{
|
|
bool result = true;
|
|
enum opt_code code = (enum opt_code) scode;
|
|
|
|
if (gfc_cpp_handle_option (scode, arg, value) == 1)
|
|
return true;
|
|
|
|
switch (code)
|
|
{
|
|
default:
|
|
if (cl_options[code].flags & gfc_option_lang_mask ())
|
|
break;
|
|
result = false;
|
|
break;
|
|
|
|
case OPT_fcheck_array_temporaries:
|
|
SET_BITFLAG (gfc_option.rtcheck, value, GFC_RTCHECK_ARRAY_TEMPS);
|
|
break;
|
|
|
|
case OPT_fd_lines_as_code:
|
|
gfc_option.flag_d_lines = 1;
|
|
break;
|
|
|
|
case OPT_fd_lines_as_comments:
|
|
gfc_option.flag_d_lines = 0;
|
|
break;
|
|
|
|
case OPT_ffixed_form:
|
|
gfc_option.source_form = FORM_FIXED;
|
|
break;
|
|
|
|
case OPT_ffree_form:
|
|
gfc_option.source_form = FORM_FREE;
|
|
break;
|
|
|
|
case OPT_static_libgfortran:
|
|
#ifndef HAVE_LD_STATIC_DYNAMIC
|
|
gfc_fatal_error ("%<-static-libgfortran%> is not supported in this "
|
|
"configuration");
|
|
#endif
|
|
break;
|
|
|
|
case OPT_fintrinsic_modules_path:
|
|
case OPT_fintrinsic_modules_path_:
|
|
|
|
/* This is needed because omp_lib.h is in a directory together
|
|
with intrinsic modules. Do no warn because during testing
|
|
without an installed compiler, we would get lots of bogus
|
|
warnings for a missing include directory. */
|
|
gfc_add_include_path (arg, false, false, false);
|
|
|
|
gfc_add_intrinsic_modules_path (arg);
|
|
break;
|
|
|
|
case OPT_fpreprocessed:
|
|
gfc_option.flag_preprocessed = value;
|
|
break;
|
|
|
|
case OPT_fmax_identifier_length_:
|
|
if (value > GFC_MAX_SYMBOL_LEN)
|
|
gfc_fatal_error ("Maximum supported identifier length is %d",
|
|
GFC_MAX_SYMBOL_LEN);
|
|
gfc_option.max_identifier_length = value;
|
|
break;
|
|
|
|
case OPT_finit_local_zero:
|
|
set_init_local_zero (value);
|
|
break;
|
|
|
|
case OPT_finit_logical_:
|
|
if (!strcasecmp (arg, "false"))
|
|
gfc_option.flag_init_logical = GFC_INIT_LOGICAL_FALSE;
|
|
else if (!strcasecmp (arg, "true"))
|
|
gfc_option.flag_init_logical = GFC_INIT_LOGICAL_TRUE;
|
|
else
|
|
gfc_fatal_error ("Unrecognized option to %<-finit-logical%>: %s",
|
|
arg);
|
|
break;
|
|
|
|
case OPT_finit_integer_:
|
|
gfc_option.flag_init_integer = GFC_INIT_INTEGER_ON;
|
|
gfc_option.flag_init_integer_value = strtol (arg, NULL, 10);
|
|
break;
|
|
|
|
case OPT_finit_character_:
|
|
if (value >= 0 && value <= 127)
|
|
{
|
|
gfc_option.flag_init_character = GFC_INIT_CHARACTER_ON;
|
|
gfc_option.flag_init_character_value = (char)value;
|
|
}
|
|
else
|
|
gfc_fatal_error ("The value of n in %<-finit-character=n%> must be "
|
|
"between 0 and 127");
|
|
break;
|
|
|
|
case OPT_I:
|
|
gfc_add_include_path (arg, true, false, true);
|
|
break;
|
|
|
|
case OPT_J:
|
|
gfc_handle_module_path_options (arg);
|
|
break;
|
|
|
|
case OPT_ffpe_trap_:
|
|
gfc_handle_fpe_option (arg, true);
|
|
break;
|
|
|
|
case OPT_ffpe_summary_:
|
|
gfc_handle_fpe_option (arg, false);
|
|
break;
|
|
|
|
case OPT_std_f95:
|
|
gfc_option.allow_std = GFC_STD_OPT_F95;
|
|
gfc_option.warn_std = GFC_STD_F95_OBS;
|
|
gfc_option.max_continue_fixed = 19;
|
|
gfc_option.max_continue_free = 39;
|
|
gfc_option.max_identifier_length = 31;
|
|
warn_ampersand = 1;
|
|
warn_tabs = 1;
|
|
break;
|
|
|
|
case OPT_std_f2003:
|
|
gfc_option.allow_std = GFC_STD_OPT_F03;
|
|
gfc_option.warn_std = GFC_STD_F95_OBS;
|
|
gfc_option.max_identifier_length = 63;
|
|
warn_ampersand = 1;
|
|
warn_tabs = 1;
|
|
break;
|
|
|
|
case OPT_std_f2008:
|
|
gfc_option.allow_std = GFC_STD_OPT_F08;
|
|
gfc_option.warn_std = GFC_STD_F95_OBS | GFC_STD_F2008_OBS;
|
|
gfc_option.max_identifier_length = 63;
|
|
warn_ampersand = 1;
|
|
warn_tabs = 1;
|
|
break;
|
|
|
|
case OPT_std_f2008ts:
|
|
case OPT_std_f2018:
|
|
gfc_option.allow_std = GFC_STD_OPT_F18;
|
|
gfc_option.warn_std = GFC_STD_F95_OBS | GFC_STD_F2008_OBS
|
|
| GFC_STD_F2018_OBS;
|
|
gfc_option.max_identifier_length = 63;
|
|
warn_ampersand = 1;
|
|
warn_tabs = 1;
|
|
break;
|
|
|
|
case OPT_std_gnu:
|
|
set_default_std_flags ();
|
|
break;
|
|
|
|
case OPT_std_legacy:
|
|
set_default_std_flags ();
|
|
gfc_option.warn_std = 0;
|
|
break;
|
|
|
|
case OPT_fshort_enums:
|
|
/* Handled in language-independent code. */
|
|
break;
|
|
|
|
case OPT_fcheck_:
|
|
gfc_handle_runtime_check_option (arg);
|
|
break;
|
|
|
|
case OPT_fdec:
|
|
/* Set (or unset) the DEC extension flags. */
|
|
set_dec_flags (value);
|
|
break;
|
|
}
|
|
|
|
Fortran_handle_option_auto (&global_options, &global_options_set,
|
|
scode, arg, value,
|
|
gfc_option_lang_mask (), kind,
|
|
loc, handlers, global_dc);
|
|
return result;
|
|
}
|
|
|
|
|
|
/* Return a string with the options passed to the compiler; used for
|
|
Fortran's compiler_options() intrinsic. */
|
|
|
|
char *
|
|
gfc_get_option_string (void)
|
|
{
|
|
unsigned j;
|
|
size_t len, pos;
|
|
char *result;
|
|
|
|
/* Allocate and return a one-character string with '\0'. */
|
|
if (!save_decoded_options_count)
|
|
return XCNEWVEC (char, 1);
|
|
|
|
/* Determine required string length. */
|
|
|
|
len = 0;
|
|
for (j = 1; j < save_decoded_options_count; j++)
|
|
{
|
|
switch (save_decoded_options[j].opt_index)
|
|
{
|
|
case OPT_o:
|
|
case OPT_d:
|
|
case OPT_dumpbase:
|
|
case OPT_dumpbase_ext:
|
|
case OPT_dumpdir:
|
|
case OPT_quiet:
|
|
case OPT_version:
|
|
case OPT_fintrinsic_modules_path:
|
|
case OPT_fintrinsic_modules_path_:
|
|
/* Ignore these. */
|
|
break;
|
|
default:
|
|
/* Ignore file names. */
|
|
if (save_decoded_options[j].orig_option_with_args_text[0] == '-')
|
|
len += 1
|
|
+ strlen (save_decoded_options[j].orig_option_with_args_text);
|
|
}
|
|
}
|
|
|
|
result = XCNEWVEC (char, len);
|
|
|
|
pos = 0;
|
|
for (j = 1; j < save_decoded_options_count; j++)
|
|
{
|
|
switch (save_decoded_options[j].opt_index)
|
|
{
|
|
case OPT_o:
|
|
case OPT_d:
|
|
case OPT_dumpbase:
|
|
case OPT_dumpbase_ext:
|
|
case OPT_dumpdir:
|
|
case OPT_quiet:
|
|
case OPT_version:
|
|
case OPT_fintrinsic_modules_path:
|
|
case OPT_fintrinsic_modules_path_:
|
|
/* Ignore these. */
|
|
continue;
|
|
|
|
case OPT_cpp_:
|
|
/* Use "-cpp" rather than "-cpp=<temporary file>". */
|
|
len = 4;
|
|
break;
|
|
|
|
default:
|
|
/* Ignore file names. */
|
|
if (save_decoded_options[j].orig_option_with_args_text[0] != '-')
|
|
continue;
|
|
|
|
len = strlen (save_decoded_options[j].orig_option_with_args_text);
|
|
}
|
|
|
|
memcpy (&result[pos], save_decoded_options[j].orig_option_with_args_text, len);
|
|
pos += len;
|
|
result[pos++] = ' ';
|
|
}
|
|
|
|
result[--pos] = '\0';
|
|
return result;
|
|
}
|
|
|
|
#undef SET_BITFLAG
|
|
#undef SET_BITFLAG2
|
|
#undef SET_FLAG
|