[flang-commits] [flang] [Flang] Support -Werror=<name> and -Wno-error=<name> (PR #205413)

Steve Scalpone via flang-commits flang-commits at lists.llvm.org
Mon Jun 29 03:53:36 PDT 2026


https://github.com/sscalpone updated https://github.com/llvm/llvm-project/pull/205413

>From b755de484134d144473b0dbb16cf954d0b1d30b7 Mon Sep 17 00:00:00 2001
From: Steve Scalpone <sscalpone at nvidia.com>
Date: Tue, 23 Jun 2026 12:19:32 -0700
Subject: [PATCH] [Flang] Support -Werror=<name> and -Wno-error=<name>

Allow per-warning control of warnings-as-errors, matching Clang/GCC
behavior. Global -Werror and -Wno-error continue to work; individual
Flang warning groups can be promoted or exempted with -Werror=<name>
and -Wno-error=<name>.
parseDiagArgs no longer rejects these options when they target Clang
diagnostic groups (e.g. -Wno-error=experimental-option for OpenMP).
---
 flang/docs/FlangDriver.md                     | 17 ++++--
 flang/docs/ReleaseNotes.md                    |  2 +-
 flang/include/flang/Parser/message.h          |  3 +-
 .../include/flang/Support/Fortran-features.h  | 12 +++++
 flang/lib/Frontend/CompilerInvocation.cpp     | 26 +++++++---
 flang/lib/Frontend/FrontendAction.cpp         |  3 +-
 flang/lib/Frontend/ParserActions.cpp          |  5 +-
 flang/lib/Parser/message.cpp                  | 31 ++++++-----
 flang/lib/Semantics/semantics.cpp             |  2 +-
 flang/lib/Support/Fortran-features.cpp        | 49 +++++++++++++++++
 .../Driver/Inputs/werror-unknown-scanning.f90 |  2 +
 flang/test/Driver/werror-unknown.f90          | 30 +++++++++++
 flang/test/Driver/wno-error.f90               | 52 +++++++++++++++++++
 .../unittests/Common/FortranFeaturesTest.cpp  | 15 ++++++
 14 files changed, 220 insertions(+), 29 deletions(-)
 create mode 100644 flang/test/Driver/Inputs/werror-unknown-scanning.f90
 create mode 100644 flang/test/Driver/werror-unknown.f90
 create mode 100644 flang/test/Driver/wno-error.f90

diff --git a/flang/docs/FlangDriver.md b/flang/docs/FlangDriver.md
index 4edc99944ad44..69eaed8108408 100644
--- a/flang/docs/FlangDriver.md
+++ b/flang/docs/FlangDriver.md
@@ -601,9 +601,20 @@ floating point and so always acts as though these flags were specified.
 GCC/GFortran will also set flush-to-zero mode: linking `crtfastmath.o`, the same
 as Flang.
 
-The only GCC/GFortran warning option currently supported is `-Werror`.  Passing
-any unsupported GCC/GFortran warning flags into Flang's compiler driver will
-result in warnings being emitted.
+Flang supports a subset of GCC/GFortran and Clang warning options.  The
+`-Werror` flag causes all warnings to become errors.  `-Wno-error` disables
+that behavior.  Per-warning control is also available: `-Werror=<name>` promotes
+a specific warning group to an error (even without global `-Werror`), and
+`-Wno-error=<name>` keeps that group as a warning even when `-Werror` is in
+effect.  For example, `-Werror -Wno-error=experimental-option` still emits
+OpenMP experimental-feature warnings but does not fail the compilation because
+of them.
+
+Flang-specific warnings (such as `-Wportability` or `-Wunused-variable`) use
+Flang warning group names.  Some diagnostics (including OpenMP
+`-Wexperimental-option`) are handled by Clang's diagnostic engine and use the
+same spellings.  Passing unsupported GCC/GFortran warning flags into Flang's
+compiler driver will result in warnings being emitted.
 
 ### Comparison with nvfortran
 nvfortran defines `-fast` as
diff --git a/flang/docs/ReleaseNotes.md b/flang/docs/ReleaseNotes.md
index 0ccb34be20571..a9e31d59a115f 100644
--- a/flang/docs/ReleaseNotes.md
+++ b/flang/docs/ReleaseNotes.md
@@ -36,7 +36,7 @@ page](https://llvm.org/releases/).
 ## New Compiler Flags
 
 - The warning flags with prefixes -Wopen-mp and -Wopen-acc have been deprecated in favor of corrected spellings with the respective prefixes -Wopenmp and -Wopenacc. Removal of the deprecated options is planned for LLVM 25 (July 2027).
-- The `-Werror` flag will cause all warnings to become errors. This includes warnings about support for OpenMP versions, which will now prevent the compilation from happening with the `-Werror` flag. These OpenMP warnings can be disabled with `-Wno-experimental-option`.
+- The `-Werror` flag will cause all warnings to become errors. This includes warnings about support for OpenMP versions, which will now prevent the compilation from happening with the `-Werror` flag. These OpenMP warnings can be downgraded back to warnings with `-Wno-error=experimental-option`, or disabled entirely with `-Wno-experimental-option`.
 
 ## Windows Support
 
diff --git a/flang/include/flang/Parser/message.h b/flang/include/flang/Parser/message.h
index c70c335133ba8..ebb5b4353035d 100644
--- a/flang/include/flang/Parser/message.h
+++ b/flang/include/flang/Parser/message.h
@@ -380,7 +380,8 @@ class Messages {
       const common::LanguageFeatureControl *hintFlags = nullptr,
       std::size_t maxErrorsToEmit = 0, bool warningsAreErrors = false) const;
   void AttachTo(Message &, std::optional<Severity> = std::nullopt);
-  bool AnyFatalError(bool warningsAreErrors = false) const;
+  bool AnyFatalError(bool warningsAreErrors = false,
+      const common::LanguageFeatureControl *control = nullptr) const;
 
 private:
   template <typename... A>
diff --git a/flang/include/flang/Support/Fortran-features.h b/flang/include/flang/Support/Fortran-features.h
index ebc6f495e59ba..82516ed14610a 100644
--- a/flang/include/flang/Support/Fortran-features.h
+++ b/flang/include/flang/Support/Fortran-features.h
@@ -11,6 +11,7 @@
 
 #include "Fortran.h"
 #include "flang/Common/enum-set.h"
+#include <optional>
 #include <string_view>
 #include <vector>
 
@@ -140,6 +141,13 @@ class LanguageFeatureControl {
   // Take a string from the Cli and apply it to the LanguageFeatureControl.
   // Return true if the option was recognized (and hence applied).
   bool EnableWarning(std::string_view input);
+  // Apply -Werror=<name> or -Wno-error=<name> to a Flang warning group.
+  // Return true if the option was recognized.
+  bool SetWarningErrorTreatment(std::string_view specifier, bool asError);
+  // Return true if a non-fatal diagnostic should be treated as an error.
+  bool ShouldPromoteWarningToError(bool globalWarnAsErr,
+      std::optional<LanguageFeature> languageFeature,
+      std::optional<UsageWarning> usageWarning) const;
   // The add and replace functions are not currently used but are provided
   // to allow a flexible many-to-one mapping from Cli spellings to enum values.
   // Taking a string by value because the functions own this string after the
@@ -193,6 +201,10 @@ class LanguageFeatureControl {
   bool warnAllLanguage_{false};
   UsageWarnings warnUsage_;
   bool warnAllUsage_{false};
+  LanguageFeatures warnAsErrorLanguage_;
+  UsageWarnings warnAsErrorUsage_;
+  LanguageFeatures warnNotAsErrorLanguage_;
+  UsageWarnings warnNotAsErrorUsage_;
   bool disableAllWarnings_{false};
 };
 } // namespace Fortran::common
diff --git a/flang/lib/Frontend/CompilerInvocation.cpp b/flang/lib/Frontend/CompilerInvocation.cpp
index 14cb5af7c81e5..61bad89c116a6 100644
--- a/flang/lib/Frontend/CompilerInvocation.cpp
+++ b/flang/lib/Frontend/CompilerInvocation.cpp
@@ -1062,17 +1062,31 @@ static bool parseDiagArgs(CompilerInvocation &res, llvm::opt::ArgList &args,
   }
 
   // -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::options::OPT_W_Joined)) {
     const auto &wArgs = args.getAllArgValues(clang::options::OPT_W_Joined);
     // TODO: Consider using std::string_view instead of llvm::StringRef
     // when moving to C++20:
     for (const llvm::StringRef wArg : wArgs) {
-      if (wArg == "error") {
-        res.setWarnAsErr(true);
-        // -Wfatal-errors
-      } else if (wArg == "fatal-errors") {
+      llvm::StringRef opt{wArg};
+      const bool isPositive{!opt.consume_front("no-")};
+      if (opt.starts_with("error")) {
+        if (opt.size() == 5) {
+          res.setWarnAsErr(isPositive);
+        } else if (opt.size() > 6 && opt[5] == '=') {
+          const llvm::StringRef specifier{opt.substr(6)};
+          if (!features.SetWarningErrorTreatment(specifier, isPositive)) {
+            // Unknown Flang warning groups are handled by Clang's
+            // ProcessWarningOptions (e.g. -Wno-error=experimental-option).
+          }
+        } else {
+          const unsigned diagID =
+              diags.getCustomDiagID(clang::DiagnosticsEngine::Error,
+                                    "Unknown diagnostic option: -W%0");
+          diags.Report(diagID) << wArg;
+        }
+        continue;
+      }
+      if (opt == "fatal-errors") {
         res.setMaxErrors(1);
         // -W[no-]<feature>
       } else if (features.EnableWarning(wArg)) {
diff --git a/flang/lib/Frontend/FrontendAction.cpp b/flang/lib/Frontend/FrontendAction.cpp
index 7d201881cbba7..6f0b1c6904a21 100644
--- a/flang/lib/Frontend/FrontendAction.cpp
+++ b/flang/lib/Frontend/FrontendAction.cpp
@@ -232,7 +232,8 @@ bool FrontendAction::reportFatalErrors(const char (&message)[N]) {
       instance->getInvocation().getFortranOpts().features};
   const size_t maxErrors{instance->getInvocation().getMaxErrors()};
   const bool warningsAreErrors{instance->getInvocation().getWarnAsErr()};
-  if (instance->getParsing().messages().AnyFatalError(warningsAreErrors)) {
+  if (instance->getParsing().messages().AnyFatalError(warningsAreErrors,
+                                                      &features)) {
     const unsigned diagID = instance->getDiagnostics().getCustomDiagID(
         clang::DiagnosticsEngine::Error, message);
     instance->getDiagnostics().Report(diagID) << getCurrentFileOrBufferName();
diff --git a/flang/lib/Frontend/ParserActions.cpp b/flang/lib/Frontend/ParserActions.cpp
index 1722c7a9cf9d0..f191623b38c03 100644
--- a/flang/lib/Frontend/ParserActions.cpp
+++ b/flang/lib/Frontend/ParserActions.cpp
@@ -96,8 +96,9 @@ void debugMeasureParseTree(CompilerInstance &ci, llvm::StringRef filename) {
   if ((ci.getParsing().parseTree().has_value() &&
        !ci.getParsing().consumedWholeFile()) ||
       (!ci.getParsing().messages().empty() &&
-       (ci.getInvocation().getWarnAsErr() ||
-        ci.getParsing().messages().AnyFatalError()))) {
+       ci.getParsing().messages().AnyFatalError(
+           ci.getInvocation().getWarnAsErr(),
+           &ci.getInvocation().getFortranOpts().features))) {
     unsigned diagID = ci.getDiagnostics().getCustomDiagID(
         clang::DiagnosticsEngine::Error, "Could not parse %0");
     ci.getDiagnostics().Report(diagID) << filename;
diff --git a/flang/lib/Parser/message.cpp b/flang/lib/Parser/message.cpp
index d68489a192081..e9964cd28866a 100644
--- a/flang/lib/Parser/message.cpp
+++ b/flang/lib/Parser/message.cpp
@@ -169,6 +169,19 @@ bool Message::SortBefore(const Message &that) const {
       location_, that.location_);
 }
 
+static bool ShouldTreatMessageAsFatal(const Message &msg,
+    bool globalWarningsAreErrors,
+    const common::LanguageFeatureControl *control) {
+  if (msg.IsFatal()) {
+    return true;
+  }
+  if (control) {
+    return control->ShouldPromoteWarningToError(
+        globalWarningsAreErrors, msg.languageFeature(), msg.usageWarning());
+  }
+  return globalWarningsAreErrors;
+}
+
 bool Message::IsFatal() const { return IsFatalSeverity(severity()); }
 
 Severity Message::severity() const {
@@ -500,7 +513,7 @@ void Messages::Emit(llvm::raw_ostream &o, const AllCookedSources &allCooked,
     }
     msgsWithLastLocation.push_back(msg);
     msg->Emit(o, allCooked, echoSourceLines, hintFlagPtr);
-    if (warningsAreErrors || msg->IsFatal()) {
+    if (ShouldTreatMessageAsFatal(*msg, warningsAreErrors, hintFlagPtr)) {
       ++errorsEmitted;
     }
     // If maxErrorsToEmit is 0, emit all errors, otherwise break after
@@ -522,20 +535,10 @@ void Messages::AttachTo(Message &msg, std::optional<Severity> severity) {
   messages_.clear();
 }
 
-bool Messages::AnyFatalError(bool warningsAreErrors) const {
-  // Short-circuit in the most common case.
-  if (messages_.empty()) {
-    return false;
-  }
-  // If warnings are errors and there are warnings or errors, this is fatal.
-  // This preserves the compiler's current behavior of treating any non-fatal
-  // message as a warning. We may want to refine this in the future.
-  if (warningsAreErrors) {
-    return true;
-  }
-  // Otherwise, check the message buffer for fatal errors.
+bool Messages::AnyFatalError(bool warningsAreErrors,
+    const common::LanguageFeatureControl *control) const {
   for (const auto &msg : messages_) {
-    if (msg.IsFatal()) {
+    if (ShouldTreatMessageAsFatal(msg, warningsAreErrors, control)) {
       return true;
     }
   }
diff --git a/flang/lib/Semantics/semantics.cpp b/flang/lib/Semantics/semantics.cpp
index 33c54c81f8abd..2e4daef8f807c 100644
--- a/flang/lib/Semantics/semantics.cpp
+++ b/flang/lib/Semantics/semantics.cpp
@@ -416,7 +416,7 @@ const DeclTypeSpec &SemanticsContext::MakeLogicalType(int kind) {
 }
 
 bool SemanticsContext::AnyFatalError() const {
-  return messages_.AnyFatalError(warningsAreErrors_);
+  return messages_.AnyFatalError(warningsAreErrors_, &languageFeatures_);
 }
 bool SemanticsContext::HasError(const Symbol &symbol) {
   return errorSymbols_.count(symbol) > 0;
diff --git a/flang/lib/Support/Fortran-features.cpp b/flang/lib/Support/Fortran-features.cpp
index a8fa4ac4a7afe..4abf53e35272a 100644
--- a/flang/lib/Support/Fortran-features.cpp
+++ b/flang/lib/Support/Fortran-features.cpp
@@ -259,6 +259,55 @@ bool LanguageFeatureControl::EnableWarning(std::string_view input) {
   return false;
 }
 
+bool LanguageFeatureControl::SetWarningErrorTreatment(
+    std::string_view specifier, bool asError) {
+  if (auto warning{FindWarning(specifier)}) {
+    if (std::holds_alternative<LanguageFeature>(warning->first)) {
+      auto feature{std::get<LanguageFeature>(warning->first)};
+      if (asError) {
+        warnNotAsErrorLanguage_.reset(feature);
+        warnAsErrorLanguage_.set(feature);
+      } else {
+        warnAsErrorLanguage_.reset(feature);
+        warnNotAsErrorLanguage_.set(feature);
+      }
+    } else {
+      auto usageWarning{std::get<UsageWarning>(warning->first)};
+      if (asError) {
+        warnNotAsErrorUsage_.reset(usageWarning);
+        warnAsErrorUsage_.set(usageWarning);
+      } else {
+        warnAsErrorUsage_.reset(usageWarning);
+        warnNotAsErrorUsage_.set(usageWarning);
+      }
+    }
+    return true;
+  }
+  return false;
+}
+
+bool LanguageFeatureControl::ShouldPromoteWarningToError(bool globalWarnAsErr,
+    std::optional<LanguageFeature> languageFeature,
+    std::optional<UsageWarning> usageWarning) const {
+  if (languageFeature) {
+    if (warnNotAsErrorLanguage_.test(*languageFeature)) {
+      return false;
+    }
+    if (warnAsErrorLanguage_.test(*languageFeature)) {
+      return true;
+    }
+  }
+  if (usageWarning) {
+    if (warnNotAsErrorUsage_.test(*usageWarning)) {
+      return false;
+    }
+    if (warnAsErrorUsage_.test(*usageWarning)) {
+      return true;
+    }
+  }
+  return globalWarnAsErr;
+}
+
 void LanguageFeatureControl::ReplaceCliCanonicalSpelling(
     LanguageFeature f, std::string input) {
   cliOptions_.erase(languageFeatureCliCanonicalSpelling_[EnumToInt(f)]);
diff --git a/flang/test/Driver/Inputs/werror-unknown-scanning.f90 b/flang/test/Driver/Inputs/werror-unknown-scanning.f90
new file mode 100644
index 0000000000000..6aba8346a6f9c
--- /dev/null
+++ b/flang/test/Driver/Inputs/werror-unknown-scanning.f90
@@ -0,0 +1,2 @@
+     xy z=1
+      end
diff --git a/flang/test/Driver/werror-unknown.f90 b/flang/test/Driver/werror-unknown.f90
new file mode 100644
index 0000000000000..c049b0be11e27
--- /dev/null
+++ b/flang/test/Driver/werror-unknown.f90
@@ -0,0 +1,30 @@
+! Verify unknown, malformed, and -Werror= / -Wno-error= for another warning group.
+!
+! Unknown Flang groups fall through to Clang's ProcessWarningOptions and are
+! accepted without "Unknown diagnostic option". Malformed -Werror= is rejected.
+! Scanning warnings come from -ffixed-form on %S/Inputs/werror-unknown-scanning.f90.
+
+!--- unknown Flang groups: no driver diagnostic --------------------------------
+! RUN: %flang_fc1 -fsyntax-only -Werror=not-a-flang-warning %s 2>&1 | FileCheck %s --allow-empty --check-prefix=NO-UNKNOWN
+! RUN: %flang_fc1 -fsyntax-only -Wno-error=not-a-flang-warning %s 2>&1 | FileCheck %s --allow-empty --check-prefix=NO-UNKNOWN
+
+!--- malformed -Werror= spelling -----------------------------------------------
+! RUN: not %flang_fc1 -fsyntax-only -Werror= %s 2>&1 | FileCheck %s --check-prefix=MALFORMED
+
+!--- scanning warning group ----------------------------------------------------
+! RUN: %flang_fc1 -fsyntax-only -ffixed-form %S/Inputs/werror-unknown-scanning.f90 -Werror -Wno-error=scanning 2>&1 | FileCheck %s --check-prefixes=SCAN-WARN,NO-ERROR
+! RUN: not %flang_fc1 -fsyntax-only -ffixed-form %S/Inputs/werror-unknown-scanning.f90 -Werror=scanning 2>&1 | FileCheck %s --check-prefixes=SCAN-ERROR,SCAN-WARN
+! RUN: not %flang_fc1 -fsyntax-only -ffixed-form %S/Inputs/werror-unknown-scanning.f90 -Werror 2>&1 | FileCheck %s --check-prefixes=SCAN-ERROR,SCAN-WARN
+
+! NO-UNKNOWN-NOT: Unknown diagnostic option
+! NO-UNKNOWN-NOT: not-a-flang-warning
+
+! MALFORMED: Unknown diagnostic option: -Werror=
+
+! FileCheck scans forward: SCAN-ERROR before SCAN-WARN.
+! SCAN-ERROR: Could not scan
+! SCAN-WARN: Statement should not begin with a continuation line [-Wscanning]
+! NO-ERROR-NOT: error:
+
+program werrorUnknown
+end
diff --git a/flang/test/Driver/wno-error.f90 b/flang/test/Driver/wno-error.f90
new file mode 100644
index 0000000000000..9ab04c7856209
--- /dev/null
+++ b/flang/test/Driver/wno-error.f90
@@ -0,0 +1,52 @@
+! Verify -Werror / -Werror= / -Wno-error / -Wno-error= for Flang warning groups.
+!
+! Portability warning from -pedantic on ichar('ab').
+! Redundant-attribute warning from duplicate SAVE on integer, save, save :: x.
+! Use -Wno-redundant-attribute on portability-only runs so they stay isolated.
+
+!--- Baseline (no -pedantic) --------------------------------------------------
+! RUN: %flang_fc1 -fsyntax-only -Wno-redundant-attribute %s 2>&1 | FileCheck %s --allow-empty --check-prefix=NO-DIAG
+
+!--- -Werror=portability without -pedantic: no warning, so no error -----------
+! RUN: %flang_fc1 -fsyntax-only -Wno-redundant-attribute -Werror=portability %s 2>&1 | FileCheck %s --allow-empty --check-prefix=NO-DIAG
+
+!--- -pedantic and redundant-attribute both emit warnings --------------------
+! RUN: %flang_fc1 -fsyntax-only -pedantic %s 2>&1 | FileCheck %s --check-prefixes=PEDANTIC-WARN,REDUNDANT-WARN,NO-ERROR
+
+!--- combinations that promote the portability warning to an error ------------
+! RUN: not %flang_fc1 -fsyntax-only -pedantic -Wno-redundant-attribute -Werror %s 2>&1 | FileCheck %s --check-prefixes=IS-ERROR,PEDANTIC-WARN
+! RUN: not %flang_fc1 -fsyntax-only -pedantic -Wno-redundant-attribute -Werror=portability %s 2>&1 | FileCheck %s --check-prefixes=IS-ERROR,PEDANTIC-WARN
+! RUN: not %flang_fc1 -fsyntax-only -pedantic -Wno-redundant-attribute -Wno-error -Werror=portability %s 2>&1 | FileCheck %s --check-prefixes=IS-ERROR,PEDANTIC-WARN
+! RUN: not %flang_fc1 -fsyntax-only -pedantic -Wno-redundant-attribute -Werror -Wno-error -Werror=portability %s 2>&1 | FileCheck %s --check-prefixes=IS-ERROR,PEDANTIC-WARN
+
+!--- combinations that leave the portability warning non-fatal ----------------
+! RUN: %flang_fc1 -fsyntax-only -pedantic -Wno-redundant-attribute -Wno-error %s 2>&1 | FileCheck %s --check-prefixes=PEDANTIC-WARN,NO-ERROR
+! RUN: %flang_fc1 -fsyntax-only -pedantic -Wno-redundant-attribute -Wno-error=portability %s 2>&1 | FileCheck %s --check-prefixes=PEDANTIC-WARN,NO-ERROR
+! RUN: %flang_fc1 -fsyntax-only -pedantic -Wno-redundant-attribute -Werror -Wno-error=portability %s 2>&1 | FileCheck %s --check-prefixes=PEDANTIC-WARN,NO-ERROR
+! RUN: %flang_fc1 -fsyntax-only -pedantic -Wno-redundant-attribute -Werror -Wno-error %s 2>&1 | FileCheck %s --check-prefixes=PEDANTIC-WARN,NO-ERROR
+! RUN: %flang_fc1 -fsyntax-only -pedantic -Wno-redundant-attribute -Werror=portability -Wno-error=portability %s 2>&1 | FileCheck %s --check-prefixes=PEDANTIC-WARN,NO-ERROR
+! RUN: %flang_fc1 -fsyntax-only -pedantic -Wno-redundant-attribute -Wno-error=portability -Werror %s 2>&1 | FileCheck %s --check-prefixes=PEDANTIC-WARN,NO-ERROR
+
+!--- per-group control with both portability and redundant-attribute warnings --
+! RUN: not %flang_fc1 -fsyntax-only -pedantic -Werror -Wno-error=portability %s 2>&1 | FileCheck %s --check-prefixes=IS-ERROR,REDUNDANT-WARN
+! RUN: not %flang_fc1 -fsyntax-only -pedantic -Werror -Wno-error=redundant-attribute %s 2>&1 | FileCheck %s --check-prefixes=IS-ERROR,PEDANTIC-WARN
+! RUN: %flang_fc1 -fsyntax-only -pedantic -Werror -Wno-error=portability -Wno-error=redundant-attribute %s 2>&1 | FileCheck %s --check-prefixes=PEDANTIC-WARN,REDUNDANT-WARN,NO-ERROR
+! RUN: not %flang_fc1 -fsyntax-only -pedantic -Werror=redundant-attribute -Wno-error=portability %s 2>&1 | FileCheck %s --check-prefixes=IS-ERROR,REDUNDANT-WARN
+! RUN: not %flang_fc1 -fsyntax-only -pedantic -Werror=portability -Wno-error=redundant-attribute %s 2>&1 | FileCheck %s --check-prefixes=IS-ERROR,PEDANTIC-WARN
+
+! NO-DIAG-NOT: portability
+! NO-DIAG-NOT: warning
+! NO-DIAG-NOT: error
+
+! FileCheck scans forward: IS-ERROR before PEDANTIC-WARN; REDUNDANT-WARN before
+! PEDANTIC-WARN when both warnings appear (redundant-attribute is emitted first).
+! IS-ERROR: Semantic errors in
+! REDUNDANT-WARN: Attribute 'SAVE' cannot be used more than once [-Wredundant-attribute]
+! PEDANTIC-WARN: should have length one [-Wportability]
+! NO-ERROR-NOT: error:
+
+subroutine wnoErrorTest
+  integer, save, save :: x
+  x = 1
+  print *, ichar('ab')
+end
diff --git a/flang/unittests/Common/FortranFeaturesTest.cpp b/flang/unittests/Common/FortranFeaturesTest.cpp
index dfd88cb8abecd..53c60a82b1a86 100644
--- a/flang/unittests/Common/FortranFeaturesTest.cpp
+++ b/flang/unittests/Common/FortranFeaturesTest.cpp
@@ -563,4 +563,19 @@ TEST(FortranFeaturesTest, HintLanguageControlFlag) {
       control.getDefaultCliSpelling(UsageWarning::Portability), "portability");
 }
 
+TEST(FortranFeaturesTest, WarningErrorTreatment) {
+  LanguageFeatureControl control{};
+  EXPECT_TRUE(control.SetWarningErrorTreatment("portability", false));
+  EXPECT_FALSE(control.ShouldPromoteWarningToError(
+      /*globalWarnAsErr=*/true, std::nullopt, UsageWarning::Portability));
+  EXPECT_TRUE(control.ShouldPromoteWarningToError(
+      /*globalWarnAsErr=*/true, std::nullopt, UsageWarning::Bounds));
+
+  EXPECT_TRUE(control.SetWarningErrorTreatment("benign-name-clash", true));
+  EXPECT_TRUE(control.ShouldPromoteWarningToError(/*globalWarnAsErr=*/false,
+      LanguageFeature::BenignNameClash, std::nullopt));
+  EXPECT_FALSE(control.ShouldPromoteWarningToError(/*globalWarnAsErr=*/false,
+      LanguageFeature::RedundantAttribute, std::nullopt));
+}
+
 } // namespace Fortran::common::details



More information about the flang-commits mailing list