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 @@ -870,7 +870,8 @@ Flags<[CC1Option]>, MetaVarName<"">, Values<".,latest">, HelpText<"Attempt to match the ABI of Clang ">; def fclasspath_EQ : Joined<["-"], "fclasspath=">, Group; -defm color_diagnostics : OptInFFlag<"color-diagnostics", "Enable", "Disable", " colors in diagnostics", [CoreOption]>; +defm color_diagnostics : OptInFFlag<"color-diagnostics", "Enable", "Disable", " colors in diagnostics", + [CoreOption, FlangOption]>; def fdiagnostics_color : Flag<["-"], "fdiagnostics-color">, Group, Flags<[CoreOption, DriverOption]>; def fdiagnostics_color_EQ : Joined<["-"], "fdiagnostics-color=">, Group; 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 @@ -11,8 +11,18 @@ #include "flang/Frontend/FrontendOptions.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/DiagnosticOptions.h" +#include "llvm/Option/ArgList.h" namespace Fortran::frontend { + +/// Fill out Opts based on the options given in Args. +/// +/// When errors are encountered, return false and, if Diags is non-null, +/// report the error(s). +bool ParseDiagnosticArgs(clang::DiagnosticOptions &opts, + llvm::opt::ArgList &args, clang::DiagnosticsEngine *diags = nullptr, + bool defaultDiagColor = true); + class CompilerInvocationBase { public: /// Options controlling the diagnostic engine.$ diff --git a/flang/include/flang/Frontend/TextDiagnostic.h b/flang/include/flang/Frontend/TextDiagnostic.h new file mode 100644 --- /dev/null +++ b/flang/include/flang/Frontend/TextDiagnostic.h @@ -0,0 +1,70 @@ +//===--- TextDiagnostic.h - Text Diagnostic Pretty-Printing -----*- 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 +// +//===----------------------------------------------------------------------===// +// +// A utility class that provides support for textual pretty-printing of +// diagnostics. Based on clang::TextDiagnostic (this is a trimmed version). +// +// TODO: If expanding, consider sharing the implementation with Clang. +//===----------------------------------------------------------------------===// + +#ifndef LLVM_FLANG_FRONTEND_TEXTDIAGNOSTIC_H +#define LLVM_FLANG_FRONTEND_TEXTDIAGNOSTIC_H + +#include "clang/Basic/Diagnostic.h" +#include "llvm/ADT/IntrusiveRefCntPtr.h" + +namespace Fortran::frontend { + +/// Class to encapsulate the logic for formatting and printing a textual +/// diagnostic message. +/// +/// The purpose of this class is to isolate the implementation of printing +/// beautiful text diagnostics from any particular interfaces. Currently only +/// simple diagnostics that lack source location information are supported (e.g. +/// Flang driver errors). +/// +/// In the future we can extend this class (akin to Clang) to support more +/// complex diagnostics that would include macro backtraces, caret diagnostics, +/// FixIt Hints and code snippets. +/// +class TextDiagnostic { +public: + TextDiagnostic(); + + ~TextDiagnostic(); + + /// Print the diagnostic level to a llvm::raw_ostream. + /// + /// This is a static helper that handles colorizing the level and formatting + /// it into an arbitrary output stream. + /// + /// \param os Where the message is printed + /// \param level The diagnostic level (e.g. error or warning) + /// \param showColors Enable colorizing of the message. + static void PrintDiagnosticLevel(llvm::raw_ostream &os, + clang::DiagnosticsEngine::Level level, bool showColors); + + /// Pretty-print a diagnostic message to a llvm::raw_ostream. + /// + /// This is a static helper to handle the colorizing and rendering diagnostic + /// message to a particular ostream. In the future we can + /// extend it to support e.g. line wrapping. It is + /// publicly visible as at this stage we don't require any state data to + /// print a diagnostic. + /// + /// \param os Where the message is printed + /// \param isSupplemental true if this is a continuation note diagnostic + /// \param message The text actually printed + /// \param showColors Enable colorizing of the message. + static void PrintDiagnosticMessage(llvm::raw_ostream &os, bool isSupplemental, + llvm::StringRef message, bool showColors); +}; + +} // namespace Fortran::frontend + +#endif diff --git a/flang/include/flang/Frontend/TextDiagnosticBuffer.h b/flang/include/flang/Frontend/TextDiagnosticBuffer.h new file mode 100644 --- /dev/null +++ b/flang/include/flang/Frontend/TextDiagnosticBuffer.h @@ -0,0 +1,52 @@ +//===- TextDiagnosticBuffer.h - Buffer Text Diagnostics ---------*- 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 +// +//===----------------------------------------------------------------------===// +// +// This is a concrete diagnostic client. The diagnostics are buffered rather +// than printed. In order to print them, use the FlushDiagnostics method. +// Pretty-printing is not supported. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_FLANG_FRONTEND_TEXTDIAGNOSTICBUFFER_H +#define LLVM_FLANG_FRONTEND_TEXTDIAGNOSTICBUFFER_H + +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/SourceLocation.h" +#include +#include +#include +#include + +namespace Fortran::frontend { + +class TextDiagnosticBuffer : public clang::DiagnosticConsumer { +public: + using DiagList = std::vector>; + using DiagnosticsLevelAndIndexPairs = + std::vector>; + +private: + DiagList errors_, warnings_, remarks_, notes_; + + /// All diagnostics in the order in which they were generated. That order + /// likely doesn't correspond to user input order, but at least it keeps + /// notes in the right places. Each pair is a diagnostic level and an index + /// into the corresponding DiagList above. + DiagnosticsLevelAndIndexPairs all_; + +public: + void HandleDiagnostic(clang::DiagnosticsEngine::Level diagLevel, + const clang::Diagnostic &info) override; + + /// Flush the buffered diagnostics to a given diagnostic engine. + void FlushDiagnostics(clang::DiagnosticsEngine &diags) const; +}; + +} // namespace Fortran::frontend + +#endif // LLVM_CLANG_FRONTEND_TEXTDIAGNOSTICBUFFER_H diff --git a/flang/include/flang/Frontend/TextDiagnosticPrinter.h b/flang/include/flang/Frontend/TextDiagnosticPrinter.h new file mode 100644 --- /dev/null +++ b/flang/include/flang/Frontend/TextDiagnosticPrinter.h @@ -0,0 +1,55 @@ +//===--- TextDiagnosticPrinter.h - Text Diagnostic Client -------*- 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 +// +//===----------------------------------------------------------------------===// +// +// This is a concrete diagnostic client. In terminals that support it, the +// diagnostics are pretty-printed (colors + bold). The printing/flushing +// happens in HandleDiagnostics (usually called at the point when the +// diagnostic is generated). +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_FLANG_FRONTEND_TEXTDIAGNOSTICPRINTER_H +#define LLVM_FLANG_FRONTEND_TEXTDIAGNOSTICPRINTER_H + +#include "clang/Basic/Diagnostic.h" +#include "llvm/ADT/IntrusiveRefCntPtr.h" +#include "llvm/Support/raw_ostream.h" + +namespace clang { +class DiagnosticOptions; +class DiagnosticsEngine; +}; // namespace clang + +using llvm::IntrusiveRefCntPtr; +using llvm::raw_ostream; + +namespace Fortran::frontend { +class TextDiagnostic; + +class TextDiagnosticPrinter : public clang::DiagnosticConsumer { + raw_ostream &os_; + llvm::IntrusiveRefCntPtr diagOpts_; + + /// A string to prefix to error messages. + std::string prefix_; + +public: + TextDiagnosticPrinter(raw_ostream &os, clang::DiagnosticOptions *diags); + ~TextDiagnosticPrinter() override; + + /// Set the diagnostic printer prefix string, which will be printed at the + /// start of any diagnostics. If empty, no prefix string is used. + void set_prefix(std::string value) { prefix_ = std::move(value); } + + void HandleDiagnostic(clang::DiagnosticsEngine::Level level, + const clang::Diagnostic &info) override; +}; + +} // namespace Fortran::frontend + +#endif diff --git a/flang/lib/Frontend/CMakeLists.txt b/flang/lib/Frontend/CMakeLists.txt --- a/flang/lib/Frontend/CMakeLists.txt +++ b/flang/lib/Frontend/CMakeLists.txt @@ -2,13 +2,13 @@ CompilerInstance.cpp CompilerInvocation.cpp FrontendOptions.cpp + TextDiagnosticPrinter.cpp + TextDiagnosticBuffer.cpp + TextDiagnostic.cpp LINK_LIBS clangBasic clangDriver - # TODO: Added to re-use clang's TextDiagnosticBuffer & TextDiagnosticPrinter. - # Add a custom implementation for Flang and remove this dependency. - clangFrontend LINK_COMPONENTS Option 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 @@ -8,7 +8,7 @@ #include "flang/Frontend/CompilerInstance.h" #include "flang/Frontend/CompilerInvocation.h" -#include "clang/Frontend/TextDiagnosticPrinter.h" +#include "flang/Frontend/TextDiagnosticPrinter.h" #include "llvm/Support/raw_ostream.h" using namespace Fortran::frontend; @@ -36,7 +36,7 @@ if (client) { diags->setClient(client, shouldOwnClient); } else { - diags->setClient(new clang::TextDiagnosticPrinter(llvm::errs(), opts)); + diags->setClient(new TextDiagnosticPrinter(llvm::errs(), opts)); } return diags; } 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 @@ -17,6 +17,7 @@ #include "llvm/Option/Arg.h" #include "llvm/Option/ArgList.h" #include "llvm/Option/OptTable.h" +#include "llvm/Support/Process.h" #include "llvm/Support/raw_ostream.h" using namespace Fortran::frontend; @@ -35,6 +36,49 @@ //===----------------------------------------------------------------------===// // Deserialization (from args) //===----------------------------------------------------------------------===// +static bool parseShowColorsArgs( + const llvm::opt::ArgList &args, bool defaultColor) { + // Color diagnostics default to auto ("on" if terminal supports) in the driver + // but default to off in cc1, needing an explicit OPT_fdiagnostics_color. + // Support both clang's -f[no-]color-diagnostics and gcc's + // -f[no-]diagnostics-colors[=never|always|auto]. + enum { + Colors_On, + Colors_Off, + Colors_Auto + } ShowColors = defaultColor ? Colors_Auto : Colors_Off; + + for (auto *a : args) { + const llvm::opt::Option &O = a->getOption(); + if (O.matches(clang::driver::options::OPT_fcolor_diagnostics) || + O.matches(clang::driver::options::OPT_fdiagnostics_color)) { + ShowColors = Colors_On; + } else if (O.matches(clang::driver::options::OPT_fno_color_diagnostics) || + O.matches(clang::driver::options::OPT_fno_diagnostics_color)) { + ShowColors = Colors_Off; + } else if (O.matches(clang::driver::options::OPT_fdiagnostics_color_EQ)) { + llvm::StringRef value(a->getValue()); + if (value == "always") + ShowColors = Colors_On; + else if (value == "never") + ShowColors = Colors_Off; + else if (value == "auto") + ShowColors = Colors_Auto; + } + } + + return ShowColors == Colors_On || + (ShowColors == Colors_Auto && llvm::sys::Process::StandardErrHasColors()); +} + +bool Fortran::frontend::ParseDiagnosticArgs(clang::DiagnosticOptions &opts, + llvm::opt::ArgList &args, clang::DiagnosticsEngine *diags, + bool defaultDiagColor) { + opts.ShowColors = parseShowColorsArgs(args, defaultDiagColor); + + return true; +} + static InputKind ParseFrontendArgs(FrontendOptions &opts, llvm::opt::ArgList &args, clang::DiagnosticsEngine &diags) { // Identify the action (i.e. opts.ProgramAction) diff --git a/flang/lib/Frontend/TextDiagnostic.cpp b/flang/lib/Frontend/TextDiagnostic.cpp new file mode 100644 --- /dev/null +++ b/flang/lib/Frontend/TextDiagnostic.cpp @@ -0,0 +1,97 @@ +//===--- TextDiagnostic.cpp - Text Diagnostic Pretty-Printing -------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "flang/Frontend/TextDiagnostic.h" +#include "clang/Basic/DiagnosticOptions.h" +#include "llvm/Support/raw_ostream.h" + +using namespace Fortran::frontend; + +// TODO: Similar enums are defined in clang/lib/Frontend/TextDiagnostic.cpp. +// It would be best to share them +static const enum llvm::raw_ostream::Colors noteColor = + llvm::raw_ostream::BLACK; +static const enum llvm::raw_ostream::Colors remarkColor = + llvm::raw_ostream::BLUE; +static const enum llvm::raw_ostream::Colors warningColor = + llvm::raw_ostream::MAGENTA; +static const enum llvm::raw_ostream::Colors errorColor = llvm::raw_ostream::RED; +static const enum llvm::raw_ostream::Colors fatalColor = llvm::raw_ostream::RED; +// Used for changing only the bold attribute. +static const enum llvm::raw_ostream::Colors savedColor = + llvm::raw_ostream::SAVEDCOLOR; + +TextDiagnostic::TextDiagnostic() {} + +TextDiagnostic::~TextDiagnostic() {} + +/*static*/ void TextDiagnostic::PrintDiagnosticLevel(llvm::raw_ostream &os, + clang::DiagnosticsEngine::Level level, bool showColors) { + if (showColors) { + // Print diagnostic category in bold and color + switch (level) { + case clang::DiagnosticsEngine::Ignored: + llvm_unreachable("Invalid diagnostic type"); + case clang::DiagnosticsEngine::Note: + os.changeColor(noteColor, true); + break; + case clang::DiagnosticsEngine::Remark: + os.changeColor(remarkColor, true); + break; + case clang::DiagnosticsEngine::Warning: + os.changeColor(warningColor, true); + break; + case clang::DiagnosticsEngine::Error: + os.changeColor(errorColor, true); + break; + case clang::DiagnosticsEngine::Fatal: + os.changeColor(fatalColor, true); + break; + } + } + + switch (level) { + case clang::DiagnosticsEngine::Ignored: + llvm_unreachable("Invalid diagnostic type"); + case clang::DiagnosticsEngine::Note: + os << "note"; + break; + case clang::DiagnosticsEngine::Remark: + os << "remark"; + break; + case clang::DiagnosticsEngine::Warning: + os << "warning"; + break; + case clang::DiagnosticsEngine::Error: + os << "error"; + break; + case clang::DiagnosticsEngine::Fatal: + os << "fatal error"; + break; + } + + os << ": "; + + if (showColors) + os.resetColor(); +} + +/*static*/ +void TextDiagnostic::PrintDiagnosticMessage(llvm::raw_ostream &os, + bool isSupplemental, llvm::StringRef message, bool showColors) { + if (showColors && !isSupplemental) { + // Print primary diagnostic messages in bold and without color. + os.changeColor(savedColor, true); + } + + os << message; + + if (showColors) + os.resetColor(); + os << '\n'; +} diff --git a/flang/lib/Frontend/TextDiagnosticBuffer.cpp b/flang/lib/Frontend/TextDiagnosticBuffer.cpp new file mode 100644 --- /dev/null +++ b/flang/lib/Frontend/TextDiagnosticBuffer.cpp @@ -0,0 +1,74 @@ +//===- TextDiagnosticBuffer.cpp - Buffer Text Diagnostics -----------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This is a concrete diagnostic client, which buffers the diagnostic messages. +// +//===----------------------------------------------------------------------===// + +#include "flang/Frontend/TextDiagnosticBuffer.h" +#include "clang/Basic/Diagnostic.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/Support/ErrorHandling.h" + +using namespace Fortran::frontend; + +/// HandleDiagnostic - Store the errors, warnings, and notes that are +/// reported. +void TextDiagnosticBuffer::HandleDiagnostic( + clang::DiagnosticsEngine::Level level, const clang::Diagnostic &info) { + // Default implementation (warnings_/errors count). + DiagnosticConsumer::HandleDiagnostic(level, info); + + llvm::SmallString<100> buf; + info.FormatDiagnostic(buf); + switch (level) { + default: + llvm_unreachable("Diagnostic not handled during diagnostic buffering!"); + case clang::DiagnosticsEngine::Note: + all_.emplace_back(level, notes_.size()); + notes_.emplace_back(info.getLocation(), std::string(buf.str())); + break; + case clang::DiagnosticsEngine::Warning: + all_.emplace_back(level, warnings_.size()); + warnings_.emplace_back(info.getLocation(), std::string(buf.str())); + break; + case clang::DiagnosticsEngine::Remark: + all_.emplace_back(level, remarks_.size()); + remarks_.emplace_back(info.getLocation(), std::string(buf.str())); + break; + case clang::DiagnosticsEngine::Error: + case clang::DiagnosticsEngine::Fatal: + all_.emplace_back(level, errors_.size()); + errors_.emplace_back(info.getLocation(), std::string(buf.str())); + break; + } +} + +void TextDiagnosticBuffer::FlushDiagnostics( + clang::DiagnosticsEngine &Diags) const { + for (const auto &i : all_) { + auto Diag = Diags.Report(Diags.getCustomDiagID(i.first, "%0")); + switch (i.first) { + default: + llvm_unreachable("Diagnostic not handled during diagnostic flushing!"); + case clang::DiagnosticsEngine::Note: + Diag << notes_[i.second].second; + break; + case clang::DiagnosticsEngine::Warning: + Diag << warnings_[i.second].second; + break; + case clang::DiagnosticsEngine::Remark: + Diag << remarks_[i.second].second; + break; + case clang::DiagnosticsEngine::Error: + case clang::DiagnosticsEngine::Fatal: + Diag << errors_[i.second].second; + break; + } + } +} diff --git a/flang/lib/Frontend/TextDiagnosticPrinter.cpp b/flang/lib/Frontend/TextDiagnosticPrinter.cpp new file mode 100644 --- /dev/null +++ b/flang/lib/Frontend/TextDiagnosticPrinter.cpp @@ -0,0 +1,57 @@ +//===--- TextDiagnosticPrinter.cpp - Diagnostic Printer -------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This diagnostic client prints out their diagnostic messages. +// +//===----------------------------------------------------------------------===// + +#include "flang/Frontend/TextDiagnosticPrinter.h" +#include "flang/Frontend/TextDiagnostic.h" +#include "clang/Basic/DiagnosticOptions.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" + +using namespace Fortran::frontend; + +using llvm::SmallString; + +TextDiagnosticPrinter::TextDiagnosticPrinter( + raw_ostream &os, clang::DiagnosticOptions *diags) + : os_(os), diagOpts_(diags) {} + +TextDiagnosticPrinter::~TextDiagnosticPrinter() {} + +void TextDiagnosticPrinter::HandleDiagnostic( + clang::DiagnosticsEngine::Level level, const clang::Diagnostic &info) { + // Default implementation (Warnings/errors count). + DiagnosticConsumer::HandleDiagnostic(level, info); + + // Render the diagnostic message into a temporary buffer eagerly. We'll use + // this later as we print out the diagnostic to the terminal. + SmallString<100> outStr; + info.FormatDiagnostic(outStr); + + llvm::raw_svector_ostream DiagMessageStream(outStr); + + if (!prefix_.empty()) + os_ << prefix_ << ": "; + + // We only emit diagnostics in contexts that lack valid source locations. + assert(!info.getLocation().isValid() && + "Diagnostics with valid source location are not supported"); + + Fortran::frontend::TextDiagnostic::PrintDiagnosticLevel( + os_, level, diagOpts_->ShowColors); + Fortran::frontend::TextDiagnostic::PrintDiagnosticMessage(os_, + /*IsSupplemental=*/level == clang::DiagnosticsEngine::Note, + DiagMessageStream.str(), diagOpts_->ShowColors); + + os_.flush(); + return; +} diff --git a/flang/test/Flang-Driver/driver-error-cc1.c b/flang/test/Flang-Driver/driver-error-cc1.c --- a/flang/test/Flang-Driver/driver-error-cc1.c +++ b/flang/test/Flang-Driver/driver-error-cc1.c @@ -4,4 +4,4 @@ // C files are currently not supported (i.e. `flang -cc1`) -// CHECK:error: unknown integrated tool '-cc1'. Valid tools include '-fc1'. +// CHECK: error: unknown integrated tool '-cc1'. Valid tools include '-fc1'. diff --git a/flang/test/Flang-Driver/driver-error-cc1.cpp b/flang/test/Flang-Driver/driver-error-cc1.cpp --- a/flang/test/Flang-Driver/driver-error-cc1.cpp +++ b/flang/test/Flang-Driver/driver-error-cc1.cpp @@ -4,4 +4,4 @@ // C++ files are currently not supported (i.e. `flang -cc1`) -// CHECK:error: unknown integrated tool '-cc1'. Valid tools include '-fc1'. +// CHECK: error: unknown integrated tool '-cc1'. Valid tools include '-fc1'. diff --git a/flang/test/Flang-Driver/driver-help.f90 b/flang/test/Flang-Driver/driver-help.f90 --- a/flang/test/Flang-Driver/driver-help.f90 +++ b/flang/test/Flang-Driver/driver-help.f90 @@ -7,7 +7,9 @@ ! CHECK:USAGE: flang-new ! CHECK-EMPTY: ! CHECK-NEXT:OPTIONS: +! 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: --version Print version information -! ERROR: error: unknown argument '-helps'; did you mean '-help' +! ERROR: flang-new: error: unknown argument '-helps'; did you mean '-help' diff --git a/flang/test/Flang-Driver/driver-version.f90 b/flang/test/Flang-Driver/driver-version.f90 --- a/flang/test/Flang-Driver/driver-version.f90 +++ b/flang/test/Flang-Driver/driver-version.f90 @@ -8,4 +8,4 @@ ! CHECK-NEXT:Thread model: ! CHECK-NEXT:InstalledDir: -! ERROR: error: unsupported option '--versions'; did you mean '--version'? +! ERROR: flang-new: error: unsupported option '--versions'; did you mean '--version'? diff --git a/flang/test/Flang-Driver/missing-input.f90 b/flang/test/Flang-Driver/missing-input.f90 --- a/flang/test/Flang-Driver/missing-input.f90 +++ b/flang/test/Flang-Driver/missing-input.f90 @@ -2,4 +2,4 @@ ! REQUIRES: new-flang-driver -! CHECK: error: no input files +! CHECK: flang-new: error: no input files diff --git a/flang/tools/flang-driver/driver.cpp b/flang/tools/flang-driver/driver.cpp --- a/flang/tools/flang-driver/driver.cpp +++ b/flang/tools/flang-driver/driver.cpp @@ -11,17 +11,21 @@ // //===----------------------------------------------------------------------===// #include "clang/Driver/Driver.h" +#include "flang/Frontend/CompilerInvocation.h" +#include "flang/Frontend/TextDiagnosticPrinter.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/DiagnosticIDs.h" #include "clang/Basic/DiagnosticOptions.h" #include "clang/Driver/Compilation.h" -#include "clang/Frontend/TextDiagnosticPrinter.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/IntrusiveRefCntPtr.h" #include "llvm/Option/ArgList.h" #include "llvm/Support/Host.h" #include "llvm/Support/InitLLVM.h" #include "llvm/Support/VirtualFileSystem.h" +#include + +using llvm::StringRef; // main frontend method. Lives inside fc1_main.cpp extern int fc1_main(llvm::ArrayRef argv, const char *argv0); @@ -37,6 +41,17 @@ static clang::DiagnosticOptions *CreateAndPopulateDiagOpts( llvm::ArrayRef argv) { auto *diagOpts = new clang::DiagnosticOptions; + + // Ignore missingArgCount and the return value of ParseDiagnosticArgs. + // Any errors that would be diagnosed here will also be diagnosed later, + // when the DiagnosticsEngine actually exists. + unsigned missingArgIndex, missingArgCount; + llvm::opt::InputArgList args = clang::driver::getDriverOptTable().ParseArgs( + argv.slice(1), missingArgIndex, missingArgCount, + /*FlagsToInclude=*/clang::driver::options::FlangOption); + + (void)Fortran::frontend::ParseDiagnosticArgs(*diagOpts, args); + return diagOpts; } @@ -83,8 +98,12 @@ CreateAndPopulateDiagOpts(argv); llvm::IntrusiveRefCntPtr diagID( new clang::DiagnosticIDs()); - clang::TextDiagnosticPrinter *diagClient = - new clang::TextDiagnosticPrinter(llvm::errs(), &*diagOpts); + Fortran::frontend::TextDiagnosticPrinter *diagClient = + new Fortran::frontend::TextDiagnosticPrinter(llvm::errs(), &*diagOpts); + + diagClient->set_prefix( + std::string(llvm::sys::path::stem(GetExecutablePath(argv[0])))); + clang::DiagnosticsEngine diags(diagID, &*diagOpts, diagClient); // Prepare the driver diff --git a/flang/tools/flang-driver/fc1_main.cpp b/flang/tools/flang-driver/fc1_main.cpp --- a/flang/tools/flang-driver/fc1_main.cpp +++ b/flang/tools/flang-driver/fc1_main.cpp @@ -14,9 +14,9 @@ #include "flang/Frontend/CompilerInstance.h" #include "flang/Frontend/CompilerInvocation.h" +#include "flang/Frontend/TextDiagnosticBuffer.h" #include "flang/FrontendTool/Utils.h" #include "clang/Driver/DriverDiagnostic.h" -#include "clang/Frontend/TextDiagnosticBuffer.h" #include "llvm/Option/Arg.h" #include "llvm/Option/ArgList.h" #include "llvm/Option/OptTable.h" @@ -34,18 +34,22 @@ if (!flang->HasDiagnostics()) return 1; + // We will buffer diagnostics from argument parsing so that we can output + // them using a well formed diagnostic object. + TextDiagnosticBuffer *diagsBuffer = new TextDiagnosticBuffer; + // Create CompilerInvocation - use a dedicated instance of DiagnosticsEngine // for parsing the arguments llvm::IntrusiveRefCntPtr diagID( new clang::DiagnosticIDs()); llvm::IntrusiveRefCntPtr diagOpts = new clang::DiagnosticOptions(); - clang::TextDiagnosticBuffer *diagsBuffer = new clang::TextDiagnosticBuffer; clang::DiagnosticsEngine diags(diagID, &*diagOpts, diagsBuffer); bool success = CompilerInvocation::CreateFromArgs(flang->GetInvocation(), argv, diags); diagsBuffer->FlushDiagnostics(flang->getDiagnostics()); + if (!success) return 1; diff --git a/flang/unittests/Frontend/CompilerInstanceTest.cpp b/flang/unittests/Frontend/CompilerInstanceTest.cpp --- a/flang/unittests/Frontend/CompilerInstanceTest.cpp +++ b/flang/unittests/Frontend/CompilerInstanceTest.cpp @@ -9,9 +9,9 @@ #include "flang/Frontend/CompilerInstance.h" #include "gtest/gtest.h" #include "flang/Frontend/CompilerInvocation.h" +#include "flang/Frontend/TextDiagnosticPrinter.h" #include "clang/Basic/DiagnosticOptions.h" #include "clang/Driver/Options.h" -#include "clang/Frontend/TextDiagnosticPrinter.h" #include "llvm/Support/raw_ostream.h" #include @@ -24,7 +24,7 @@ // 1. Set-up a basic DiagnosticConsumer std::string diagnosticOutput; llvm::raw_string_ostream diagnosticsOS(diagnosticOutput); - auto diagPrinter = std::make_unique( + auto diagPrinter = std::make_unique( diagnosticsOS, new clang::DiagnosticOptions()); // 2. Create a CompilerInstance (to manage a DiagnosticEngine)