#ifndef LLVM_FLANG_FRONTENDTOOL_UTILS_H
#define LLVM_FLANG_FRONTENDTOOL_UTILS_H
+#include "llvm/ADT/StringRef.h"
+
namespace Fortran::frontend {
class CompilerInstance;
/// \return - True on success.
bool ExecuteCompilerInvocation(CompilerInstance *flang);
+/// \param suffix The file extension
+/// \return True if the file extension should be processed as fixed form
+bool isFixedFormSuffix(llvm::StringRef suffix);
+
+/// \param suffix The file extension
+/// \return True if the file extension should be processed as free form
+bool isFreeFormSuffix(llvm::StringRef suffix);
+
} // end namespace Fortran::frontend
#endif // LLVM_FLANG_FRONTENDTOOL_UTILS_H
#include "flang/Frontend/FrontendAction.h"
#include "flang/Frontend/CompilerInstance.h"
#include "flang/Frontend/FrontendActions.h"
+#include "flang/FrontendTool/Utils.h"
#include "llvm/Support/Errc.h"
using namespace Fortran::frontend;
Fortran::parser::Options parserOptions =
this->instance().invocation().fortranOpts();
+ // Set the fixed form flag based on the file extension
+ auto pathDotIndex{currentInputPath.rfind(".")};
+ if (pathDotIndex != std::string::npos) {
+ std::string pathSuffix{currentInputPath.substr(pathDotIndex + 1)};
+ parserOptions.isFixedForm = isFixedFormSuffix(pathSuffix);
+ }
// Prescan. In case of failure, report and return.
ci.parsing().Prescan(currentInputPath, parserOptions);
//===----------------------------------------------------------------------===//
#include "flang/Frontend/FrontendOptions.h"
-#include "llvm/ADT/StringSwitch.h"
+#include "flang/FrontendTool/Utils.h"
using namespace Fortran::frontend;
InputKind FrontendOptions::GetInputKindForExtension(llvm::StringRef extension) {
- return llvm::StringSwitch<InputKind>(extension)
- // TODO: Should match the list in flang/test/lit.cfg.py
- // FIXME: Currently this API allows at most 9 items per case.
- .Cases("f", "F", "f77", "f90", "F90", "f95", "F95", "ff95", "f18", "F18",
- Language::Fortran)
- .Default(Language::Unknown);
+ if (isFixedFormSuffix(extension) || isFreeFormSuffix(extension)) {
+ return Language::Fortran;
+ }
+ return Language::Unknown;
}
return success;
}
+bool isFixedFormSuffix(llvm::StringRef suffix) {
+ // Note: Keep this list in-sync with flang/test/lit.cfg.py
+ return suffix == "f" || suffix == "F" || suffix == "ff" || suffix == "for" ||
+ suffix == "FOR" || suffix == "fpp" || suffix == "FPP";
+}
+
+bool isFreeFormSuffix(llvm::StringRef suffix) {
+ // Note: Keep this list in-sync with flang/test/lit.cfg.py
+ // TODO: Add Cuda Fortan files (i.e. `*.cuf` and `*.CUF`).
+ return suffix == "f77" || suffix == "f90" || suffix == "F90" ||
+ suffix == "ff90" || suffix == "f95" || suffix == "F95" ||
+ suffix == "ff95" || suffix == "f03" || suffix == "F03" ||
+ suffix == "f08" || suffix == "F08" || suffix == "f18" || suffix == "F18";
+}
+
} // namespace Fortran::frontend
--- /dev/null
+ program FixedForm
+ end
--- /dev/null
+program FreeForm
+end
--- /dev/null
+! Ensure the driver correctly switches between fixed and free form based on the file extension.
+! This test exploits the fact that the preprocessor treats white-spaces differently for free
+! and fixed form input files.
+
+! REQUIRES: new-flang-driver
+
+!--------------------------
+! FLANG DRIVER (flang-new)
+!--------------------------
+! RUN: %flang-new -E %S/Inputs/free-form-test.f90 2>&1 | FileCheck %s --check-prefix=FREEFORM
+! RUN: %flang-new -E %S/Inputs/fixed-form-test.f 2>&1 | FileCheck %s --check-prefix=FIXEDFORM
+! RUN: %flang-new -E %S/Inputs/free-form-test.f90 %S/Inputs/fixed-form-test.f 2>&1 | FileCheck %s --check-prefix=MULTIPLEFORMS
+
+!-----------------------------------------
+! FRONTEND FLANG DRIVER (flang-new -fc1)
+!-----------------------------------------
+! RUN: %flang-new -fc1 -E %S/Inputs/free-form-test.f90 2>&1 | FileCheck %s --check-prefix=FREEFORM
+! RUN: %flang-new -fc1 -E %S/Inputs/fixed-form-test.f 2>&1 | FileCheck %s --check-prefix=FIXEDFORM
+! RUN: %flang-new -fc1 -E %S/Inputs/free-form-test.f90 %S/Inputs/fixed-form-test.f 2>&1 | FileCheck %s --check-prefix=MULTIPLEFORMS
+
+!-------------------------------------
+! EXPECTED OUTPUT FOR A FREE FORM FILE
+!-------------------------------------
+! FREEFORM:program freeform
+! FREEFORM-NOT:programfixedform
+
+!---------------------------------------
+! EXPECTED OUTPUT FOR A FIXED FORM FILE
+!---------------------------------------
+! FIXEDFORM:programfixedform
+! FIXEDFORM-NOT:program freeform
+
+!------------------------------------------------
+! EXPECTED OUTPUT FOR 2 FILES OF DIFFERENT FORMS
+!------------------------------------------------
+! MULTIPLEFORMS:program freeform
+! MULTIPLEFORMS-NOT:programfixedform
+! MULTIPLEFORMS-NEXT:end
+! MULTIPLEFORMS-NEXT:programfixedform
+! MULTIPLEFORMS-NOT:program freeform
# suffixes: A list of file extensions to treat as test files.
config.suffixes = ['.c', '.cpp', '.f', '.F', '.ff', '.FOR', '.for', '.f77', '.f90', '.F90',
- '.ff90', '.f95', '.F95', '.ff95', '.fpp', '.FPP', '.cuf',
- '.CUF', '.f18', '.F18', '.fir']
+ '.ff90', '.f95', '.F95', '.ff95', '.fpp', '.FPP', '.cuf'
+ '.CUF', '.f18', '.F18', '.fir', '.f03', '.F03', '.f08', '.F08']
config.substitutions.append(('%PATH%', config.environment['PATH']))
// Generate a unique test file name.
const testing::TestInfo *const test_info =
testing::UnitTest::GetInstance()->current_test_info();
- inputFileName_ = std::string(test_info->name()) + "_test-file.f";
+ inputFileName_ = std::string(test_info->name()) + "_test-file.f90";
// Create the input file stream. Note that this stream is populated
// separately in every test (i.e. the input is test specific).