[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