def fcheck_EQ : Joined<["-"], "fcheck=">, Group<gfortran_Group>;
def fcoarray_EQ : Joined<["-"], "fcoarray=">, Group<gfortran_Group>;
def fconvert_EQ : Joined<["-"], "fconvert=">, Group<gfortran_Group>;
-def ffixed_line_length_VALUE : Joined<["-"], "ffixed-line-length-">, Group<gfortran_Group>;
def ffpe_trap_EQ : Joined<["-"], "ffpe-trap=">, Group<gfortran_Group>;
def ffree_line_length_VALUE : Joined<["-"], "ffree-line-length-">, Group<gfortran_Group>;
def finit_character_EQ : Joined<["-"], "finit-character=">, Group<gfortran_Group>;
defm dump_parse_tree : BooleanFFlag<"dump-parse-tree">, Group<gfortran_Group>;
defm external_blas : BooleanFFlag<"external-blas">, Group<gfortran_Group>;
defm f2c : BooleanFFlag<"f2c">, Group<gfortran_Group>;
-defm fixed_form : BooleanFFlag<"fixed-form">, Group<gfortran_Group>;
-defm free_form : BooleanFFlag<"free-form">, Group<gfortran_Group>;
defm frontend_optimize : BooleanFFlag<"frontend-optimize">, Group<gfortran_Group>;
defm implicit_none : BooleanFFlag<"implicit-none">, Group<gfortran_Group>;
defm init_local_zero : BooleanFFlag<"init-local-zero">, Group<gfortran_Group>;
def test_io : Flag<["-"], "test-io">, Flags<[HelpHidden, FlangOption, FC1Option, FlangOnlyOption]>, Group<Action_Group>,
HelpText<"Run the InputOuputTest action. Use for development and testing only.">;
+let Flags = [FC1Option, FlangOption, FlangOnlyOption] in {
+
+def ffixed_form : Flag<["-"], "ffixed-form">, Group<f_Group>,
+ HelpText<"Process source files in fixed form">;
+def ffree_form : Flag<["-"], "ffree-form">, Group<f_Group>,
+ HelpText<"Process source files in free form">;
+def ffixed_line_length_EQ : Joined<["-"], "ffixed-line-length=">, Group<f_Group>,
+ HelpText<"Use <value> as character line width in fixed mode">,
+ DocBrief<[{Set column after which characters are ignored in typical fixed-form lines in the source
+file}]>;
+def ffixed_line_length_VALUE : Joined<["-"], "ffixed-line-length-">, Group<f_Group>, Alias<ffixed_line_length_EQ>;
+
+}
+
//===----------------------------------------------------------------------===//
// CC1 Options
//===----------------------------------------------------------------------===//
using namespace clang;
using namespace llvm::opt;
+void Flang::AddFortranDialectOptions(const ArgList &Args,
+ ArgStringList &CmdArgs) const {
+ Args.AddAllArgs(CmdArgs, {options::OPT_ffixed_form, options::OPT_ffree_form,
+ options::OPT_ffixed_line_length_EQ});
+}
+
void Flang::AddPreprocessingOptions(const ArgList &Args,
ArgStringList &CmdArgs) const {
Args.AddAllArgs(CmdArgs, {options::OPT_D, options::OPT_U, options::OPT_I});
if (types::getPreprocessedType(InputType) != types::TY_INVALID)
AddPreprocessingOptions(Args, CmdArgs);
+ AddFortranDialectOptions(Args, CmdArgs);
+
if (Output.isFilename()) {
CmdArgs.push_back("-o");
CmdArgs.push_back(Output.getFilename());
/// Flang compiler tool.
class LLVM_LIBRARY_VISIBILITY Flang : public Tool {
private:
+ /// Extract fortran dialect options from the driver arguments and add them to
+ /// the list of arguments for the generated command/job.
+ ///
+ /// \param [in] Args The list of input driver arguments
+ /// \param [out] CmdArgs The list of output command arguments
+ void AddFortranDialectOptions(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const;
+
/// Extract preprocessing options from the driver arguments and add them to
/// the preprocessor command arguments.
///
Fortran,
};
+// Source file layout
+enum class FortranForm {
+ /// The user has not specified a form. Base the form off the file extension.
+ Unknown,
+
+ /// -ffree-form
+ FixedForm,
+
+ /// -ffixed-form
+ FreeForm
+};
+
/// The kind of a file that we've been handed as an input.
class InputKind {
private:
/// The frontend action to perform.
frontend::ActionKind programAction_;
+ // The form to process files in, if specified.
+ FortranForm fortranForm_ = FortranForm::Unknown;
+
+ // The column after which characters are ignored in fixed form lines in the
+ // source file.
+ int fixedFormColumns_ = 72;
+
public:
FrontendOptions() : showHelp_(false), showVersion_(false) {}
// Run the frontend action `act` for every input file.
for (const FrontendInputFile &fif : frontendOpts().inputs_) {
if (act.BeginSourceFile(*this, fif)) {
- // Switch between fixed and free form format based on the input file
- // extension. Ideally we should have all Fortran options set before
- // entering this loop (i.e. processing any input files). However, we
- // can't decide between fixed and free form based on the file extension
- // earlier than this.
- invoc.fortranOpts().isFixedForm = fif.IsFixedForm();
+ if (invoc.frontendOpts().fortranForm_ == FortranForm::Unknown) {
+ // Switch between fixed and free form format based on the input file
+ // extension. Ideally we should have all Fortran options set before
+ // entering this loop (i.e. processing any input files). However, we
+ // can't decide between fixed and free form based on the file extension
+ // earlier than this.
+ invoc.fortranOpts().isFixedForm = fif.IsFixedForm();
+ }
if (llvm::Error err = act.Execute()) {
consumeError(std::move(err));
}
opts.inputs_.emplace_back(std::move(inputs[i]), ik);
}
+
+ // Set fortranForm_ based on options -ffree-form and -ffixed-form.
+ if (const auto *arg = args.getLastArg(clang::driver::options::OPT_ffixed_form,
+ clang::driver::options::OPT_ffree_form)) {
+ opts.fortranForm_ =
+ arg->getOption().matches(clang::driver::options::OPT_ffixed_form)
+ ? FortranForm::FixedForm
+ : FortranForm::FreeForm;
+ }
+
+ // Set fixedFormColumns_ based on -ffixed-line-length=<value>
+ if (const auto *arg =
+ args.getLastArg(clang::driver::options::OPT_ffixed_line_length_EQ)) {
+ llvm::StringRef argValue = llvm::StringRef(arg->getValue());
+ std::int64_t columns = -1;
+ if (argValue == "none") {
+ columns = 0;
+ } else if (argValue.getAsInteger(/*Radix=*/10, columns)) {
+ columns = -1;
+ }
+ if (columns < 0) {
+ diags.Report(clang::diag::err_drv_invalid_value_with_suggestion)
+ << arg->getOption().getName() << arg->getValue()
+ << "value must be 'none' or a non-negative integer";
+ } else if (columns == 0) {
+ opts.fixedFormColumns_ = 1000000;
+ } else if (columns < 7) {
+ diags.Report(clang::diag::err_drv_invalid_value_with_suggestion)
+ << arg->getOption().getName() << arg->getValue()
+ << "value must be at least seven";
+ } else {
+ opts.fixedFormColumns_ = columns;
+ }
+ }
return dashX;
}
void CompilerInvocation::setFortranOpts() {
auto &fortranOptions = fortranOpts();
+ const auto &frontendOptions = frontendOpts();
const auto &preprocessorOptions = preprocessorOpts();
+ if (frontendOptions.fortranForm_ != FortranForm::Unknown) {
+ fortranOptions.isFixedForm =
+ frontendOptions.fortranForm_ == FortranForm::FixedForm;
+ }
+ fortranOptions.fixedFormColumns = frontendOptions.fixedFormColumns_;
+
collectMacroDefinitions(preprocessorOptions, fortranOptions);
fortranOptions.searchDirectories.insert(
program FixedForm
+c end
end
--- /dev/null
+! The length of the line below is exactly 73 characters
+ program aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ end
! CHECK-NEXT: -D <macro>=<value> Define <macro> to <value> (or 1 if <value> omitted)
! CHECK-NEXT: -E Only run the preprocessor
! CHECK-NEXT: -fcolor-diagnostics Enable colors in diagnostics
+! CHECK-NEXT: -ffixed-form Process source files in fixed form
+! CHECK-NEXT: -ffixed-line-length=<value>
+! CHECK-NEXT: Use <value> as character line width in fixed mode
+! CHECK-NEXT: -ffree-form Process source files in free form
! CHECK-NEXT: -fno-color-diagnostics Disable colors in diagnostics
! CHECK-NEXT: -help Display available options
! CHECK-NEXT: -I <dir> Add directory to the end of the list of include search paths
! HELP-NEXT: -D <macro>=<value> Define <macro> to <value> (or 1 if <value> omitted)
! HELP-NEXT: -E Only run the preprocessor
! HELP-NEXT: -fcolor-diagnostics Enable colors in diagnostics
+! HELP-NEXT: -ffixed-form Process source files in fixed form
+! HELP-NEXT: -ffixed-line-length=<value>
+! HELP-NEXT: Use <value> as character line width in fixed mode
+! HELP-NEXT: -ffree-form Process source files in free form
! HELP-NEXT: -fno-color-diagnostics Disable colors in diagnostics
! HELP-NEXT: -help Display available options
! HELP-NEXT: -I <dir> Add directory to the end of the list of include search paths
! HELP-FC1-NEXT: -D <macro>=<value> Define <macro> to <value> (or 1 if <value> omitted)
! HELP-FC1-NEXT: -emit-obj Emit native object files
! HELP-FC1-NEXT: -E Only run the preprocessor
+! HELP-FC1-NEXT: -ffixed-form Process source files in fixed form
+! HELP-FC1-NEXT: -ffixed-line-length=<value>
+! HELP-FC1-NEXT: Use <value> as character line width in fixed mode
+! HELP-FC1-NEXT: -ffree-form Process source files in free form
! HELP-FC1-NEXT: -help Display available options
! HELP-FC1-NEXT: -I <dir> Add directory to the end of the list of include search paths
! HELP-FC1-NEXT: -o <file> Write output to <file>
--- /dev/null
+! Ensure arguments -ffree-form and -ffixed-form work as expected.
+
+! REQUIRES: new-flang-driver
+
+!--------------------------
+! FLANG DRIVER (flang-new)
+!--------------------------
+! RUN: not %flang-new -fsyntax-only -ffree-form %S/Inputs/fixed-form-test.f 2>&1 | FileCheck %s --check-prefix=FREEFORM
+! RUN: %flang-new -fsyntax-only -ffixed-form %S/Inputs/free-form-test.f90 2>&1 | FileCheck %s --check-prefix=FIXEDFORM
+
+!----------------------------------------
+! FRONTEND FLANG DRIVER (flang-new -fc1)
+!----------------------------------------
+! RUN: not %flang-new -fc1 -fsyntax-only -ffree-form %S/Inputs/fixed-form-test.f 2>&1 | FileCheck %s --check-prefix=FREEFORM
+! RUN: %flang-new -fc1 -fsyntax-only -ffixed-form %S/Inputs/free-form-test.f90 2>&1 | FileCheck %s --check-prefix=FIXEDFORM
+
+!------------------------------------
+! EXPECTED OUTPUT FOR FREE FORM MODE
+!------------------------------------
+! FREEFORM:error: Could not parse
+
+!-------------------------------------
+! EXPECTED OUTPUT FOR FIXED FORM MODE
+!-------------------------------------
+! FIXEDFORM:free-form-test.f90:1:1: Character in fixed-form label field must be a digit
--- /dev/null
+! Ensure argument -ffixed-line-length=n works as expected.
+
+! REQUIRES: new-flang-driver
+
+!--------------------------
+! FLANG DRIVER (flang-new)
+!--------------------------
+! RUN: %flang-new -E %S/Inputs/fixed-line-length-test.f 2>&1 | FileCheck %s --check-prefix=DEFAULTLENGTH
+! RUN: not %flang-new -E -ffixed-line-length=-2 %S/Inputs/fixed-line-length-test.f 2>&1 | FileCheck %s --check-prefix=NEGATIVELENGTH
+! RUN: not %flang-new -E -ffixed-line-length=3 %S/Inputs/fixed-line-length-test.f 2>&1 | FileCheck %s --check-prefix=INVALIDLENGTH
+! RUN: %flang-new -E -ffixed-line-length=none %S/Inputs/fixed-line-length-test.f 2>&1 | FileCheck %s --check-prefix=UNLIMITEDLENGTH
+! RUN: %flang-new -E -ffixed-line-length=0 %S/Inputs/fixed-line-length-test.f 2>&1 | FileCheck %s --check-prefix=UNLIMITEDLENGTH
+! RUN: %flang-new -E -ffixed-line-length=13 %S/Inputs/fixed-line-length-test.f 2>&1 | FileCheck %s --check-prefix=LENGTH13
+
+!----------------------------------------
+! FRONTEND FLANG DRIVER (flang-new -fc1)
+!----------------------------------------
+! RUN: %flang-new -fc1 -E %S/Inputs/fixed-line-length-test.f 2>&1 | FileCheck %s --check-prefix=DEFAULTLENGTH
+! RUN: not %flang-new -fc1 -E -ffixed-line-length=-2 %S/Inputs/fixed-line-length-test.f 2>&1 | FileCheck %s --check-prefix=NEGATIVELENGTH
+! RUN: not %flang-new -fc1 -E -ffixed-line-length=3 %S/Inputs/fixed-line-length-test.f 2>&1 | FileCheck %s --check-prefix=INVALIDLENGTH
+! RUN: %flang-new -fc1 -E -ffixed-line-length=none %S/Inputs/fixed-line-length-test.f 2>&1 | FileCheck %s --check-prefix=UNLIMITEDLENGTH
+! RUN: %flang-new -fc1 -E -ffixed-line-length=0 %S/Inputs/fixed-line-length-test.f 2>&1 | FileCheck %s --check-prefix=UNLIMITEDLENGTH
+! RUN: %flang-new -fc1 -E -ffixed-line-length=13 %S/Inputs/fixed-line-length-test.f 2>&1 | FileCheck %s --check-prefix=LENGTH13
+
+!-------------------------------------
+! COMMAND ALIAS -ffixed-line-length-n
+!-------------------------------------
+! RUN: %flang-new -E -ffixed-line-length-13 %S/Inputs/fixed-line-length-test.f 2>&1 | FileCheck %s --check-prefix=LENGTH13
+! RUN: %flang-new -fc1 -E -ffixed-line-length-13 %S/Inputs/fixed-line-length-test.f 2>&1 | FileCheck %s --check-prefix=LENGTH13
+
+!-------------------------------------
+! EXPECTED OUTPUT WITH DEFAULT LENGTH
+!-------------------------------------
+! The line should be trimmed to 72 characters when reading based on the default value of fixed line length.
+! DEFAULTLENGTH: program{{(a{58})}}
+
+!-----------------------------------------
+! EXPECTED OUTPUT WITH A NEGATIVE LENGTH
+!-----------------------------------------
+! NEGATIVELENGTH: invalid value '-2' in 'ffixed-line-length=','value must be 'none' or a non-negative integer'
+
+!-----------------------------------------
+! EXPECTED OUTPUT WITH LENGTH LESS THAN 7
+!-----------------------------------------
+! INVALIDLENGTH: invalid value '3' in 'ffixed-line-length=','value must be at least seven'
+
+!---------------------------------------
+! EXPECTED OUTPUT WITH UNLIMITED LENGTH
+!---------------------------------------
+! The line should not be trimmed and so 73 characters (including spaces) should be read.
+! UNLIMITEDLENGTH: program{{(a{59})}}
+
+!--------------------------------
+! EXPECTED OUTPUT WITH LENGTH 13
+!--------------------------------
+! LENGTH13: program