From ad687856445ce2aea2c9ea57e052d70e34f139d9 Mon Sep 17 00:00:00 2001
From: Jean-Didier Pailleux <jean-didier.pailleux@sipearl.com>
Date: Mon, 10 Mar 2025 13:40:30 +0100
Subject: [PATCH] [flang/clang] Adding use of Clang's diagnostics in Flang

---
 clang/include/clang/Basic/Diagnostic.td       |   5 +-
 .../clang/Basic/DiagnosticCategories.h        |   3 +-
 clang/include/clang/Basic/DiagnosticIDs.h     |   5 +
 clang/lib/Basic/DiagnosticIDs.cpp             |  14 ++-
 clang/lib/Basic/Warnings.cpp                  |   9 ++
 clang/test/TableGen/DiagnosticBase.inc        |   4 +-
 clang/tools/diagtool/DiagnosticNames.cpp      |   3 +-
 .../TableGen/ClangDiagnosticsEmitter.cpp      |   4 +
 .../flang/Frontend/CompilerInvocation.h       |  10 +-
 flang/include/flang/Semantics/semantics.h     |   5 +-
 flang/include/flang/Semantics/symbol.h        |   3 +
 flang/lib/Frontend/CMakeLists.txt             |   1 +
 flang/lib/Frontend/CompilerInstance.cpp       |   3 +-
 flang/lib/Frontend/CompilerInvocation.cpp     |  50 +++++----
 flang/lib/Frontend/Warnings.cpp               | 102 ++++++++++++++++++
 flang/lib/Semantics/CMakeLists.txt            |   3 +
 flang/lib/Semantics/semantics.cpp             |   4 +-
 flang/test/Driver/w-arg-unknown.f90           |   7 ++
 flang/test/Driver/werror-wrong.f90            |   6 --
 flang/test/Driver/wextra-ok.f90               |   4 +-
 flang/tools/bbc/CMakeLists.txt                |   5 +
 flang/tools/bbc/bbc.cpp                       |  14 ++-
 flang/tools/flang-driver/driver.cpp           |  10 +-
 flang/tools/flang-driver/fc1_main.cpp         |  19 ++--
 24 files changed, 242 insertions(+), 51 deletions(-)
 create mode 100644 flang/lib/Frontend/Warnings.cpp
 create mode 100644 flang/test/Driver/w-arg-unknown.f90
 delete mode 100644 flang/test/Driver/werror-wrong.f90

diff --git a/clang/include/clang/Basic/Diagnostic.td b/clang/include/clang/Basic/Diagnostic.td
index 0b8b3af939ba0..b3a2e76ddc453 100644
--- a/clang/include/clang/Basic/Diagnostic.td
+++ b/clang/include/clang/Basic/Diagnostic.td
@@ -55,11 +55,14 @@ class DiagCategory<string Name> {
 }
 
 // Diagnostic Groups.
