[llvm-branch-commits] [clang] 7809fa2 - [flang][driver] Add support for `-D`, `-U`

Andrzej Warzynski via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Wed Jan 6 08:22:10 PST 2021


Author: Faris Rehman
Date: 2021-01-06T16:17:13Z
New Revision: 7809fa20400000fd40b4a4b56696c7fbcd0f0fa9

URL: https://github.com/llvm/llvm-project/commit/7809fa20400000fd40b4a4b56696c7fbcd0f0fa9
DIFF: https://github.com/llvm/llvm-project/commit/7809fa20400000fd40b4a4b56696c7fbcd0f0fa9.diff

LOG: [flang][driver] Add support for `-D`, `-U`

Add support for options -D and -U in the new Flang driver.

Summary of changes:
  - Create PreprocessorOptions, to be used by the driver then translated
    into Fortran::parser::Options
  - Create CompilerInvocation::setFortranOpts to pass preprocessor
    options into the parser options
  - Add a dedicated method, Flang::AddPreprocessingOptions, to extract
    preprocessing options from the driver arguments into the preprocessor
    command arguments

Macros specified like -DName will default to definition 1.

When defining macros, the new driver will drop anything after an
end-of-line character. This is consistent with gfortran and clang, but
different to what currently f18 does. However, flang (which is a bash
wrapper for f18), also drops everything after an end-of-line character.
So gfortran-like behaviour felt like the natural choice. Test is added
to demonstrate this behaviour.

Reviewed By: awarzynski

Differential Revision: https://reviews.llvm.org/D93401

Added: 
    flang/include/flang/Frontend/PreprocessorOptions.h
    flang/test/Flang-Driver/macro_def_undef.f90
    flang/test/Flang-Driver/macro_multiline.f90

Modified: 
    clang/include/clang/Driver/Options.td
    clang/lib/Driver/ToolChains/Flang.cpp
    clang/lib/Driver/ToolChains/Flang.h
    flang/include/flang/Frontend/CompilerInstance.h
    flang/include/flang/Frontend/CompilerInvocation.h
    flang/lib/Frontend/CompilerInstance.cpp
    flang/lib/Frontend/CompilerInvocation.cpp
    flang/test/Flang-Driver/driver-help-hidden.f90
    flang/test/Flang-Driver/driver-help.f90

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index 3c2a9f307c65..428c14a7d9bb 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -631,7 +631,7 @@ def C : Flag<["-"], "C">, Flags<[CC1Option]>, Group<Preprocessor_Group>,
     HelpText<"Include comments in preprocessed output">,
     MarshallingInfoFlag<"PreprocessorOutputOpts.ShowComments">;
 def D : JoinedOrSeparate<["-"], "D">, Group<Preprocessor_Group>,
-    Flags<[CC1Option]>, MetaVarName<"<macro>=<value>">,
+    Flags<[CC1Option, FlangOption, FC1Option]>, MetaVarName<"<macro>=<value>">,
     HelpText<"Define <macro> to <value> (or 1 if <value> omitted)">;
 def E : Flag<["-"], "E">, Flags<[NoXarchOption,CC1Option, FlangOption, FC1Option]>, Group<Action_Group>,
     HelpText<"Only run the preprocessor">;
@@ -730,7 +730,7 @@ def Ttext : JoinedOrSeparate<["-"], "Ttext">, Group<T_Group>,
 def T : JoinedOrSeparate<["-"], "T">, Group<T_Group>,
   MetaVarName<"<script>">, HelpText<"Specify <script> as linker script">;
 def U : JoinedOrSeparate<["-"], "U">, Group<Preprocessor_Group>,
-  Flags<[CC1Option]>, MetaVarName<"<macro>">, HelpText<"Undefine macro <macro>">;
+  Flags<[CC1Option, FlangOption, FC1Option]>, MetaVarName<"<macro>">, HelpText<"Undefine macro <macro>">;
 def V : JoinedOrSeparate<["-"], "V">, Flags<[NoXarchOption, Unsupported]>;
 def Wa_COMMA : CommaJoined<["-"], "Wa,">,
   HelpText<"Pass the comma separated arguments in <arg> to the assembler">,

