diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -4071,7 +4071,9 @@ def fcheck_EQ : Joined<["-"], "fcheck=">, Group; def fcoarray_EQ : Joined<["-"], "fcoarray=">, Group; def fconvert_EQ : Joined<["-"], "fconvert=">, Group; -def ffixed_line_length_VALUE : Joined<["-"], "ffixed-line-length-">, Group; +def ffixed_line_length_VALUE : Joined<["-"], "ffixed-line-length-">, Flags<[FlangOption, FC1Option]>, + HelpText<"Set column after which characters are ignored in typical fixed-form lines in the source file">, + Group; def ffpe_trap_EQ : Joined<["-"], "ffpe-trap=">, Group; def ffree_line_length_VALUE : Joined<["-"], "ffree-line-length-">, Group; def finit_character_EQ : Joined<["-"], "finit-character=">, Group; @@ -4105,8 +4107,8 @@ defm dump_parse_tree : BooleanFFlag<"dump-parse-tree">, Group; defm external_blas : BooleanFFlag<"external-blas">, Group; defm f2c : BooleanFFlag<"f2c">, Group; -defm fixed_form : BooleanFFlag<"fixed-form">, Group; -defm free_form : BooleanFFlag<"free-form">, Group; +defm fixed_form : BooleanFFlag<"fixed-form">, Flags<[FlangOption, FC1Option]>, Group; +defm free_form : BooleanFFlag<"free-form">, Flags<[FlangOption, FC1Option]>, Group; defm frontend_optimize : BooleanFFlag<"frontend-optimize">, Group; defm implicit_none : BooleanFFlag<"implicit-none">, Group; defm init_local_zero : BooleanFFlag<"init-local-zero">, Group; diff --git a/clang/lib/Driver/ToolChains/Flang.cpp b/clang/lib/Driver/ToolChains/Flang.cpp --- a/clang/lib/Driver/ToolChains/Flang.cpp +++ b/clang/lib/Driver/ToolChains/Flang.cpp @@ -21,7 +21,9 @@ void Flang::AddPreprocessingOptions(const ArgList &Args, ArgStringList &CmdArgs) const { - Args.AddAllArgs(CmdArgs, {options::OPT_D, options::OPT_U, options::OPT_I}); + Args.AddAllArgs(CmdArgs, {options::OPT_D, options::OPT_U, options::OPT_I, + options::OPT_ffixed_form, options::OPT_ffree_form, + options::OPT_ffixed_line_length_VALUE}); } void Flang::ConstructJob(Compilation &C, const JobAction &JA, diff --git a/flang/include/flang/Frontend/FrontendOptions.h b/flang/include/flang/Frontend/FrontendOptions.h --- a/flang/include/flang/Frontend/FrontendOptions.h +++ b/flang/include/flang/Frontend/FrontendOptions.h @@ -74,6 +74,17 @@ Fortran, }; +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: @@ -159,6 +170,13 @@ /// 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) {} diff --git a/flang/lib/Frontend/CompilerInstance.cpp b/flang/lib/Frontend/CompilerInstance.cpp --- a/flang/lib/Frontend/CompilerInstance.cpp +++ b/flang/lib/Frontend/CompilerInstance.cpp @@ -148,12 +148,14 @@ // 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)); } diff --git a/flang/lib/Frontend/CompilerInvocation.cpp b/flang/lib/Frontend/CompilerInvocation.cpp --- a/flang/lib/Frontend/CompilerInvocation.cpp +++ b/flang/lib/Frontend/CompilerInvocation.cpp @@ -158,6 +158,45 @@ opts.inputs_.emplace_back(std::move(inputs[i]), ik); } + + // Set fortranForm_ based on options -ffree-form and -ffixed-form. + for (const auto *currentArg : + args.filtered(clang::driver::options::OPT_ffixed_form, + clang::driver::options::OPT_ffree_form)) { + if (currentArg->getOption().matches( + clang::driver::options::OPT_ffixed_form)) { + opts.fortranForm_ = FortranForm::FixedForm; + } else { + opts.fortranForm_ = FortranForm::FreeForm; + } + currentArg->claim(); + } + + // Set fixedFormColumns_ based on -ffixed-line-length-n + for (const auto *currentArg : + args.filtered(clang::driver::options::OPT_ffixed_line_length_VALUE)) { + llvm::StringRef argValue = llvm::StringRef(currentArg->getValue()); + std::int64_t columns = -1; + if (argValue == "none") { + columns = 0; + } else if (argValue.getAsInteger(10, columns)) { + columns = -1; + } + if (columns < 0) { + diags.Report(clang::diag::err_drv_invalid_value_with_suggestion) + << currentArg->getOption().getName() << currentArg->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) + << currentArg->getOption().getName() << currentArg->getValue() + << "value must be at least seven"; + } else { + opts.fixedFormColumns_ = columns; + } + currentArg->claim(); + } return dashX; } @@ -274,8 +313,16 @@ void CompilerInvocation::setFortranOpts() { auto &fortranOptions = fortranOpts(); + const auto &frontendOptions = frontendOpts(); const auto &preprocessorOptions = preprocessorOpts(); + if (frontendOptions.fortranForm_ == FortranForm::FixedForm) { + fortranOptions.isFixedForm = true; + } else if (frontendOptions.fortranForm_ == FortranForm::FreeForm) { + fortranOptions.isFixedForm = false; + } + fortranOptions.fixedFormColumns = frontendOptions.fixedFormColumns_; + collectMacroDefinitions(preprocessorOptions, fortranOptions); fortranOptions.searchDirectories.insert( diff --git a/flang/test/Flang-Driver/Inputs/fixed-form-test.f b/flang/test/Flang-Driver/Inputs/fixed-form-test.f --- a/flang/test/Flang-Driver/Inputs/fixed-form-test.f +++ b/flang/test/Flang-Driver/Inputs/fixed-form-test.f @@ -1,2 +1,3 @@ program FixedForm +c end end diff --git a/flang/test/Flang-Driver/Inputs/fixed-line-length-test.f b/flang/test/Flang-Driver/Inputs/fixed-line-length-test.f new file mode 100644 --- /dev/null +++ b/flang/test/Flang-Driver/Inputs/fixed-line-length-test.f @@ -0,0 +1,3 @@ +! The length of the line below is exactly 73 characters + program aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + end \ No newline at end of file diff --git a/flang/test/Flang-Driver/driver-help-hidden.f90 b/flang/test/Flang-Driver/driver-help-hidden.f90 --- a/flang/test/Flang-Driver/driver-help-hidden.f90 +++ b/flang/test/Flang-Driver/driver-help-hidden.f90 @@ -23,6 +23,8 @@ ! CHECK-NEXT: -D = Define to (or 1 if omitted) ! CHECK-NEXT: -E Only run the preprocessor ! CHECK-NEXT: -fcolor-diagnostics Enable colors in diagnostics +! CHECK-NEXT: -ffixed-line-length- +! CHECK-NEXT: Set column after which characters are ignored ! CHECK-NEXT: -fno-color-diagnostics Disable colors in diagnostics ! CHECK-NEXT: -help Display available options ! CHECK-NEXT: -I Add directory to the end of the list of include search paths diff --git a/flang/test/Flang-Driver/driver-help.f90 b/flang/test/Flang-Driver/driver-help.f90 --- a/flang/test/Flang-Driver/driver-help.f90 +++ b/flang/test/Flang-Driver/driver-help.f90 @@ -23,6 +23,8 @@ ! HELP-NEXT: -D = Define to (or 1 if omitted) ! HELP-NEXT: -E Only run the preprocessor ! HELP-NEXT: -fcolor-diagnostics Enable colors in diagnostics +! HELP-NEXT: -ffixed-line-length- +! HELP-NEXT: Set column after which characters are ignored ! HELP-NEXT: -fno-color-diagnostics Disable colors in diagnostics ! HELP-NEXT: -help Display available options ! HELP-NEXT: -I Add directory to the end of the list of include search paths @@ -39,6 +41,8 @@ ! HELP-FC1-NEXT: -D = Define to (or 1 if omitted) ! HELP-FC1-NEXT: -emit-obj Emit native object files ! HELP-FC1-NEXT: -E Only run the preprocessor +! HELP-FC1-NEXT: -ffixed-line-length- +! HELP-FC1-NEXT: Set column after which characters are ignored ! HELP-FC1-NEXT: -help Display available options ! HELP-FC1-NEXT: -I Add directory to the end of the list of include search paths ! HELP-FC1-NEXT: -o Write output to diff --git a/flang/test/Flang-Driver/fixed-free-flag.f90 b/flang/test/Flang-Driver/fixed-free-flag.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Flang-Driver/fixed-free-flag.f90 @@ -0,0 +1,25 @@ +! 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 %S/Inputs/free-form-test.f90 2>&1 | FileCheck %s --check-prefix=FREEFORM +! RUN: %flang-new -fsyntax-only -ffixed-form %S/Inputs/free-form-test.f90 %S/Inputs/fixed-form-test.f 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 %S/Inputs/free-form-test.f90 2>&1 | FileCheck %s --check-prefix=FREEFORM +! RUN: %flang-new -fc1 -fsyntax-only -ffixed-form %S/Inputs/free-form-test.f90 %S/Inputs/fixed-form-test.f 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 diff --git a/flang/test/Flang-Driver/fixed-line-length.f90 b/flang/test/Flang-Driver/fixed-line-length.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Flang-Driver/fixed-line-length.f90 @@ -0,0 +1,43 @@ +! 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-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-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 + +!------------------------------------- +! 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: programaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + +!----------------------------------------- +! EXPECTED OUTPUT WITH LENGTH LESS THAN 7 +!----------------------------------------- +! INVALIDLENGTH: invalid value '{{(-)?[0-9]+}}' + +!--------------------------------------- +! EXPECTED OUTPUT WITH UNLIMITED LENGTH +!--------------------------------------- +! The line should not be trimmed and so 73 characters (including spaces) should be read. +! UNLIMITEDLENGTH: programaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + +!-------------------------------- +! EXPECTED OUTPUT WITH LENGTH 13 +!-------------------------------- +! LENGTH13: program