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 @@ -4219,8 +4219,6 @@ // Generic gfortran options. def A_DASH : Joined<["-"], "A-">, Group; -def cpp : Flag<["-"], "cpp">, Group; -def nocpp : Flag<["-"], "nocpp">, Group; def static_libgfortran : Flag<["-"], "static-libgfortran">, Group; // "f" options with values for gfortran. @@ -4300,6 +4298,10 @@ //===----------------------------------------------------------------------===// let Flags = [FC1Option, FlangOption, FlangOnlyOption] in { +def cpp : Flag<["-"], "cpp">, Group, + HelpText<"Always add standard macro predefinitions">; +def nocpp : Flag<["-"], "nocpp">, Group, + HelpText<"Never add standard macro predefinitions">; def module_dir : Separate<["-"], "module-dir">, MetaVarName<"">, HelpText<"Put MODULE files in ">, DocBrief<[{This option specifies where to put .mod files for compiled modules. diff --git a/flang/include/flang/Frontend/CompilerInvocation.h b/flang/include/flang/Frontend/CompilerInvocation.h --- a/flang/include/flang/Frontend/CompilerInvocation.h +++ b/flang/include/flang/Frontend/CompilerInvocation.h @@ -132,6 +132,10 @@ /// Set the Semantic Options void setSemanticsOpts(Fortran::parser::AllCookedSources &); + + /// Updates this instance based on the extension of the input file (e.g. f90 + /// s F90) + void updateBasedOnExtension(const FrontendInputFile &inputFile); }; } // end namespace Fortran::frontend 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 @@ -79,6 +79,10 @@ /// \return True if the file extension should be processed as free form bool isFreeFormSuffix(llvm::StringRef suffix); +/// \param suffix The file extension +/// \return True if the file should be preprocessed +bool mustBePreprocessed(llvm::StringRef suffix); + enum class Language : uint8_t { Unknown, @@ -137,6 +141,9 @@ /// stdin this is never modified. bool isFixedForm_ = false; + /// + unsigned mustBePreprocessed_ : 1; + public: FrontendInputFile() = default; FrontendInputFile(llvm::StringRef file, InputKind kind) @@ -147,7 +154,9 @@ auto pathDotIndex{file.rfind(".")}; std::string pathSuffix{file.substr(pathDotIndex + 1)}; isFixedForm_ = isFixedFormSuffix(pathSuffix); + mustBePreprocessed_ = mustBePreprocessed(pathSuffix); } + FrontendInputFile(const llvm::MemoryBuffer *buffer, InputKind kind) : buffer_(buffer), kind_(kind) {} @@ -157,6 +166,7 @@ bool IsFile() const { return !IsBuffer(); } bool IsBuffer() const { return buffer_ != nullptr; } bool IsFixedForm() const { return isFixedForm_; } + bool MustBePreprocessed() const { return mustBePreprocessed_; } llvm::StringRef file() const { assert(IsFile()); diff --git a/flang/include/flang/Frontend/PreprocessorOptions.h b/flang/include/flang/Frontend/PreprocessorOptions.h --- a/flang/include/flang/Frontend/PreprocessorOptions.h +++ b/flang/include/flang/Frontend/PreprocessorOptions.h @@ -19,6 +19,20 @@ namespace Fortran::frontend { +/// Communicates whether to include standard macro predefinitions for the +/// preprocessor +enum class StdMacroPredefs : uint8_t { + /// Use the file extension to decide whether to include/exclude standard + /// macro predefintions + Unknown, + + /// Include standard macro predefinitions + Include, + + /// Exclude standard macro predefinitions + Exclude +}; + /// This class is used for passing the various options used /// in preprocessor initialization to the parser options. class PreprocessorOptions { @@ -32,6 +46,8 @@ // Search directories specified by the user with -fintrinsic-modules-path std::vector searchDirectoriesFromIntrModPath; + StdMacroPredefs predefs_ = StdMacroPredefs::Unknown; + public: PreprocessorOptions() {} 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 @@ -142,7 +142,6 @@ // Set some sane defaults for the frontend. invoc.SetDefaultFortranOpts(); - invoc.setDefaultPredefinitions(); // Update the fortran options based on user-based input. invoc.setFortranOpts(); // Set the encoding to read all input files in based on user input. 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 @@ -323,6 +323,14 @@ for (const auto *currentArg : args.filtered(clang::driver::options::OPT_fintrinsic_modules_path)) opts.searchDirectoriesFromIntrModPath.emplace_back(currentArg->getValue()); + + // -cpp/-nocpp + if (const auto *currentArg = args.getLastArg( + clang::driver::options::OPT_cpp, clang::driver::options::OPT_nocpp)) + opts.predefs_ = + (currentArg->getOption().matches(clang::driver::options::OPT_cpp)) + ? StdMacroPredefs::Include + : StdMacroPredefs::Exclude; } /// Parses all semantic related arguments and populates the variables diff --git a/flang/lib/Frontend/FrontendAction.cpp b/flang/lib/Frontend/FrontendAction.cpp --- a/flang/lib/Frontend/FrontendAction.cpp +++ b/flang/lib/Frontend/FrontendAction.cpp @@ -67,6 +67,22 @@ return false; } + auto &invoc = ci.invocation(); + + // Include standard macro predefinitions (use the file + // extension if the user didn't express any prefernce) + if ((invoc.preprocessorOpts().predefs_ == StdMacroPredefs::Include) || + (invoc.preprocessorOpts().predefs_ == StdMacroPredefs::Unknown && + currentInput().MustBePreprocessed())) { + invoc.setDefaultPredefinitions(); + } + + // Decide between fixed and free form (if the user didn't express any + // prefernce, use the file extension to decide) + if (invoc.frontendOpts().fortranForm_ == FortranForm::Unknown) { + invoc.fortranOpts().isFixedForm = currentInput().IsFixedForm(); + } + if (!BeginSourceFileAction(ci)) { BeginSourceFileCleanUp(*this, ci); return false; diff --git a/flang/lib/Frontend/FrontendActions.cpp b/flang/lib/Frontend/FrontendActions.cpp --- a/flang/lib/Frontend/FrontendActions.cpp +++ b/flang/lib/Frontend/FrontendActions.cpp @@ -10,6 +10,7 @@ #include "flang/Common/default-kinds.h" #include "flang/Frontend/CompilerInstance.h" #include "flang/Frontend/FrontendOptions.h" +#include "flang/Frontend/PreprocessorOptions.h" #include "flang/Lower/PFTBuilder.h" #include "flang/Parser/dump-parse-tree.h" #include "flang/Parser/parsing.h" @@ -45,21 +46,9 @@ bool PrescanAction::BeginSourceFileAction(CompilerInstance &c1) { CompilerInstance &ci = this->instance(); - std::string currentInputPath{GetCurrentFileOrBufferName()}; - Fortran::parser::Options parserOptions = ci.invocation().fortranOpts(); - if (ci.invocation().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 - // method (i.e. before processing any specific input files). However, we - // can't decide between fixed and free form based on the file extension - // earlier than this. - parserOptions.isFixedForm = currentInput().IsFixedForm(); - } // Prescan. In case of failure, report and return. ci.parsing().Prescan(currentInputPath, parserOptions); @@ -78,22 +67,9 @@ bool PrescanAndSemaAction::BeginSourceFileAction(CompilerInstance &c1) { CompilerInstance &ci = this->instance(); - std::string currentInputPath{GetCurrentFileOrBufferName()}; - Fortran::parser::Options parserOptions = ci.invocation().fortranOpts(); - if (ci.invocation().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 - // method (i.e. before processing any specific input files). However, we - // can't decide between fixed and free form based on the file extension - // earlier than this. - parserOptions.isFixedForm = currentInput().IsFixedForm(); - } - // Prescan. In case of failure, report and return. ci.parsing().Prescan(currentInputPath, parserOptions); diff --git a/flang/lib/Frontend/FrontendOptions.cpp b/flang/lib/Frontend/FrontendOptions.cpp --- a/flang/lib/Frontend/FrontendOptions.cpp +++ b/flang/lib/Frontend/FrontendOptions.cpp @@ -26,6 +26,12 @@ suffix == "f08" || suffix == "F08" || suffix == "f18" || suffix == "F18"; } +bool Fortran::frontend::mustBePreprocessed(llvm::StringRef suffix) { + return suffix == "F" || suffix == "FOR" || suffix == "FPP" || + suffix == "F90" || suffix == "F95" || suffix == "F03" || + suffix == "F08" || suffix == "F18"; +} + // TODO: This is a copy of `asFortran` from f18.cpp and is added here for // compatiblity. It doesn't really belong here, but I couldn't find a better // place. We should decide whether to add it to the Evaluate or Parse/Unparse diff --git a/flang/test/Driver/cpp_nocpp.F90 b/flang/test/Driver/cpp_nocpp.F90 new file mode 100644 --- /dev/null +++ b/flang/test/Driver/cpp_nocpp.F90 @@ -0,0 +1,18 @@ +!----------- +! RUN lines +!----------- +! RUN: %flang_fc1 -E %s 2>&1 | FileCheck %s --check-prefix=DEFINED +! RUN: %flang_fc1 -E -cpp %s 2>&1 | FileCheck %s --check-prefix=DEFINED +! RUN: %flang_fc1 -E -nocpp %s 2>&1 | FileCheck %s --check-prefix=NOT_DEFINED + +!----------------- +! EXPECTED OUTPUT +!----------------- +! DEFINED: flang = 1 +! DEFINED-NEXT: flang_major = {{[1-9][0-9]*$}} + +! NOT_DEFINED: flang = __flang__ +! NOT_DEFINED-NEXT: flang_major = __flang_major__ + +integer, parameter :: flang = __flang__ +integer, parameter :: flang_major = __flang_major__ diff --git a/flang/test/Driver/driver-help-hidden.f90 b/flang/test/Driver/driver-help-hidden.f90 --- a/flang/test/Driver/driver-help-hidden.f90 +++ b/flang/test/Driver/driver-help-hidden.f90 @@ -19,6 +19,7 @@ ! CHECK-EMPTY: ! CHECK-NEXT:OPTIONS: ! CHECK-NEXT: -### Print (but do not run) the commands to run for this compilation +! CHECK-NEXT: -cpp Always add standard macro predefinitions ! CHECK-NEXT: -c Only run preprocess, compile, and assemble steps ! CHECK-NEXT: -D = Define to (or 1 if omitted) ! CHECK-NEXT: -E Only run the preprocessor @@ -46,6 +47,7 @@ ! CHECK-NEXT: -help Display available options ! CHECK-NEXT: -I Add directory to the end of the list of include search paths ! CHECK-NEXT: -module-dir Put MODULE files in +! CHECK-NEXT: -nocpp Never add standard macro predefinitions ! CHECK-NEXT: -o Write output to ! CHECK-NEXT: -U Undefine macro ! CHECK-NEXT: --version Print version information diff --git a/flang/test/Driver/driver-help.f90 b/flang/test/Driver/driver-help.f90 --- a/flang/test/Driver/driver-help.f90 +++ b/flang/test/Driver/driver-help.f90 @@ -19,6 +19,7 @@ ! HELP-EMPTY: ! HELP-NEXT:OPTIONS: ! HELP-NEXT: -### Print (but do not run) the commands to run for this compilation +! HELP-NEXT: -cpp Always add standard macro predefinitions ! HELP-NEXT: -c Only run preprocess, compile, and assemble steps ! HELP-NEXT: -D = Define to (or 1 if omitted) ! HELP-NEXT: -E Only run the preprocessor @@ -46,6 +47,7 @@ ! HELP-NEXT: -help Display available options ! HELP-NEXT: -I Add directory to the end of the list of include search paths ! HELP-NEXT: -module-dir Put MODULE files in +! HELP-NEXT: -nocpp Never add standard macro predefinitions ! HELP-NEXT: -o Write output to ! HELP-NEXT: -U Undefine macro ! HELP-NEXT: --version Print version information @@ -57,6 +59,7 @@ ! HELP-FC1:USAGE: flang-new ! HELP-FC1-EMPTY: ! HELP-FC1-NEXT:OPTIONS: +! HELP-FC1-NEXT: -cpp Always add standard macro predefinitions ! 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 @@ -95,6 +98,7 @@ ! 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: -module-dir Put MODULE files in +! HELP-FC1-NEXT: -nocpp Never add standard macro predefinitions ! HELP-FC1-NEXT: -o Write output to ! HELP-FC1-NEXT: -test-io Run the InputOuputTest action. Use for development and testing only. ! HELP-FC1-NEXT: -U Undefine macro diff --git a/flang/test/Driver/predefined-macros-compiler-version.f90 b/flang/test/Driver/predefined-macros-compiler-version.F90 rename from flang/test/Driver/predefined-macros-compiler-version.f90 rename to flang/test/Driver/predefined-macros-compiler-version.F90