-class DiagGroup<string Name, list<DiagGroup> subgroups = [], code docs = [{}]> {
+class DiagGroup<string Name, list<DiagGroup> subgroups = [], code docs = [{}],
+                bit clangDiag = 1, bit flangDiag = 0> {
   string GroupName = Name;
   list<DiagGroup> SubGroups = subgroups;
   string CategoryName = "";
   code Documentation = docs;
+  bit IsClangDiag = clangDiag;
+  bit IsFlangDiag = flangDiag;
 }
 class InGroup<DiagGroup G> { DiagGroup Group = G; }
 //class IsGroup<string Name> { DiagGroup Group = DiagGroup<Name>; }
diff --git a/clang/include/clang/Basic/DiagnosticCategories.h b/clang/include/clang/Basic/DiagnosticCategories.h
index 839f8dee3ca89..5e44889a2fcd8 100644
--- a/clang/include/clang/Basic/DiagnosticCategories.h
+++ b/clang/include/clang/Basic/DiagnosticCategories.h
@@ -21,7 +21,8 @@ namespace clang {
     };
 
     enum class Group {
-#define DIAG_ENTRY(GroupName, FlagNameOffset, Members, SubGroups, Docs)    \
+#define DIAG_ENTRY(GroupName, FlagNameOffset, Members, SubGroups, Docs,    \
+                       IsClang, IsFlang)                                       \
       GroupName,
 #include "clang/Basic/DiagnosticGroups.inc"
 #undef CATEGORY
diff --git a/clang/include/clang/Basic/DiagnosticIDs.h b/clang/include/clang/Basic/DiagnosticIDs.h
index 017ef7065610f..e57500fb85d3c 100644
--- a/clang/include/clang/Basic/DiagnosticIDs.h
+++ b/clang/include/clang/Basic/DiagnosticIDs.h
@@ -365,6 +365,11 @@ class DiagnosticIDs : public RefCountedBase<DiagnosticIDs> {
   /// Given a diagnostic group ID, return its documentation.
   static StringRef getWarningOptionDocumentation(diag::Group GroupID);
 
+  /// Given a diagnostic group ID, return true if its a Flang warning.
+  static bool isFlangWarningOption(diag::Group Group);
+  /// Given a diagnostic group ID, return true if its a Clang warning.
+  static bool isClangWarningOption(diag::Group Group);
+
   void setGroupSeverity(StringRef Group, diag::Severity);
   void setGroupNoWarningsAsError(StringRef Group, bool);
 
diff --git a/clang/lib/Basic/DiagnosticIDs.cpp b/clang/lib/Basic/DiagnosticIDs.cpp
index ca5b8d2da769e..e275f7165b392 100644
--- a/clang/lib/Basic/DiagnosticIDs.cpp
+++ b/clang/lib/Basic/DiagnosticIDs.cpp
@@ -585,6 +585,8 @@ namespace {
     uint16_t Members;
     uint16_t SubGroups;
     StringRef Documentation;
+    bool IsClangDiag;
+    bool IsFlangDiag;
 
     StringRef getName() const { return DiagGroupNames[NameOffset]; }
   };
@@ -592,8 +594,9 @@ namespace {
 
 // Second the table of options, sorted by name for fast binary lookup.
 static const WarningOption OptionTable[] = {
-#define DIAG_ENTRY(GroupName, FlagNameOffset, Members, SubGroups, Docs)        \
-  {FlagNameOffset, Members, SubGroups, Docs},
+#define DIAG_ENTRY(GroupName, FlagNameOffset, Members, SubGroups, Docs,        \
+                   IsClang, IsFlang)                                           \
+  {FlagNameOffset, Members, SubGroups, Docs, IsClang, IsFlang},
 #include "clang/Basic/DiagnosticGroups.inc"
 #undef DIAG_ENTRY
 };
@@ -607,6 +610,13 @@ StringRef DiagnosticIDs::getWarningOptionForGroup(diag::Group Group) {
   return OptionTable[static_cast<int>(Group)].getName();
 }
 
+bool DiagnosticIDs::isFlangWarningOption(diag::Group Group) {
+  return OptionTable[static_cast<int>(Group)].IsFlangDiag;
+}
+
+bool DiagnosticIDs::isClangWarningOption(diag::Group Group) {
+  return OptionTable[static_cast<int>(Group)].IsClangDiag;
+}
 std::optional<diag::Group>
 DiagnosticIDs::getGroupForWarningOption(StringRef Name) {
   const auto *Found = llvm::partition_point(
diff --git a/clang/lib/Basic/Warnings.cpp b/clang/lib/Basic/Warnings.cpp
index 5f48e0ec81554..e6c1355650113 100644
--- a/clang/lib/Basic/Warnings.cpp
+++ b/clang/lib/Basic/Warnings.cpp
@@ -106,6 +106,15 @@ void clang::ProcessWarningOptions(DiagnosticsEngine &Diags,
       diag::Severity Mapping =
           isPositive ? diag::Severity::Warning : diag::Severity::Ignored;
 
+      // Check if the warning option is valid for Clang
+      std::optional<diag::Group> Group = DiagIDs->getGroupForWarningOption(Opt);
+      if (Group.has_value() && !DiagIDs->isClangWarningOption(Group.value())) {
+        const unsigned DiagID = Diags.getCustomDiagID(
+            DiagnosticsEngine::Error,
+            "Warning option \"%0\" is valid for Fortran but not for C++.");
+        Diags.Report(DiagID) << Opt;
+      }
+
       // -Wsystem-headers is a special case, not driven by the option table.  It
       // cannot be controlled with -Werror.
       if (Opt == "system-headers") {
diff --git a/clang/test/TableGen/DiagnosticBase.inc b/clang/test/TableGen/DiagnosticBase.inc
index 2fc7bb4266edb..359c6d1edd79a 100644
--- a/clang/test/TableGen/DiagnosticBase.inc
+++ b/clang/test/TableGen/DiagnosticBase.inc
@@ -55,11 +55,13 @@ class DiagCategory<string Name> {
 }
 
 // Diagnostic Groups.
-class DiagGroup<string Name, list<DiagGroup> subgroups = []> {
+class DiagGroup<string Name, list<DiagGroup> subgroups = [], bit clangDiag = 1, bit flangDiag = 0> {
   string GroupName = Name;
   list<DiagGroup> SubGroups = subgroups;
   string CategoryName = "";
   code Documentation = [{}];
+  bit IsClangDiag = clangDiag;
+  bit IsFlangDiag = flangDiag;
 }
 class InGroup<DiagGroup G> { DiagGroup Group = G; }
 //class IsGroup<string Name> { DiagGroup Group = DiagGroup<Name>; }
diff --git a/clang/tools/diagtool/DiagnosticNames.cpp b/clang/tools/diagtool/DiagnosticNames.cpp
index 4ac9825848ef3..95b9da461599b 100644
--- a/clang/tools/diagtool/DiagnosticNames.cpp
+++ b/clang/tools/diagtool/DiagnosticNames.cpp
@@ -62,7 +62,8 @@ const DiagnosticRecord &diagtool::getDiagnosticForID(short DiagID) {
 
 // Second the table of options, sorted by name for fast binary lookup.
 static const GroupRecord OptionTable[] = {
-#define DIAG_ENTRY(GroupName, FlagNameOffset, Members, SubGroups, Docs)        \
+#define DIAG_ENTRY(GroupName, FlagNameOffset, Members, SubGroups, Docs,        \
+                   IsClang, IsFlang)                                           \
   {FlagNameOffset, Members, SubGroups},
 #include "clang/Basic/DiagnosticGroups.inc"
 #undef DIAG_ENTRY
diff --git a/clang/utils/TableGen/ClangDiagnosticsEmitter.cpp b/clang/utils/TableGen/ClangDiagnosticsEmitter.cpp
index 8f846a4744bbf..0c0962f6fceaa 100644
--- a/clang/utils/TableGen/ClangDiagnosticsEmitter.cpp
+++ b/clang/utils/TableGen/ClangDiagnosticsEmitter.cpp
@@ -1890,6 +1890,10 @@ static void emitDiagTable(DiagsInGroupTy &DiagsInGroup,
 
     OS << "R\"(" << StringRef(Documentation).trim() << ")\"";
 
+    OS << ", /*IsClangDiag*/ "
+       << bool(GroupInfo.Defs.back()->getValueAsBit("IsClangDiag"));
+    OS << ", /*IsFlangDiag*/ "
+       << bool(GroupInfo.Defs.back()->getValueAsBit("IsFlangDiag"));
     OS << ")\n";
   }
   OS << "#endif // DIAG_ENTRY\n\n";
diff --git a/flang/include/flang/Frontend/CompilerInvocation.h b/flang/include/flang/Frontend/CompilerInvocation.h
index 9e6724be33033..9fdaeac3d999a 100644
--- a/flang/include/flang/Frontend/CompilerInvocation.h
+++ b/flang/include/flang/Frontend/CompilerInvocation.h
@@ -33,12 +33,18 @@ class TargetMachine;
 
 namespace Fortran::frontend {
 
+/// processWarningOptions - Initialize the diagnostic client and process the
+/// warning options specified on the command line.
+void processWarningOptions(clang::DiagnosticsEngine &Diags,
+                           const clang::DiagnosticOptions &Opts);
+
 /// 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);
+                         llvm::opt::ArgList &args,
+                         bool defaultDiagColor = true);
 
 class CompilerInvocationBase {
 public:
@@ -174,7 +180,7 @@ class CompilerInvocation : public CompilerInvocationBase {
   /// Creates and configures semantics context based on the compilation flags.
   std::unique_ptr<Fortran::semantics::SemanticsContext>
   getSemanticsCtx(Fortran::parser::AllCookedSources &allCookedSources,
-                  const llvm::TargetMachine &);
+                  const llvm::TargetMachine &, clang::DiagnosticsEngine &diag);
 
   std::string &getModuleDir() { return moduleDir; }
   const std::string &getModuleDir() const { return moduleDir; }
diff --git a/flang/include/flang/Semantics/semantics.h b/flang/include/flang/Semantics/semantics.h
index 730513dbe3232..72ecd046f4048 100644
--- a/flang/include/flang/Semantics/semantics.h
+++ b/flang/include/flang/Semantics/semantics.h
@@ -19,6 +19,7 @@
 #include "flang/Parser/message.h"
 #include "flang/Support/Fortran-features.h"
 #include "flang/Support/LangOptions.h"
+#include "clang/Basic/Diagnostic.h"
 #include <iosfwd>
 #include <set>
 #include <string>
@@ -68,7 +69,7 @@ class SemanticsContext {
 public:
   SemanticsContext(const common::IntrinsicTypeDefaultKinds &,
       const common::LanguageFeatureControl &, const common::LangOptions &,
-      parser::AllCookedSources &);
+      parser::AllCookedSources &, clang::DiagnosticsEngine &);
   ~SemanticsContext();
 
   const common::IntrinsicTypeDefaultKinds &defaultKinds() const {
@@ -82,6 +83,7 @@ class SemanticsContext {
   int doublePrecisionKind() const {
     return defaultKinds_.doublePrecisionKind();
   }
+  clang::DiagnosticsEngine &getDiagnostics() const { return diags_; }
   int quadPrecisionKind() const { return defaultKinds_.quadPrecisionKind(); }
   bool IsEnabled(common::LanguageFeature feature) const {
     return languageFeatures_.IsEnabled(feature);
@@ -305,6 +307,7 @@ class SemanticsContext {
   const common::IntrinsicTypeDefaultKinds &defaultKinds_;
   const common::LanguageFeatureControl &languageFeatures_;
   const common::LangOptions &langOpts_;
+  clang::DiagnosticsEngine &diags_;
   parser::AllCookedSources &allCookedSources_;
   std::optional<parser::CharBlock> location_;
   std::vector<std::string> searchDirectories_;
diff --git a/flang/include/flang/Semantics/symbol.h b/flang/include/flang/Semantics/symbol.h
index 715811885c219..a14ca19241823 100644
--- a/flang/include/flang/Semantics/symbol.h
+++ b/flang/include/flang/Semantics/symbol.h
@@ -293,10 +293,13 @@ class EntityDetails : public WithBindName {
   void set_isDummy(bool value = true) { isDummy_ = value; }
   bool isFuncResult() const { return isFuncResult_; }
   void set_funcResult(bool x) { isFuncResult_ = x; }
+  bool isUsed() const { return isUsed_; }
+  void set_isUsed() { isUsed_ = true; }
 
 private:
   bool isDummy_{false};
   bool isFuncResult_{false};
+  bool isUsed_{false};
   const DeclTypeSpec *type_{nullptr};
   friend llvm::raw_ostream &operator<<(
       llvm::raw_ostream &, const EntityDetails &);
diff --git a/flang/lib/Frontend/CMakeLists.txt b/flang/lib/Frontend/CMakeLists.txt
index 80d63fca6fb76..1d49b91db092a 100644
--- a/flang/lib/Frontend/CMakeLists.txt
+++ b/flang/lib/Frontend/CMakeLists.txt
@@ -11,6 +11,7 @@ add_flang_library(flangFrontend
   TextDiagnosticPrinter.cpp
   TextDiagnosticBuffer.cpp
   TextDiagnostic.cpp
+  Warnings.cpp
 
   DEPENDS
   CUFDialect
diff --git a/flang/lib/Frontend/CompilerInstance.cpp b/flang/lib/Frontend/CompilerInstance.cpp
index b1fa32ecb4cfc..6374a8b0d45bd 100644
--- a/flang/lib/Frontend/CompilerInstance.cpp
+++ b/flang/lib/Frontend/CompilerInstance.cpp
@@ -163,7 +163,8 @@ bool CompilerInstance::executeAction(FrontendAction &act) {
   if (!setUpTargetMachine())
     return false;
   // Create the semantics context
-  semaContext = invoc.getSemanticsCtx(*allCookedSources, getTargetMachine());
+  semaContext = invoc.getSemanticsCtx(*allCookedSources, getTargetMachine(),
+                                      getDiagnostics());
   // Set options controlling lowering to FIR.
   invoc.setLoweringOptions();
 
diff --git a/flang/lib/Frontend/CompilerInvocation.cpp b/flang/lib/Frontend/CompilerInvocation.cpp
index 8b07a50824899..cee4b7c053f9e 100644
--- a/flang/lib/Frontend/CompilerInvocation.cpp
+++ b/flang/lib/Frontend/CompilerInvocation.cpp
@@ -33,6 +33,7 @@
 #include "llvm/Option/Arg.h"
 #include "llvm/Option/ArgList.h"
 #include "llvm/Option/OptTable.h"
+#include "llvm/Option/Option.h"
 #include "llvm/Support/CodeGen.h"
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/FileUtilities.h"
@@ -119,9 +120,26 @@ static unsigned getOptimizationLevel(llvm::opt::ArgList &args,
 }
 
 bool Fortran::frontend::parseDiagnosticArgs(clang::DiagnosticOptions &opts,
-                                            llvm::opt::ArgList &args) {
-  opts.ShowColors = parseShowColorsArgs(args);
-
+                                            llvm::opt::ArgList &args,
+                                            bool defaultDiagColor) {
+  opts.ShowColors = parseShowColorsArgs(args, defaultDiagColor);
+
+  for (llvm::opt::Arg *A : args.filtered(clang::driver::options::OPT_W_Group)) {
+    if (A->getOption().getKind() == llvm::opt::Option::FlagClass) {
+      // The argument is a pure flag (such as OPT_Wall).
+      opts.Warnings.push_back(
+          std::string(A->getOption().getName().drop_front(1)));
+    } else if (A->getOption().matches(
+                   clang::driver::options::OPT_W_value_Group)) {
+      // This is -Wfoo= where foo is the name of the diagnostic group.
+      // Add only the group name to the diagnostics.
+      opts.Warnings.push_back(
+          std::string(A->getOption().getName().drop_front(1).rtrim("=-")));
+    } else {
+      // Otherwise, add its value for OPT_W_Joined.
+      opts.Warnings.push_back(A->getValue());
+    }
+  }
   return true;
 }
 
@@ -927,22 +945,11 @@ static bool parseDiagArgs(CompilerInvocation &res, llvm::opt::ArgList &args,
                           clang::DiagnosticsEngine &diags) {
   unsigned numErrorsBefore = diags.getNumErrors();
 
-  // -Werror option
-  // TODO: Currently throws a Diagnostic for anything other than -W<error>,
-  // this has to change when other -W<opt>'s are supported.
-  if (args.hasArg(clang::driver::options::OPT_W_Joined)) {
-    const auto &wArgs =
-        args.getAllArgValues(clang::driver::options::OPT_W_Joined);
-    for (const auto &wArg : wArgs) {
-      if (wArg == "error") {
-        res.setWarnAsErr(true);
-      } else {
-        const unsigned diagID =
-            diags.getCustomDiagID(clang::DiagnosticsEngine::Error,
-                                  "Only `-Werror` is supported currently.");
-        diags.Report(diagID);
-      }
-    }
+  // Handle warning Diagnostic for the frontend.
+  clang::DiagnosticOptions &diagOpts = res.getDiagnosticOpts();
+  for (const auto &warning : diagOpts.Warnings) {
+    if (warning == "error")
+      res.setWarnAsErr(true);
   }
 
   // Default to off for `flang -fc1`.
@@ -1030,6 +1037,7 @@ static bool parseDialectArgs(CompilerInvocation &res, llvm::opt::ArgList &args,
   if (args.hasArg(clang::driver::options::OPT_pedantic)) {
     res.setEnableConformanceChecks();
     res.setEnableUsageChecks();
+    res.getDiagnosticOpts().Pedantic = true;
   }
 
   // -w
@@ -1650,12 +1658,12 @@ void CompilerInvocation::setFortranOpts() {
 std::unique_ptr<Fortran::semantics::SemanticsContext>
 CompilerInvocation::getSemanticsCtx(
     Fortran::parser::AllCookedSources &allCookedSources,
-    const llvm::TargetMachine &targetMachine) {
+    const llvm::TargetMachine &targetMachine, clang::DiagnosticsEngine &diags) {
   auto &fortranOptions = getFortranOpts();
 
   auto semanticsContext = std::make_unique<semantics::SemanticsContext>(
       getDefaultKinds(), fortranOptions.features, getLangOpts(),
-      allCookedSources);
+      allCookedSources, diags);
 
   semanticsContext->set_moduleDirectory(getModuleDir())
       .set_searchDirectories(fortranOptions.searchDirectories)
diff --git a/flang/lib/Frontend/Warnings.cpp b/flang/lib/Frontend/Warnings.cpp
new file mode 100644
index 0000000000000..70e93efdd866d
--- /dev/null
+++ b/flang/lib/Frontend/Warnings.cpp
@@ -0,0 +1,102 @@
+//===--- Warnings.cpp -----------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// Command line warning options handler.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is responsible for handling all warning options. This includes
+// a number of -Wfoo options and their variants, which are driven by TableGen-
+// generated data, and the special cases -pedantic, -pedantic-errors, -w,
+// -Werror, ...
+//
+// Each warning option controls any number of actual warnings.
+// Given a warning option 'foo', the following are valid:
+//    -Wfoo, -Wno-foo, -Werror=foo
+//
+#include "clang/Basic/AllDiagnostics.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/DiagnosticDriver.h"
+#include "clang/Basic/DiagnosticIDs.h"
+#include "clang/Basic/DiagnosticOptions.h"
+#include "llvm/ADT/StringRef.h"
+#include <cstring>
+
+namespace Fortran::frontend {
+
+// EmitUnknownDiagWarning - Emit a warning and typo hint for unknown warning
+// opts
+
+static void EmitUnknownDiagWarning(clang::DiagnosticsEngine &diags,
+                                   clang::diag::Flavor flavor,
+                                   llvm::StringRef prefix,
+                                   llvm::StringRef opt) {
+  llvm::StringRef suggestion =
+      clang::DiagnosticIDs::getNearestOption(flavor, opt);
+  diags.Report(clang::diag::warn_unknown_diag_option)
+      << (flavor == clang::diag::Flavor::WarningOrError ? 0 : 1)
+      << (prefix.str() += std::string(opt)) << !suggestion.empty()
+      << (prefix.str() += std::string(suggestion));
+}
+
+void processWarningOptions(clang::DiagnosticsEngine &diags,
+                           const clang::DiagnosticOptions &opts) {
+  diags.setIgnoreAllWarnings(opts.IgnoreWarnings);
+  diags.setShowColors(opts.ShowColors);
+
+  // If -pedantic or -pedantic-errors was specified, then we want to map all
+  // extension diagnostics onto WARNING or ERROR.
+  if (opts.PedanticErrors)
+    diags.setExtensionHandlingBehavior(clang::diag::Severity::Error);
+  else if (opts.Pedantic)
+    diags.setExtensionHandlingBehavior(clang::diag::Severity::Warning);
+  else
+    diags.setExtensionHandlingBehavior(clang::diag::Severity::Ignored);
+
+  llvm::SmallVector<clang::diag::kind, 10> _diags;
+  const llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs> diagIDs =
+      diags.getDiagnosticIDs();
+  for (unsigned i = 0, e = opts.Warnings.size(); i != e; ++i) {
+    const auto flavor = clang::diag::Flavor::WarningOrError;
+    llvm::StringRef opt = opts.Warnings[i];
+
+    // Check to see if this warning starts with "no-", if so, this is a
+    // negative form of the option.
+    bool isPositive = !opt.consume_front("no-");
+
+    // Figure out how this option affects the warning.  If -Wfoo, map the
+    // diagnostic to a warning, if -Wno-foo, map it to ignore.
+    clang::diag::Severity mapping = isPositive ? clang::diag::Severity::Warning
+                                               : clang::diag::Severity::Ignored;
+
+    // -Werror/-Wno-error is a special case, not controlled by the option table.
+    // TODO: Adding support of "specifier" form of -Werror=foo.
+    if (opt == "error") {
+      diags.setWarningsAsErrors(isPositive);
+      continue;
+    }
+
+    if (std::optional<clang::diag::Group> group =
+            diagIDs->getGroupForWarningOption(opt)) {
+      if (!diagIDs->isFlangWarningOption(group.value())) {
+        // Warning option not supported by Flang
+        // FIXME : Updating diagnostic error message when all warning options
+        // will be supported
+        const unsigned diagID =
+            diags.getCustomDiagID(clang::DiagnosticsEngine::Error,
+                                  "Warning option \"%0\" not supported.");
+        diags.Report(diagID) << opt;
+      }
+    } else {
+      // Unkown warning option.
+      EmitUnknownDiagWarning(diags, flavor, isPositive ? "-W" : "-Wno-", opt);
+    }
+    diags.setSeverityForGroup(flavor, opt, mapping);
+  }
+}
+} // namespace Fortran::frontend
diff --git a/flang/lib/Semantics/CMakeLists.txt b/flang/lib/Semantics/CMakeLists.txt
index 93bf0c7c5facd..90c34d9a8766c 100644
--- a/flang/lib/Semantics/CMakeLists.txt
+++ b/flang/lib/Semantics/CMakeLists.txt
@@ -63,4 +63,7 @@ add_flang_library(FortranSemantics
   FrontendOpenMP
   FrontendOpenACC
   TargetParser
+
+  CLANG_LIBS
+  clangBasic
 )
diff --git a/flang/lib/Semantics/semantics.cpp b/flang/lib/Semantics/semantics.cpp
index 10a01039ea0ae..4b4293e7eb006 100644
--- a/flang/lib/Semantics/semantics.cpp
+++ b/flang/lib/Semantics/semantics.cpp
@@ -346,9 +346,9 @@ SemanticsContext::SemanticsContext(
     const common::IntrinsicTypeDefaultKinds &defaultKinds,
     const common::LanguageFeatureControl &languageFeatures,
     const common::LangOptions &langOpts,
-    parser::AllCookedSources &allCookedSources)
+    parser::AllCookedSources &allCookedSources, clang::DiagnosticsEngine &diags)
     : defaultKinds_{defaultKinds}, languageFeatures_{languageFeatures},
-      langOpts_{langOpts}, allCookedSources_{allCookedSources},
+      langOpts_{langOpts}, allCookedSources_{allCookedSources}, diags_{diags},
       intrinsics_{evaluate::IntrinsicProcTable::Configure(defaultKinds_)},
       globalScope_{*this}, intrinsicModulesScope_{globalScope_.MakeScope(
                                Scope::Kind::IntrinsicModules, nullptr)},
diff --git a/flang/test/Driver/w-arg-unknown.f90 b/flang/test/Driver/w-arg-unknown.f90
new file mode 100644
index 0000000000000..19b39f6cb3b33
--- /dev/null
+++ b/flang/test/Driver/w-arg-unknown.f90
@@ -0,0 +1,7 @@
+! Ensure that unknown warning options generate a warning message. 
+
+! RUN: %flang_fc1 -fsyntax-only -WX %s  2>&1 | FileCheck %s --check-prefix=UNKNOWN1
+! RUN: %flang_fc1 -fsyntax-only -Werror2 %s  2>&1 | FileCheck %s --check-prefix=UNKNOWN2
+
+! UNKNOWN1: unknown warning option '-WX'
+! UNKNOWN2: unknown warning option '-Werror2'
diff --git a/flang/test/Driver/werror-wrong.f90 b/flang/test/Driver/werror-wrong.f90
deleted file mode 100644
index 58adf6f745d5e..0000000000000
--- a/flang/test/Driver/werror-wrong.f90
+++ /dev/null
@@ -1,6 +0,0 @@
-! Ensure that only argument -Werror is supported.
-
-! RUN: not %flang_fc1 -fsyntax-only -Wall %s  2>&1 | FileCheck %s --check-prefix=WRONG
-! RUN: not %flang_fc1 -fsyntax-only -WX %s  2>&1 | FileCheck %s --check-prefix=WRONG
-
-! WRONG: Only `-Werror` is supported currently.
diff --git a/flang/test/Driver/wextra-ok.f90 b/flang/test/Driver/wextra-ok.f90
index 441029aa0af27..63c18c3ad2b12 100644
--- a/flang/test/Driver/wextra-ok.f90
+++ b/flang/test/Driver/wextra-ok.f90
@@ -2,10 +2,10 @@
 ! The first check should be changed if -Wextra is implemented
 
 ! RUN: %flang -std=f2018 -Wextra %s -c 2>&1 | FileCheck %s --check-prefix=CHECK-OK
-! RUN: not %flang -std=f2018 -Wblah -Wextra %s -c 2>&1 | FileCheck %s --check-prefix=WRONG
+! RUN: %flang -std=f2018 -Wblah -Wextra %s -c 2>&1 | FileCheck %s --check-prefix=WRONG
 
 ! CHECK-OK: the warning option '-Wextra' is not supported
-! WRONG: Only `-Werror` is supported currently.
+! WRONG: unknown warning option '-Wblah' 
 
 program wextra_ok
 end program wextra_ok
diff --git a/flang/tools/bbc/CMakeLists.txt b/flang/tools/bbc/CMakeLists.txt
index f950f03920d3f..7c6ac4220ca33 100644
--- a/flang/tools/bbc/CMakeLists.txt
+++ b/flang/tools/bbc/CMakeLists.txt
@@ -31,6 +31,11 @@ target_link_libraries(bbc PRIVATE
   FlangOpenMPTransforms
 )
 
+clang_target_link_libraries(bbc PRIVATE
+  PRIVATE
+  clangBasic
+)
+
 mlir_target_link_libraries(bbc PRIVATE
   ${dialect_libs}
   ${extension_libs}
diff --git a/flang/tools/bbc/bbc.cpp b/flang/tools/bbc/bbc.cpp
index 3b19a1c2a78d9..0a07eee2da839 100644
--- a/flang/tools/bbc/bbc.cpp
+++ b/flang/tools/bbc/bbc.cpp
@@ -15,7 +15,10 @@
 //===----------------------------------------------------------------------===//
 
 #include "flang/Frontend/CodeGenOptions.h"
+#include "flang/Frontend/CompilerInstance.h"
+#include "flang/Frontend/CompilerInvocation.h"
 #include "flang/Frontend/TargetOptions.h"
+#include "flang/Frontend/TextDiagnosticBuffer.h"
 #include "flang/Lower/Bridge.h"
 #include "flang/Lower/PFTBuilder.h"
 #include "flang/Lower/Support/Verifier.h"
@@ -492,6 +495,15 @@ static llvm::LogicalResult convertFortranSourceToMLIR(
 }
 
 int main(int argc, char **argv) {
+  // Creating a SemanticsContext require a DiagnosticsEngine
+  Fortran::frontend::TextDiagnosticBuffer *diagsBuffer =
+      new Fortran::frontend::TextDiagnosticBuffer;
+  llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs> diagID(
+      new clang::DiagnosticIDs());
+  llvm::IntrusiveRefCntPtr<clang::DiagnosticOptions> diagOpts =
+      new clang::DiagnosticOptions();
+  clang::DiagnosticsEngine diags(diagID, &*diagOpts, diagsBuffer);
+
   [[maybe_unused]] llvm::InitLLVM y(argc, argv);
   llvm::InitializeAllTargets();
   llvm::InitializeAllTargetMCs();
@@ -573,7 +585,7 @@ int main(int argc, char **argv) {
   Fortran::parser::AllSources allSources;
   Fortran::parser::AllCookedSources allCookedSources(allSources);
   Fortran::semantics::SemanticsContext semanticsContext{
-      defaultKinds, options.features, langOpts, allCookedSources};
+      defaultKinds, options.features, langOpts, allCookedSources, diags};
   semanticsContext.set_moduleDirectory(moduleDir)
       .set_moduleFileSuffix(moduleSuffix)
       .set_searchDirectories(includeDirs)
diff --git a/flang/tools/flang-driver/driver.cpp b/flang/tools/flang-driver/driver.cpp
index ed52988feaa59..a6c616289f28a 100644
--- a/flang/tools/flang-driver/driver.cpp
+++ b/flang/tools/flang-driver/driver.cpp
@@ -115,12 +115,20 @@ int main(int argc, const char **argv) {
 
   // Create DiagnosticsEngine for the compiler driver
   llvm::IntrusiveRefCntPtr<clang::DiagnosticOptions> diagOpts =
-      createAndPopulateDiagOpts(args);
+      new clang::DiagnosticOptions();
   llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs> diagID(
       new clang::DiagnosticIDs());
   Fortran::frontend::TextDiagnosticPrinter *diagClient =
       new Fortran::frontend::TextDiagnosticPrinter(llvm::errs(), &*diagOpts);
 
+  // Use the DiagnosticsEngine instance of the frontend driver
+  // for parsing the arguments
+  unsigned missingArgIndex, missingArgCount;
+  llvm::opt::InputArgList args2 = clang::driver::getDriverOptTable().ParseArgs(
+      args, missingArgIndex, missingArgCount,
+      llvm::opt::Visibility(clang::driver::options::FlangOption));
+  Fortran::frontend::parseDiagnosticArgs(*diagOpts, args2);
+
   diagClient->setPrefix(
       std::string(llvm::sys::path::stem(getExecutablePath(args[0]))));
 
diff --git a/flang/tools/flang-driver/fc1_main.cpp b/flang/tools/flang-driver/fc1_main.cpp
index 561a0dd5524e3..af98d8b0c6993 100644
--- a/flang/tools/flang-driver/fc1_main.cpp
+++ b/flang/tools/flang-driver/fc1_main.cpp
@@ -20,6 +20,7 @@
 #include "flang/Frontend/CompilerInvocation.h"
 #include "flang/Frontend/TextDiagnosticBuffer.h"
 #include "flang/FrontendTool/Utils.h"
+#include "clang/Driver/Driver.h"
 #include "clang/Driver/DriverDiagnostic.h"
 #include "llvm/MC/TargetRegistry.h"
 #include "llvm/Option/Arg.h"
@@ -63,15 +64,17 @@ int fc1_main(llvm::ArrayRef<const char *> argv, const char *argv0) {
   // them using a well formed diagnostic object.
   TextDiagnosticBuffer *diagsBuffer = new TextDiagnosticBuffer;
 
-  // Create CompilerInvocation - use a dedicated instance of DiagnosticsEngine
+  // Use the DiagnosticsEngine instance of the frontend driver
   // for parsing the arguments
-  llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs> diagID(
-      new clang::DiagnosticIDs());
-  llvm::IntrusiveRefCntPtr<clang::DiagnosticOptions> diagOpts =
-      new clang::DiagnosticOptions();
-  clang::DiagnosticsEngine diags(diagID, &*diagOpts, diagsBuffer);
-  bool success = CompilerInvocation::createFromArgs(flang->getInvocation(),
-                                                    argv, diags, argv0);
+  unsigned missingArgIndex, missingArgCount;
+  llvm::opt::InputArgList args = clang::driver::getDriverOptTable().ParseArgs(
+      argv.slice(0), missingArgIndex, missingArgCount,
+      llvm::opt::Visibility(clang::driver::options::FC1Option));
+  parseDiagnosticArgs(flang->getDiagnosticOpts(), args, false);
+
+  bool success = CompilerInvocation::createFromArgs(
+      flang->getInvocation(), argv, flang->getDiagnostics(), argv0);
+  processWarningOptions(flang->getDiagnostics(), flang->getDiagnosticOpts());
 
   // Initialize targets first, so that --version shows registered targets.
   llvm::InitializeAllTargets();