8sa1-gcc/gcc/fortran/options.c
Alexandre Oliva 1dedc12d18 revamp dump and aux output names
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.
2020-05-26 04:30:15 -03:00

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