Index: clang/include/clang/Driver/Options.td =================================================================== --- clang/include/clang/Driver/Options.td +++ clang/include/clang/Driver/Options.td @@ -1011,6 +1011,11 @@ def module_dependency_dir : Separate<["-"], "module-dependency-dir">, Flags<[CC1Option]>, HelpText<"Directory to dump module dependencies to">, MarshallingInfoString>; +def J : JoinedOrSeparate<["-"], "J">, Flags<[RenderJoined,FlangOption,FC1Option]>, + MetaVarName<"">, HelpText<"Put MODULE files in 'directory'">, DocBrief<[{This option specifies where to put .mod files for + compiled modules. It is also added to the list of directories to searched by + an USE statement. The default is the current directory.}]>,Group; +def module_dir : Separate<["-"], "module-dir">, Flags<[FlangOption,FC1Option]>, MetaVarName<"">, Alias; def dsym_dir : JoinedOrSeparate<["-"], "dsym-dir">, Flags<[NoXarchOption, RenderAsInput]>, HelpText<"Directory to output dSYM's (if any) to">, MetaVarName<"">; @@ -4121,7 +4126,6 @@ // Generic gfortran options. def A_DASH : Joined<["-"], "A-">, Group; -def J : JoinedOrSeparate<["-"], "J">, Flags<[RenderJoined]>, Group; def cpp : Flag<["-"], "cpp">, Group; def nocpp : Flag<["-"], "nocpp">, Group; def static_libgfortran : Flag<["-"], "static-libgfortran">, Group; Index: clang/lib/Driver/ToolChains/Flang.h =================================================================== --- clang/lib/Driver/ToolChains/Flang.h +++ clang/lib/Driver/ToolChains/Flang.h @@ -31,7 +31,13 @@ /// \param [out] CmdArgs The list of output command arguments void AddPreprocessingOptions(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const; - + /// Extract other compilation options from the driver arguments and add them to + /// the command arguments. + /// + /// \param [in] Args The list of input driver arguments + /// \param [out] CmdArgs The list of output command arguments + void AddOtherOptions(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const; public: Flang(const ToolChain &TC); ~Flang() override; Index: clang/lib/Driver/ToolChains/Flang.cpp =================================================================== --- clang/lib/Driver/ToolChains/Flang.cpp +++ clang/lib/Driver/ToolChains/Flang.cpp @@ -24,6 +24,11 @@ Args.AddAllArgs(CmdArgs, {options::OPT_D, options::OPT_U, options::OPT_I}); } +void Flang::AddOtherOptions(const ArgList &Args, + ArgStringList &CmdArgs) const { + Args.AddAllArgs(CmdArgs, options::OPT_J); +} + void Flang::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { @@ -79,6 +84,9 @@ if (types::getPreprocessedType(InputType) != types::TY_INVALID) AddPreprocessingOptions(Args, CmdArgs); + // Add other compile options + AddOtherOptions(Args, CmdArgs); + if (Output.isFilename()) { CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); Index: flang/include/flang/Frontend/CompilerInstance.h =================================================================== --- flang/include/flang/Frontend/CompilerInstance.h +++ flang/include/flang/Frontend/CompilerInstance.h @@ -30,6 +30,8 @@ std::shared_ptr parsing_; + std::shared_ptr semantics_; + /// The stream for diagnostics from Semantics llvm::raw_ostream *semaOutputStream_ = &llvm::errs(); @@ -100,6 +102,7 @@ /// } /// @name Semantic analysis /// { + Fortran::semantics::SemanticsContext &semaChecking() const { return *semantics_; } /// Replace the current stream for verbose output. void set_semaOutputStream(llvm::raw_ostream &Value); Index: flang/include/flang/Frontend/CompilerInvocation.h =================================================================== --- flang/include/flang/Frontend/CompilerInvocation.h +++ flang/include/flang/Frontend/CompilerInvocation.h @@ -11,6 +11,7 @@ #include "flang/Frontend/FrontendOptions.h" #include "flang/Frontend/PreprocessorOptions.h" #include "flang/Parser/parsing.h" +#include "flang/Semantics/semantics.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/DiagnosticOptions.h" #include "llvm/Option/ArgList.h" @@ -60,6 +61,11 @@ // of options. Fortran::parser::Options parserOpts_; + /// Semantic options + // TODO: Merge with or translate to frontendOpts_. We shouldn't need two sets + // of options. + std::string moduleDirJ_ = "."; + public: CompilerInvocation() = default; @@ -69,6 +75,9 @@ Fortran::parser::Options &fortranOpts() { return parserOpts_; } const Fortran::parser::Options &fortranOpts() const { return parserOpts_; } + std::string &moduleDir() { return moduleDirJ_; } + const std::string &moduleDir() const { return moduleDirJ_;; } + /// Create a compiler invocation from a list of input options. /// \returns true on success. /// \returns false if an error was encountered while parsing the arguments @@ -87,6 +96,9 @@ /// Set the Fortran options to user-specified values. /// These values are found in the preprocessor options. void setFortranOpts(); + + /// Set the Semantic Options + void setSemanticsOpts(Fortran::semantics::SemanticsContext &); }; } // end namespace Fortran::frontend Index: flang/lib/Frontend/CompilerInstance.cpp =================================================================== --- flang/lib/Frontend/CompilerInstance.cpp +++ flang/lib/Frontend/CompilerInstance.cpp @@ -24,7 +24,9 @@ : invocation_(new CompilerInvocation()), allSources_(new Fortran::parser::AllSources()), allCookedSources_(new Fortran::parser::AllCookedSources(*allSources_)), - parsing_(new Fortran::parser::Parsing(*allCookedSources_)) { + parsing_(new Fortran::parser::Parsing(*allCookedSources_)), + semantics_(new Fortran::semantics::SemanticsContext(*(new Fortran::common::IntrinsicTypeDefaultKinds()),*(new common::LanguageFeatureControl()), + *allCookedSources_)) { // TODO: This is a good default during development, but ultimately we should // give the user the opportunity to specify this. @@ -144,6 +146,8 @@ invoc.SetDefaultFortranOpts(); // Update the fortran options based on user-based input. invoc.setFortranOpts(); + // Set semantic options + invoc.setSemanticsOpts(this->semaChecking()); // Run the frontend action `act` for every input file. for (const FrontendInputFile &fif : frontendOpts().inputs_) { Index: flang/lib/Frontend/CompilerInvocation.cpp =================================================================== --- flang/lib/Frontend/CompilerInvocation.cpp +++ flang/lib/Frontend/CompilerInvocation.cpp @@ -183,6 +183,14 @@ opts.searchDirectoriesFromDashI.emplace_back(currentArg->getValue()); } +/// Parses all semantic related arguments and populates the variables +/// options accordingly. +static void parseSemaArgs( + std::string &moduleDir, llvm::opt::ArgList &args) { + for (const auto *currentArg : args.filtered(clang::driver::options::OPT_J)) + moduleDir = currentArg->getValue(); +} + bool CompilerInvocation::CreateFromArgs(CompilerInvocation &res, llvm::ArrayRef commandLineArgs, clang::DiagnosticsEngine &diags) { @@ -213,6 +221,8 @@ ParseFrontendArgs(res.frontendOpts(), args, diags); // Parse the preprocessor args parsePreprocessorArgs(res.preprocessorOpts(), args); + // Parse semantic args + parseSemaArgs(res.moduleDir(),args); return success; } @@ -276,6 +286,7 @@ void CompilerInvocation::setFortranOpts() { auto &fortranOptions = fortranOpts(); const auto &preprocessorOptions = preprocessorOpts(); + auto &moduleDirJ = moduleDir(); collectMacroDefinitions(preprocessorOptions, fortranOptions); @@ -283,4 +294,15 @@ fortranOptions.searchDirectories.end(), preprocessorOptions.searchDirectoriesFromDashI.begin(), preprocessorOptions.searchDirectoriesFromDashI.end()); + // Add the directory supplied through -J/-module-dir to the list of search + // directories + fortranOptions.searchDirectories.emplace_back(moduleDirJ); +} + +void CompilerInvocation::setSemanticsOpts(Fortran::semantics::SemanticsContext &semaCtxt) { + auto &fortranOptions = fortranOpts(); + auto &moduleDirJ = moduleDir(); + semaCtxt.set_moduleDirectory(moduleDirJ) + .set_searchDirectories(fortranOptions.searchDirectories); + return; } Index: flang/lib/Frontend/FrontendActions.cpp =================================================================== --- flang/lib/Frontend/FrontendActions.cpp +++ flang/lib/Frontend/FrontendActions.cpp @@ -96,11 +96,9 @@ auto &parseTree{*ci.parsing().parseTree()}; - // Prepare semantics - Fortran::semantics::SemanticsContext semanticsContext{ - defaultKinds, features, ci.allCookedSources()}; + // Prepare semantics Fortran::semantics::Semantics semantics{ - semanticsContext, parseTree, ci.parsing().cooked().AsCharBlock()}; + ci.semaChecking(), parseTree, ci.parsing().cooked().AsCharBlock()}; // Run semantic checks semantics.Perform(); Index: flang/test/Flang-Driver/driver-help-hidden.f90 =================================================================== --- flang/test/Flang-Driver/driver-help-hidden.f90 +++ flang/test/Flang-Driver/driver-help-hidden.f90 @@ -26,6 +26,7 @@ ! 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 +! CHECK-NEXT: -J Put MODULE files in 'directory' ! CHECK-NEXT: -o Write output to ! CHECK-NEXT: -test-io Run the InputOuputTest action. Use for development and testing only. ! CHECK-NEXT: -U Undefine macro Index: flang/test/Flang-Driver/driver-help.f90 =================================================================== --- flang/test/Flang-Driver/driver-help.f90 +++ flang/test/Flang-Driver/driver-help.f90 @@ -26,6 +26,7 @@ ! 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 +! HELP-NEXT: -J Put MODULE files in 'directory' ! HELP-NEXT: -o Write output to ! HELP-NEXT: -U Undefine macro ! HELP-NEXT: --version Print version information @@ -41,6 +42,7 @@ ! HELP-FC1-NEXT: -E Only run the preprocessor ! 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: -J Put MODULE files in 'directory' ! HELP-FC1-NEXT: -o Write output to ! HELP-FC1-NEXT: -U Undefine macro ! HELP-FC1-NEXT: --version Print version information Index: flang/test/Flang-Driver/include-module.f90 =================================================================== --- flang/test/Flang-Driver/include-module.f90 +++ flang/test/Flang-Driver/include-module.f90 @@ -8,12 +8,28 @@ !-------------------------- ! RUN: not %flang-new -fsyntax-only -I %S/Inputs -I %S/Inputs/module-dir %s 2>&1 | FileCheck %s --check-prefix=INCLUDED ! RUN: not %flang-new -fsyntax-only -I %S/Inputs %s 2>&1 | FileCheck %s --check-prefix=SINGLEINCLUDE +! RUN: not %flang-new -fsyntax-only -J %S/Inputs -I %S/Inputs/module-dir %s 2>&1 | FileCheck %s --check-prefix=INCLUDED +! RUN: not %flang-new -fsyntax-only -J %S/Inputs %s 2>&1 | FileCheck %s --check-prefix=SINGLEINCLUDE +! RUN: not %flang-new -fsyntax-only -module-dir %S/Inputs -I %S/Inputs/module-dir %s 2>&1 | FileCheck %s --check-prefix=INCLUDED +! RUN: not %flang-new -fsyntax-only -module-dir %S/Inputs %s 2>&1 | FileCheck %s --check-prefix=SINGLEINCLUDE +! RUN: not %flang-new -fsyntax-only -J %S/Inputs/module-dir -J %S/Inputs/ %s 2>&1 | FileCheck %s --check-prefix=SINGLEINCLUDE +! RUN: not %flang-new -fsyntax-only -J %S/Inputs/module-dir -module-dir %S/Inputs/ %s 2>&1 | FileCheck %s --check-prefix=SINGLEINCLUDE +! RUN: not %flang-new -fsyntax-only -module-dir %S/Inputs/module-dir -J%S/Inputs/ %s 2>&1 | FileCheck %s --check-prefix=SINGLEINCLUDE +! RUN: not %flang-new -fsyntax-only -module-dir %S/Inputs -I %S/Inputs/module-dir %s 2>&1 | FileCheck %s --check-prefix=INCLUDED !----------------------------------------- ! FRONTEND FLANG DRIVER (flang-new -fc1) !----------------------------------------- ! RUN: not %flang-new -fc1 -fsyntax-only -I %S/Inputs -I %S/Inputs/module-dir %s 2>&1 | FileCheck %s --check-prefix=INCLUDED ! RUN: not %flang-new -fc1 -fsyntax-only -I %S/Inputs %s 2>&1 | FileCheck %s --check-prefix=SINGLEINCLUDE +! RUN: not %flang-new -fc1 -fsyntax-only -J %S/Inputs -I %S/Inputs/module-dir %s 2>&1 | FileCheck %s --check-prefix=INCLUDED +! RUN: not %flang-new -fc1 -fsyntax-only -J %S/Inputs %s 2>&1 | FileCheck %s --check-prefix=SINGLEINCLUDE +! RUN: not %flang-new -fc1 -fsyntax-only -module-dir %S/Inputs -I %S/Inputs/module-dir %s 2>&1 | FileCheck %s --check-prefix=INCLUDED +! RUN: not %flang-new -fc1 -fsyntax-only -module-dir %S/Inputs %s 2>&1 | FileCheck %s --check-prefix=SINGLEINCLUDE +! RUN: not %flang-new -fc1 -fsyntax-only -J %S/Inputs/module-dir -J %S/Inputs/ %s 2>&1 | FileCheck %s --check-prefix=SINGLEINCLUDE +! RUN: not %flang-new -fc1 -fsyntax-only -J %S/Inputs/module-dir -module-dir %S/Inputs/ %s 2>&1 | FileCheck %s --check-prefix=SINGLEINCLUDE +! RUN: not %flang-new -fc1 -fsyntax-only -module-dir %S/Inputs/module-dir -J%S/Inputs/ %s 2>&1 | FileCheck %s --check-prefix=SINGLEINCLUDE +! RUN: not %flang-new -fc1 -fsyntax-only -module-dir %S/Inputs -I %S/Inputs/module-dir %s 2>&1 | FileCheck %s --check-prefix=INCLUDED !----------------------------------------- ! EXPECTED OUTPUT FOR MISSING MODULE FILE