/* Parse and display command line options. Copyright (C) 2000-2015 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 . */ #include "config.h" #include "system.h" #include "coretypes.h" #include "hash-set.h" #include "machmode.h" #include "vec.h" #include "double-int.h" #include "input.h" #include "alias.h" #include "symtab.h" #include "options.h" #include "wide-int.h" #include "inchash.h" #include "tree.h" #include "flags.h" #include "intl.h" #include "opts.h" #include "toplev.h" /* For save_decoded_options. */ #include "params.h" #include "tree-inline.h" #include "gfortran.h" #include "target.h" #include "cpp.h" #include "diagnostic.h" /* For global_dc. */ #include "tm.h" #include "langhooks.h" gfc_option_t gfc_option; /* 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_F2008_TS | GFC_STD_GNU | GFC_STD_LEGACY; gfc_option.warn_std = GFC_STD_F95_DEL | GFC_STD_LEGACY; } /* 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; gfc_option.flag_init_integer = GFC_INIT_INTEGER_OFF; gfc_option.flag_init_integer_value = 0; gfc_option.flag_init_logical = GFC_INIT_LOGICAL_OFF; gfc_option.flag_init_character = GFC_INIT_CHARACTER_OFF; gfc_option.flag_init_character_value = (char)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. */ if (!global_options_set.x_cpp_warn_missing_include_dirs) global_options.x_cpp_warn_missing_include_dirs = 1;; 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; /* Excess precision other than "fast" requires front-end support. */ if (flag_excess_precision_cmdline == EXCESS_PRECISION_STANDARD && TARGET_FLT_EVAL_METHOD_NON_DEFAULT) sorry ("-fexcess-precision=standard for Fortran"); flag_excess_precision_cmdline = 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; if (flag_stack_arrays == -1) 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; gfc_warning_now (0, "Reading file %qs as free form", (filename[0] == '\0') ? "" : 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 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 (0, "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 default. */ if (flag_max_stack_var_size == -2) flag_max_stack_var_size = 32768; /* Implement -fno-automatic as -fmax-stack-var-size=0. */ if (!flag_automatic) flag_max_stack_var_size = 0; /* Optimization implies front end optimization, unless the user specified it directly. */ if (flag_frontend_optimize == -1) flag_frontend_optimize = optimize; 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", 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, 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; } } 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, 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: gfc_option.rtcheck |= 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: gfc_option.flag_init_integer = GFC_INIT_INTEGER_ON; gfc_option.flag_init_integer_value = 0; flag_init_real = GFC_INIT_REAL_ZERO; gfc_option.flag_init_logical = GFC_INIT_LOGICAL_FALSE; gfc_option.flag_init_character = GFC_INIT_CHARACTER_ON; gfc_option.flag_init_character_value = (char)0; 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 = atoi (arg); 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_F95_OBS | GFC_STD_F95 | GFC_STD_F77 | GFC_STD_F2008_OBS; 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_F95_OBS | GFC_STD_F77 | GFC_STD_F2003 | GFC_STD_F95 | GFC_STD_F2008_OBS; 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_F95_OBS | GFC_STD_F77 | GFC_STD_F2003 | GFC_STD_F95 | GFC_STD_F2008 | GFC_STD_F2008_OBS; 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: gfc_option.allow_std = GFC_STD_F95_OBS | GFC_STD_F77 | GFC_STD_F2003 | GFC_STD_F95 | GFC_STD_F2008 | GFC_STD_F2008_OBS | GFC_STD_F2008_TS; 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_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; } 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_dumpdir: case OPT_auxbase: 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_dumpdir: case OPT_auxbase: 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=". */ 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; }