diff  --git a/clang/lib/Driver/ToolChains/Flang.cpp b/clang/lib/Driver/ToolChains/Flang.cpp
index d7dee9594e45..69f0841bb0c5 100644
--- a/clang/lib/Driver/ToolChains/Flang.cpp
+++ b/clang/lib/Driver/ToolChains/Flang.cpp
@@ -19,6 +19,11 @@ using namespace clang::driver::tools;
 using namespace clang;
 using namespace llvm::opt;
 
+void Flang::AddPreprocessingOptions(const ArgList &Args,
+                                    ArgStringList &CmdArgs) const {
+  Args.AddAllArgs(CmdArgs, {options::OPT_D, options::OPT_U});
+}
+
 void Flang::ConstructJob(Compilation &C, const JobAction &JA,
                          const InputInfo &Output, const InputInfoList &Inputs,
                          const ArgList &Args, const char *LinkingOutput) const {
@@ -63,6 +68,14 @@ void Flang::ConstructJob(Compilation &C, const JobAction &JA,
     assert(false && "Unexpected action class for Flang tool.");
   }
 
+  const InputInfo &Input = Inputs[0];
+  types::ID InputType = Input.getType();
+
+  // Add preprocessing options like -I, -D, etc. if we are using the
+  // preprocessor (i.e. skip when dealing with e.g. binary files).
+  if (types::getPreprocessedType(InputType) != types::TY_INVALID)
+    AddPreprocessingOptions(Args, CmdArgs);
+
   if (Output.isFilename()) {
     CmdArgs.push_back("-o");
     CmdArgs.push_back(Output.getFilename());
@@ -70,7 +83,6 @@ void Flang::ConstructJob(Compilation &C, const JobAction &JA,
     assert(Output.isNothing() && "Invalid output.");
   }
 
-  const InputInfo &Input = Inputs[0];
   assert(Input.isFilename() && "Invalid input.");
   CmdArgs.push_back(Input.getFilename());
 

diff  --git a/clang/lib/Driver/ToolChains/Flang.h b/clang/lib/Driver/ToolChains/Flang.h
index 19e3a8c28f7e..83b79505e0a9 100644
--- a/clang/lib/Driver/ToolChains/Flang.h
+++ b/clang/lib/Driver/ToolChains/Flang.h
@@ -23,6 +23,15 @@ namespace tools {
 
 /// Flang compiler tool.
 class LLVM_LIBRARY_VISIBILITY Flang : public Tool {
+private:
+  /// Extract preprocessing options from the driver arguments and add them to
+  /// the preprocessor command arguments.
+  ///
+  /// \param [in] Args The list of input driver arguments
+  /// \param [out] CmdArgs The list of output command arguments
+  void AddPreprocessingOptions(const llvm::opt::ArgList &Args,
+                               llvm::opt::ArgStringList &CmdArgs) const;
+
 public:
   Flang(const ToolChain &TC);
   ~Flang() override;

diff  --git a/flang/include/flang/Frontend/CompilerInstance.h b/flang/include/flang/Frontend/CompilerInstance.h
index b00b5cd4479a..79a05c0ddbbe 100644
--- a/flang/include/flang/Frontend/CompilerInstance.h
+++ b/flang/include/flang/Frontend/CompilerInstance.h
@@ -10,6 +10,7 @@
 
 #include "flang/Frontend/CompilerInvocation.h"
 #include "flang/Frontend/FrontendAction.h"
+#include "flang/Frontend/PreprocessorOptions.h"
 #include "flang/Parser/parsing.h"
 #include "flang/Parser/provenance.h"
 #include "flang/Semantics/semantics.h"
@@ -135,6 +136,13 @@ class CompilerInstance {
     return invocation_->frontendOpts();
   }
 
+  PreprocessorOptions &preprocessorOpts() {
+    return invocation_->preprocessorOpts();
+  }
+  const PreprocessorOptions &preprocessorOpts() const {
+    return invocation_->preprocessorOpts();
+  }
+
   /// }
   /// @name Diagnostics Engine
   /// {

diff  --git a/flang/include/flang/Frontend/CompilerInvocation.h b/flang/include/flang/Frontend/CompilerInvocation.h
index 12915c7c1d9c..5136de54e06b 100644
--- a/flang/include/flang/Frontend/CompilerInvocation.h
+++ b/flang/include/flang/Frontend/CompilerInvocation.h
@@ -9,10 +9,12 @@
 #define LLVM_FLANG_FRONTEND_COMPILERINVOCATION_H
 
 #include "flang/Frontend/FrontendOptions.h"
+#include "flang/Frontend/PreprocessorOptions.h"
 #include "flang/Parser/parsing.h"
 #include "clang/Basic/Diagnostic.h"
 #include "clang/Basic/DiagnosticOptions.h"
 #include "llvm/Option/ArgList.h"
+#include <memory>
 
 namespace Fortran::frontend {
 
@@ -27,6 +29,8 @@ class CompilerInvocationBase {
 public:
   /// Options controlling the diagnostic engine.
   llvm::IntrusiveRefCntPtr<clang::DiagnosticOptions> diagnosticOpts_;
+  /// Options for the preprocessor.
+  std::shared_ptr<Fortran::frontend::PreprocessorOptions> preprocessorOpts_;
 
   CompilerInvocationBase();
   CompilerInvocationBase(const CompilerInvocationBase &x);
@@ -38,6 +42,11 @@ class CompilerInvocationBase {
   const clang::DiagnosticOptions &GetDiagnosticOpts() const {
     return *diagnosticOpts_.get();
   }
+
+  PreprocessorOptions &preprocessorOpts() { return *preprocessorOpts_; }
+  const PreprocessorOptions &preprocessorOpts() const {
+    return *preprocessorOpts_;
+  }
 };
 
 class CompilerInvocation : public CompilerInvocationBase {
@@ -74,6 +83,10 @@ class CompilerInvocation : public CompilerInvocationBase {
   // need to extend frontendOpts_ first. Next, we need to add the corresponding
   // compiler driver options in libclangDriver.
   void SetDefaultFortranOpts();
+
+  /// Set the Fortran options to user-specified values.
+  /// These values are found in the preprocessor options.
+  void setFortranOpts();
 };
 
 } // end namespace Fortran::frontend

diff  --git a/flang/include/flang/Frontend/PreprocessorOptions.h b/flang/include/flang/Frontend/PreprocessorOptions.h
new file mode 100644
index 000000000000..d182969eb78b
--- /dev/null
+++ b/flang/include/flang/Frontend/PreprocessorOptions.h
@@ -0,0 +1,42 @@
+//===- PreprocessorOptions.h ------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file contains the declaration of the PreprocessorOptions class, which
+/// is the class for all preprocessor options.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_FLANG_PREPROCESSOROPTIONS_H
+#define LLVM_FLANG_PREPROCESSOROPTIONS_H
+
+#include "llvm/ADT/StringRef.h"
+
+namespace Fortran::frontend {
+
+/// This class is used for passing the various options used
+/// in preprocessor initialization to the parser options.
+class PreprocessorOptions {
+public:
+  std::vector<std::pair<std::string, /*isUndef*/ bool>> macros;
+
+public:
+  PreprocessorOptions() {}
+
+  void addMacroDef(llvm::StringRef name) {
+    macros.emplace_back(std::string(name), false);
+  }
+
+  void addMacroUndef(llvm::StringRef name) {
+    macros.emplace_back(std::string(name), true);
+  }
+};
+
+} // namespace Fortran::frontend
+
+#endif // LLVM_FLANG_PREPROCESSOROPTIONS_H
\ No newline at end of file

diff  --git a/flang/lib/Frontend/CompilerInstance.cpp b/flang/lib/Frontend/CompilerInstance.cpp
index f473bcd19546..589f8204c60f 100644
--- a/flang/lib/Frontend/CompilerInstance.cpp
+++ b/flang/lib/Frontend/CompilerInstance.cpp
@@ -142,6 +142,8 @@ bool CompilerInstance::ExecuteAction(FrontendAction &act) {
   // TODO: Instead of defaults we should be setting these options based on the
   // user input.
   this->invocation().SetDefaultFortranOpts();
+  // Set the fortran options to user-based input.
+  this->invocation().setFortranOpts();
 
   // Connect Input to a CompileInstance
   for (const FrontendInputFile &fif : frontendOpts().inputs_) {

diff  --git a/flang/lib/Frontend/CompilerInvocation.cpp b/flang/lib/Frontend/CompilerInvocation.cpp
index db3ae74128cd..df7fe44feb9c 100644
--- a/flang/lib/Frontend/CompilerInvocation.cpp
+++ b/flang/lib/Frontend/CompilerInvocation.cpp
@@ -7,6 +7,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "flang/Frontend/CompilerInvocation.h"
+#include "flang/Frontend/PreprocessorOptions.h"
 #include "clang/Basic/AllDiagnostics.h"
 #include "clang/Basic/DiagnosticDriver.h"
 #include "clang/Basic/DiagnosticOptions.h"
@@ -26,10 +27,12 @@ using namespace Fortran::frontend;
 // Initialization.
 //===----------------------------------------------------------------------===//
 CompilerInvocationBase::CompilerInvocationBase()
-    : diagnosticOpts_(new clang::DiagnosticOptions()) {}
+    : diagnosticOpts_(new clang::DiagnosticOptions()),
+      preprocessorOpts_(new PreprocessorOptions()) {}
 
 CompilerInvocationBase::CompilerInvocationBase(const CompilerInvocationBase &x)
-    : diagnosticOpts_(new clang::DiagnosticOptions(x.GetDiagnosticOpts())) {}
+    : diagnosticOpts_(new clang::DiagnosticOptions(x.GetDiagnosticOpts())),
+      preprocessorOpts_(new PreprocessorOptions(x.preprocessorOpts())) {}
 
 CompilerInvocationBase::~CompilerInvocationBase() = default;
 
@@ -155,6 +158,24 @@ static InputKind ParseFrontendArgs(FrontendOptions &opts,
   return dashX;
 }
 
+/// Parses all preprocessor input arguments and populates the preprocessor
+/// options accordingly.
+///
+/// \param [in] opts The preprocessor options instance
+/// \param [out] args The list of input arguments
+static void parsePreprocessorArgs(
+    Fortran::frontend::PreprocessorOptions &opts, llvm::opt::ArgList &args) {
+  // Add macros from the command line.
+  for (const auto *currentArg : args.filtered(
+           clang::driver::options::OPT_D, clang::driver::options::OPT_U)) {
+    if (currentArg->getOption().matches(clang::driver::options::OPT_D)) {
+      opts.addMacroDef(currentArg->getValue());
+    } else {
+      opts.addMacroUndef(currentArg->getValue());
+    }
+  }
+}
+
 bool CompilerInvocation::CreateFromArgs(CompilerInvocation &res,
     llvm::ArrayRef<const char *> commandLineArgs,
     clang::DiagnosticsEngine &diags) {
@@ -183,10 +204,47 @@ bool CompilerInvocation::CreateFromArgs(CompilerInvocation &res,
 
   // Parse the frontend args
   ParseFrontendArgs(res.frontendOpts(), args, diags);
+  // Parse the preprocessor args
+  parsePreprocessorArgs(res.preprocessorOpts(), args);
 
   return success;
 }
 
+/// Collect the macro definitions provided by the given preprocessor
+/// options into the parser options.
+///
+/// \param [in] ppOpts The preprocessor options
+/// \param [out] opts The fortran options
+static void collectMacroDefinitions(
+    const PreprocessorOptions &ppOpts, Fortran::parser::Options &opts) {
+  for (unsigned i = 0, n = ppOpts.macros.size(); i != n; ++i) {
+    llvm::StringRef macro = ppOpts.macros[i].first;
+    bool isUndef = ppOpts.macros[i].second;
+
+    std::pair<llvm::StringRef, llvm::StringRef> macroPair = macro.split('=');
+    llvm::StringRef macroName = macroPair.first;
+    llvm::StringRef macroBody = macroPair.second;
+
+    // For an #undef'd macro, we only care about the name.
+    if (isUndef) {
+      opts.predefinitions.emplace_back(
+          macroName.str(), std::optional<std::string>{});
+      continue;
+    }
+
+    // For a #define'd macro, figure out the actual definition.
+    if (macroName.size() == macro.size())
+      macroBody = "1";
+    else {
+      // Note: GCC drops anything following an end-of-line character.
+      llvm::StringRef::size_type End = macroBody.find_first_of("\n\r");
+      macroBody = macroBody.substr(0, End);
+    }
+    opts.predefinitions.emplace_back(
+        macroName, std::optional<std::string>(macroBody.str()));
+  }
+}
+
 void CompilerInvocation::SetDefaultFortranOpts() {
   auto &fortranOptions = fortranOpts();
 
@@ -195,3 +253,10 @@ void CompilerInvocation::SetDefaultFortranOpts() {
   fortranOptions.searchDirectories = searchDirectories;
   fortranOptions.isFixedForm = false;
 }
+
+void CompilerInvocation::setFortranOpts() {
+  auto &fortranOptions = fortranOpts();
+  const auto &preprocessorOptions = preprocessorOpts();
+
+  collectMacroDefinitions(preprocessorOptions, fortranOptions);
+}

diff  --git a/flang/test/Flang-Driver/driver-help-hidden.f90 b/flang/test/Flang-Driver/driver-help-hidden.f90
index 3143cfd3d715..2b0e3162eb6f 100644
--- a/flang/test/Flang-Driver/driver-help-hidden.f90
+++ b/flang/test/Flang-Driver/driver-help-hidden.f90
@@ -19,12 +19,14 @@
 ! CHECK-EMPTY:
 ! CHECK-NEXT:OPTIONS:
 ! CHECK-NEXT: -###      Print (but do not run) the commands to run for this compilation
+! 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: -fno-color-diagnostics Disable colors in diagnostics
 ! CHECK-NEXT: -help     Display available options
 ! CHECK-NEXT: -o <file> Write output to <file>
 ! CHECK-NEXT: -test-io  Run the InputOuputTest action. Use for development and testing only.
+! CHECK-NEXT: -U <macro>             Undefine macro <macro>
 ! CHECK-NEXT: --version Print version information
 
 !-------------------------------------------------------------

diff  --git a/flang/test/Flang-Driver/driver-help.f90 b/flang/test/Flang-Driver/driver-help.f90
index 58fa8fc79aca..69319253034c 100644
--- a/flang/test/Flang-Driver/driver-help.f90
+++ b/flang/test/Flang-Driver/driver-help.f90
@@ -19,11 +19,13 @@
 ! HELP-EMPTY:
 ! HELP-NEXT:OPTIONS:
 ! HELP-NEXT: -###                   Print (but do not run) the commands to run for this compilation
+! 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: -fno-color-diagnostics Disable colors in diagnostics
 ! HELP-NEXT: -help                  Display available options
 ! HELP-NEXT: -o <file>              Write output to <file>
+! HELP-NEXT: -U <macro>             Undefine macro <macro>
 ! HELP-NEXT: --version              Print version information
 
 !-------------------------------------------------------------
@@ -32,10 +34,12 @@
 ! HELP-FC1:USAGE: flang-new
 ! HELP-FC1-EMPTY:
 ! HELP-FC1-NEXT:OPTIONS:
-! HELP-FC1-NEXT: -E        Only run the preprocessor
-! HELP-FC1-NEXT: -help     Display available options
-! HELP-FC1-NEXT: -o <file> Write output to <file>
-! HELP-FC1-NEXT: --version Print version information
+! HELP-FC1-NEXT: -D <macro>=<value>     Define <macro> to <value> (or 1 if <value> omitted)
+! HELP-FC1-NEXT: -E                     Only run the preprocessor
+! HELP-FC1-NEXT: -help                  Display available options
+! HELP-FC1-NEXT: -o <file>              Write output to <file>
+! HELP-FC1-NEXT: -U <macro>             Undefine macro <macro>
+! HELP-FC1-NEXT: --version              Print version information
 
 !---------------
 ! EXPECTED ERROR

diff  --git a/flang/test/Flang-Driver/macro_def_undef.f90 b/flang/test/Flang-Driver/macro_def_undef.f90
new file mode 100644
index 000000000000..694f7676eeb1
--- /dev/null
+++ b/flang/test/Flang-Driver/macro_def_undef.f90
@@ -0,0 +1,38 @@
+! Ensure arguments -D and -U work as expected.
+
+! REQUIRES: new-flang-driver
+
+!--------------------------
+! FLANG DRIVER (flang-new)
+!--------------------------
+! RUN: %flang-new -E %s  2>&1 | FileCheck %s --check-prefix=UNDEFINED
+! RUN: %flang-new -E -DX=A %s  2>&1 | FileCheck %s --check-prefix=DEFINED
+! RUN: %flang-new -E -DX=A -UX %s  2>&1 | FileCheck %s --check-prefix=UNDEFINED
+
+!-----------------------------------------
+! FRONTEND FLANG DRIVER (flang-new -fc1)
+!-----------------------------------------
+! RUN: %flang-new -fc1 -E %s  2>&1 | FileCheck %s --check-prefix=UNDEFINED
+! RUN: %flang-new -fc1 -E -DX=A %s  2>&1 | FileCheck %s --check-prefix=DEFINED
+! RUN: %flang-new -fc1 -E -DX -UX %s  2>&1 | FileCheck %s --check-prefix=UNDEFINED
+
+!--------------------------------------------
+! EXPECTED OUTPUT FOR AN UNDEFINED MACRO
+!--------------------------------------------
+! UNDEFINED:program b
+! UNDEFINED-NOT:program x
+! UNDEFINED-NEXT:end
+
+!--------------------------------------------
+! EXPECTED OUTPUT FOR MACRO 'X' DEFINED AS A
+!--------------------------------------------
+! DEFINED:program a
+! DEFINED-NOT:program b
+! DEFINED-NEXT:end
+
+#ifdef X
+program X
+#else
+program B
+#endif
+end
\ No newline at end of file

diff  --git a/flang/test/Flang-Driver/macro_multiline.f90 b/flang/test/Flang-Driver/macro_multiline.f90
new file mode 100644
index 000000000000..c02996eed5bf
--- /dev/null
+++ b/flang/test/Flang-Driver/macro_multiline.f90
@@ -0,0 +1,22 @@
+! Ensure the end-of-line character and anything that follows after in a macro definition (-D) is ignored.
+
+! REQUIRES: new-flang-driver
+
+!--------------------------
+! FLANG DRIVER (flang-new)
+!--------------------------
+! RUN: printf -- "-DX=A\\\\\nTHIS_SHOULD_NOT_EXIST_IN_THE_OUTPUT\n" | xargs %flang-new -E %s  2>&1 | FileCheck --strict-whitespace --match-full-lines %s
+
+!-----------------------------------------
+! FRONTEND FLANG DRIVER (flang-new -fc1)
+!-----------------------------------------
+! RUN: printf -- "-DX=A\\\\\nTHIS_SHOULD_NOT_EXIST_IN_THE_OUTPUT\n" | xargs %flang-new -fc1 -E %s  2>&1 | FileCheck --strict-whitespace --match-full-lines %s
+
+!-------------------------------
+! EXPECTED OUTPUT FOR MACRO 'X'
+!-------------------------------
+! CHECK:start a end
+! CHECK-NOT:THIS_SHOULD_NOT_EXIST_IN_THE_OUTPUT
+! CHECK-NOT:this_should_not_exist_in_the_output
+
+START X END
\ No newline at end of file


        


More information about the llvm-branch-commits mailing list