[flang-commits] [flang] [flang][cli] Add diagnostic flags to the CLI (PR #142022)
Andre Kuhlenschmidt via flang-commits
flang-commits at lists.llvm.org
Fri May 30 18:02:20 PDT 2025
https://github.com/akuhlens updated https://github.com/llvm/llvm-project/pull/142022
>From 8f3fd2daab46f477e87043c66b3049dff4a5b20e Mon Sep 17 00:00:00 2001
From: Andre Kuhlenschmidt <akuhlenschmi at nvidia.com>
Date: Thu, 29 May 2025 12:11:04 -0700
Subject: [PATCH 1/8] initial commit
---
flang/include/flang/Common/enum-class.h | 47 ++++-
.../include/flang/Support/Fortran-features.h | 51 ++++--
flang/lib/Frontend/CompilerInvocation.cpp | 62 ++++---
flang/lib/Support/CMakeLists.txt | 1 +
flang/lib/Support/Fortran-features.cpp | 168 ++++++++++++++----
flang/lib/Support/enum-class.cpp | 24 +++
flang/test/Driver/disable-diagnostic.f90 | 19 ++
flang/test/Driver/werror-wrong.f90 | 7 +-
flang/test/Driver/wextra-ok.f90 | 2 +-
flang/unittests/Common/CMakeLists.txt | 3 +
flang/unittests/Common/EnumClassTests.cpp | 45 +++++
.../unittests/Common/FortranFeaturesTest.cpp | 142 +++++++++++++++
12 files changed, 483 insertions(+), 88 deletions(-)
create mode 100644 flang/lib/Support/enum-class.cpp
create mode 100644 flang/test/Driver/disable-diagnostic.f90
create mode 100644 flang/unittests/Common/EnumClassTests.cpp
create mode 100644 flang/unittests/Common/FortranFeaturesTest.cpp
diff --git a/flang/include/flang/Common/enum-class.h b/flang/include/flang/Common/enum-class.h
index 41575d45091a8..baf9fe418141d 100644
--- a/flang/include/flang/Common/enum-class.h
+++ b/flang/include/flang/Common/enum-class.h
@@ -18,8 +18,9 @@
#define FORTRAN_COMMON_ENUM_CLASS_H_
#include <array>
-#include <string>
-
+#include <functional>
+#include <optional>
+#include <string_view>
namespace Fortran::common {
constexpr std::size_t CountEnumNames(const char *p) {
@@ -58,15 +59,51 @@ constexpr std::array<std::string_view, ITEMS> EnumNames(const char *p) {
return result;
}
+template <typename F, typename T>
+std::optional<T> inline fmap(std::optional<F> x, std::function<T(const F)> f) {
+ return x ? std::optional<T>{f(*x)} : std::nullopt;
+}
+
+using Predicate = std::function<bool(const std::string_view)>;
+// Finds the first index for which the predicate returns true.
+std::optional<int> FindEnumIndex(
+ Predicate pred, int size, const std::string_view *names);
+
+using FindEnumIndexType = std::optional<int>(
+ Predicate, int, const std::string_view *);
+
+template <typename NAME>
+std::optional<NAME> inline FindEnum(
+ Predicate pred, std::function<std::optional<int>(Predicate)> find) {
+ std::function<NAME(int)> f = [](int x) { return static_cast<NAME>(x); };
+ return fmap(find(pred), f);
+}
+
#define ENUM_CLASS(NAME, ...) \
enum class NAME { __VA_ARGS__ }; \
[[maybe_unused]] static constexpr std::size_t NAME##_enumSize{ \
::Fortran::common::CountEnumNames(#__VA_ARGS__)}; \
+ [[maybe_unused]] static constexpr std::array<std::string_view, \
+ NAME##_enumSize> NAME##_names{ \
+ ::Fortran::common::EnumNames<NAME##_enumSize>(#__VA_ARGS__)}; \
[[maybe_unused]] static inline std::string_view EnumToString(NAME e) { \
- static const constexpr auto names{ \
- ::Fortran::common::EnumNames<NAME##_enumSize>(#__VA_ARGS__)}; \
- return names[static_cast<std::size_t>(e)]; \
+ return NAME##_names[static_cast<std::size_t>(e)]; \
}
+#define ENUM_CLASS_EXTRA(NAME) \
+ [[maybe_unused]] inline std::optional<int> Find##NAME##Index( \
+ ::Fortran::common::Predicate p) { \
+ return ::Fortran::common::FindEnumIndex( \
+ p, NAME##_enumSize, NAME##_names.data()); \
+ } \
+ [[maybe_unused]] inline std::optional<NAME> Find##NAME( \
+ ::Fortran::common::Predicate p) { \
+ return ::Fortran::common::FindEnum<NAME>(p, Find##NAME##Index); \
+ } \
+ [[maybe_unused]] inline std::optional<NAME> StringTo##NAME( \
+ const std::string_view name) { \
+ return Find##NAME( \
+ [name](const std::string_view s) -> bool { return name == s; }); \
+ }
} // namespace Fortran::common
#endif // FORTRAN_COMMON_ENUM_CLASS_H_
diff --git a/flang/include/flang/Support/Fortran-features.h b/flang/include/flang/Support/Fortran-features.h
index e696da9042480..d5aa7357ffea0 100644
--- a/flang/include/flang/Support/Fortran-features.h
+++ b/flang/include/flang/Support/Fortran-features.h
@@ -12,6 +12,8 @@
#include "Fortran.h"
#include "flang/Common/enum-set.h"
#include "flang/Common/idioms.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/raw_ostream.h"
#include <optional>
#include <vector>
@@ -79,12 +81,13 @@ ENUM_CLASS(UsageWarning, Portability, PointerToUndefinable,
NullActualForDefaultIntentAllocatable, UseAssociationIntoSameNameSubprogram,
HostAssociatedIntentOutInSpecExpr, NonVolatilePointerToVolatile)
+// Generate default String -> Enum mapping.
+ENUM_CLASS_EXTRA(LanguageFeature)
+ENUM_CLASS_EXTRA(UsageWarning)
+
using LanguageFeatures = EnumSet<LanguageFeature, LanguageFeature_enumSize>;
using UsageWarnings = EnumSet<UsageWarning, UsageWarning_enumSize>;
-std::optional<LanguageFeature> FindLanguageFeature(const char *);
-std::optional<UsageWarning> FindUsageWarning(const char *);
-
class LanguageFeatureControl {
public:
LanguageFeatureControl();
@@ -97,8 +100,10 @@ class LanguageFeatureControl {
void EnableWarning(UsageWarning w, bool yes = true) {
warnUsage_.set(w, yes);
}
- void WarnOnAllNonstandard(bool yes = true) { warnAllLanguage_ = yes; }
- void WarnOnAllUsage(bool yes = true) { warnAllUsage_ = yes; }
+ void WarnOnAllNonstandard(bool yes = true);
+ bool IsWarnOnAllNonstandard() const { return warnAllLanguage_; }
+ void WarnOnAllUsage(bool yes = true);
+ bool IsWarnOnAllUsage() const { return warnAllUsage_; }
void DisableAllNonstandardWarnings() {
warnAllLanguage_ = false;
warnLanguage_.clear();
@@ -107,16 +112,16 @@ class LanguageFeatureControl {
warnAllUsage_ = false;
warnUsage_.clear();
}
-
- bool IsEnabled(LanguageFeature f) const { return !disable_.test(f); }
- bool ShouldWarn(LanguageFeature f) const {
- return (warnAllLanguage_ && f != LanguageFeature::OpenMP &&
- f != LanguageFeature::OpenACC && f != LanguageFeature::CUDA) ||
- warnLanguage_.test(f);
- }
- bool ShouldWarn(UsageWarning w) const {
- return warnAllUsage_ || warnUsage_.test(w);
+ void DisableAllWarnings() {
+ disableAllWarnings_ = true;
+ DisableAllNonstandardWarnings();
+ DisableAllUsageWarnings();
}
+ bool applyCLIOption(llvm::StringRef input);
+ bool AreWarningsDisabled() const { return disableAllWarnings_; }
+ bool IsEnabled(LanguageFeature f) const { return !disable_.test(f); }
+ bool ShouldWarn(LanguageFeature f) const { return warnLanguage_.test(f); }
+ bool ShouldWarn(UsageWarning w) const { return warnUsage_.test(w); }
// Return all spellings of operators names, depending on features enabled
std::vector<const char *> GetNames(LogicalOperator) const;
std::vector<const char *> GetNames(RelationalOperator) const;
@@ -127,6 +132,24 @@ class LanguageFeatureControl {
bool warnAllLanguage_{false};
UsageWarnings warnUsage_;
bool warnAllUsage_{false};
+ bool disableAllWarnings_{false};
};
+
+// Parse a CLI enum option return the enum index and whether it should be
+// enabled (true) or disabled (false). Just exposed for the template below.
+std::optional<std::pair<bool, int>> parseCLIEnumIndex(
+ llvm::StringRef input, std::function<std::optional<int>(Predicate)> find);
+
+template <typename ENUM>
+std::optional<std::pair<bool, ENUM>> parseCLIEnum(
+ llvm::StringRef input, std::function<std::optional<int>(Predicate)> find) {
+ using To = std::pair<bool, ENUM>;
+ using From = std::pair<bool, int>;
+ static std::function<To(From)> cast = [](From x) {
+ return std::pair{x.first, static_cast<ENUM>(x.second)};
+ };
+ return fmap(parseCLIEnumIndex(input, find), cast);
+}
+
} // namespace Fortran::common
#endif // FORTRAN_SUPPORT_FORTRAN_FEATURES_H_
diff --git a/flang/lib/Frontend/CompilerInvocation.cpp b/flang/lib/Frontend/CompilerInvocation.cpp
index ba2531819ee5e..9ea568549bd6c 100644
--- a/flang/lib/Frontend/CompilerInvocation.cpp
+++ b/flang/lib/Frontend/CompilerInvocation.cpp
@@ -34,6 +34,7 @@
#include "llvm/Option/ArgList.h"
#include "llvm/Option/OptTable.h"
#include "llvm/Support/CodeGen.h"
+#include "llvm/Support/Error.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/FileUtilities.h"
#include "llvm/Support/Path.h"
@@ -45,6 +46,7 @@
#include <cstdlib>
#include <memory>
#include <optional>
+#include <string>
using namespace Fortran::frontend;
@@ -971,10 +973,23 @@ static bool parseSemaArgs(CompilerInvocation &res, llvm::opt::ArgList &args,
/// Parses all diagnostics related arguments and populates the variables
/// options accordingly. Returns false if new errors are generated.
+/// FC1 driver entry point for parsing diagnostic arguments.
static bool parseDiagArgs(CompilerInvocation &res, llvm::opt::ArgList &args,
clang::DiagnosticsEngine &diags) {
unsigned numErrorsBefore = diags.getNumErrors();
+ auto &features = res.getFrontendOpts().features;
+ // The order of these flags (-pedantic -W<feature> -w) is important and is
+ // chosen to match clang's behavior.
+
+ // -pedantic
+ if (args.hasArg(clang::driver::options::OPT_pedantic)) {
+ features.WarnOnAllNonstandard();
+ features.WarnOnAllUsage();
+ res.setEnableConformanceChecks();
+ res.setEnableUsageChecks();
+ }
+
// -Werror option
// TODO: Currently throws a Diagnostic for anything other than -W<error>,
// this has to change when other -W<opt>'s are supported.
@@ -984,21 +999,27 @@ static bool parseDiagArgs(CompilerInvocation &res, llvm::opt::ArgList &args,
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);
+ // -W(no-)<feature>
+ } else if (!features.applyCLIOption(wArg)) {
+ const unsigned diagID = diags.getCustomDiagID(
+ clang::DiagnosticsEngine::Error, "Unknown diagnostic option: -W%0");
+ diags.Report(diagID) << wArg;
}
}
}
+ // -w
+ if (args.hasArg(clang::driver::options::OPT_w)) {
+ features.DisableAllWarnings();
+ res.setDisableWarnings();
+ }
+
// Default to off for `flang -fc1`.
- res.getFrontendOpts().showColors =
- parseShowColorsArgs(args, /*defaultDiagColor=*/false);
+ bool showColors = parseShowColorsArgs(args, false);
- // Honor color diagnostics.
- res.getDiagnosticOpts().ShowColors = res.getFrontendOpts().showColors;
+ diags.getDiagnosticOptions().ShowColors = showColors;
+ res.getDiagnosticOpts().ShowColors = showColors;
+ res.getFrontendOpts().showColors = showColors;
return diags.getNumErrors() == numErrorsBefore;
}
@@ -1074,16 +1095,6 @@ static bool parseDialectArgs(CompilerInvocation &res, llvm::opt::ArgList &args,
Fortran::common::LanguageFeature::OpenACC);
}
- // -pedantic
- if (args.hasArg(clang::driver::options::OPT_pedantic)) {
- res.setEnableConformanceChecks();
- res.setEnableUsageChecks();
- }
-
- // -w
- if (args.hasArg(clang::driver::options::OPT_w))
- res.setDisableWarnings();
-
// -std=f2018
// TODO: Set proper options when more fortran standards
// are supported.
@@ -1092,6 +1103,7 @@ static bool parseDialectArgs(CompilerInvocation &res, llvm::opt::ArgList &args,
// We only allow f2018 as the given standard
if (standard == "f2018") {
res.setEnableConformanceChecks();
+ res.getFrontendOpts().features.WarnOnAllNonstandard();
} else {
const unsigned diagID =
diags.getCustomDiagID(clang::DiagnosticsEngine::Error,
@@ -1099,6 +1111,7 @@ static bool parseDialectArgs(CompilerInvocation &res, llvm::opt::ArgList &args,
diags.Report(diagID);
}
}
+
return diags.getNumErrors() == numErrorsBefore;
}
@@ -1694,16 +1707,7 @@ void CompilerInvocation::setFortranOpts() {
if (frontendOptions.needProvenanceRangeToCharBlockMappings)
fortranOptions.needProvenanceRangeToCharBlockMappings = true;
- if (getEnableConformanceChecks())
- fortranOptions.features.WarnOnAllNonstandard();
-
- if (getEnableUsageChecks())
- fortranOptions.features.WarnOnAllUsage();
-
- if (getDisableWarnings()) {
- fortranOptions.features.DisableAllNonstandardWarnings();
- fortranOptions.features.DisableAllUsageWarnings();
- }
+ fortranOptions.features = frontendOptions.features;
}
std::unique_ptr<Fortran::semantics::SemanticsContext>
diff --git a/flang/lib/Support/CMakeLists.txt b/flang/lib/Support/CMakeLists.txt
index 363f57ce97dae..9ef31a2a6dcc7 100644
--- a/flang/lib/Support/CMakeLists.txt
+++ b/flang/lib/Support/CMakeLists.txt
@@ -44,6 +44,7 @@ endif()
add_flang_library(FortranSupport
default-kinds.cpp
+ enum-class.cpp
Flags.cpp
Fortran.cpp
Fortran-features.cpp
diff --git a/flang/lib/Support/Fortran-features.cpp b/flang/lib/Support/Fortran-features.cpp
index bee8984102b82..55abf0385d185 100644
--- a/flang/lib/Support/Fortran-features.cpp
+++ b/flang/lib/Support/Fortran-features.cpp
@@ -9,6 +9,8 @@
#include "flang/Support/Fortran-features.h"
#include "flang/Common/idioms.h"
#include "flang/Support/Fortran.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/raw_ostream.h"
namespace Fortran::common {
@@ -94,57 +96,123 @@ LanguageFeatureControl::LanguageFeatureControl() {
warnLanguage_.set(LanguageFeature::NullActualForAllocatable);
}
-// Ignore case and any inserted punctuation (like '-'/'_')
-static std::optional<char> GetWarningChar(char ch) {
- if (ch >= 'a' && ch <= 'z') {
- return ch;
- } else if (ch >= 'A' && ch <= 'Z') {
- return ch - 'A' + 'a';
- } else if (ch >= '0' && ch <= '9') {
- return ch;
- } else {
- return std::nullopt;
+// Split a string with camel case into the individual words.
+// Note, the small vector is just an array of a few pointers and lengths
+// into the original input string. So all this allocation should be pretty
+// cheap.
+llvm::SmallVector<llvm::StringRef> splitCamelCase(llvm::StringRef input) {
+ using namespace llvm;
+ if (input.empty()) {
+ return {};
}
+ SmallVector<StringRef> parts{};
+ parts.reserve(input.size());
+ auto check = [&input](size_t j, function_ref<bool(char)> predicate) {
+ return j < input.size() && predicate(input[j]);
+ };
+ size_t i{0};
+ size_t startWord = i;
+ for (; i < input.size(); i++) {
+ if ((check(i, isUpper) && check(i + 1, isUpper) && check(i + 2, isLower)) ||
+ ((check(i, isLower) || check(i, isDigit)) && check(i + 1, isUpper))) {
+ parts.push_back(StringRef(input.data() + startWord, i - startWord + 1));
+ startWord = i + 1;
+ }
+ }
+ parts.push_back(llvm::StringRef(input.data() + startWord, i - startWord));
+ return parts;
}
-static bool WarningNameMatch(const char *a, const char *b) {
- while (true) {
- auto ach{GetWarningChar(*a)};
- while (!ach && *a) {
- ach = GetWarningChar(*++a);
- }
- auto bch{GetWarningChar(*b)};
- while (!bch && *b) {
- bch = GetWarningChar(*++b);
+// Split a string whith hyphens into the individual words.
+llvm::SmallVector<llvm::StringRef> splitHyphenated(llvm::StringRef input) {
+ auto parts = llvm::SmallVector<llvm::StringRef>{};
+ llvm::SplitString(input, parts, "-");
+ return parts;
+}
+
+// Check if two strings are equal while normalizing case for the
+// right word which is assumed to be a single word in camel case.
+bool equalLowerCaseWithCamelCaseWord(llvm::StringRef l, llvm::StringRef r) {
+ size_t ls = l.size();
+ if (ls != r.size())
+ return false;
+ size_t j{0};
+ // Process the upper case characters.
+ for (; j < ls; j++) {
+ char rc = r[j];
+ char rc2l = llvm::toLower(rc);
+ if (rc == rc2l) {
+ // Past run of Uppers Case;
+ break;
}
- if (!ach && !bch) {
- return true;
- } else if (!ach || !bch || *ach != *bch) {
+ if (l[j] != rc2l)
+ return false;
+ }
+ // Process the lower case characters.
+ for (; j < ls; j++) {
+ if (l[j] != r[j]) {
return false;
}
- ++a, ++b;
}
+ return true;
}
-template <typename ENUM, std::size_t N>
-std::optional<ENUM> ScanEnum(const char *name) {
- if (name) {
- for (std::size_t j{0}; j < N; ++j) {
- auto feature{static_cast<ENUM>(j)};
- if (WarningNameMatch(name, EnumToString(feature).data())) {
- return feature;
+// Parse a CLI enum option return the enum index and whether it should be
+// enabled (true) or disabled (false).
+std::optional<std::pair<bool, int>> parseCLIEnumIndex(
+ llvm::StringRef input, std::function<std::optional<int>(Predicate)> find) {
+ auto parts = splitHyphenated(input);
+ bool negated = false;
+ if (parts.size() >= 1 && !parts[0].compare(llvm::StringRef("no", 2))) {
+ negated = true;
+ // Remove the "no" part
+ parts = llvm::SmallVector<llvm::StringRef>(parts.begin() + 1, parts.end());
+ }
+ size_t chars = 0;
+ for (auto p : parts) {
+ chars += p.size();
+ }
+ auto pred = [&](auto s) {
+ if (chars != s.size()) {
+ return false;
+ }
+ auto ccParts = splitCamelCase(s);
+ auto num_ccParts = ccParts.size();
+ if (parts.size() != num_ccParts) {
+ return false;
+ }
+ for (size_t i{0}; i < num_ccParts; i++) {
+ if (!equalLowerCaseWithCamelCaseWord(parts[i], ccParts[i])) {
+ return false;
}
}
- }
- return std::nullopt;
+ return true;
+ };
+ auto cast = [negated](int x) { return std::pair{!negated, x}; };
+ return fmap<int, std::pair<bool, int>>(find(pred), cast);
}
-std::optional<LanguageFeature> FindLanguageFeature(const char *name) {
- return ScanEnum<LanguageFeature, LanguageFeature_enumSize>(name);
+std::optional<std::pair<bool, LanguageFeature>> parseCLILanguageFeature(
+ llvm::StringRef input) {
+ return parseCLIEnum<LanguageFeature>(input, FindLanguageFeatureIndex);
}
-std::optional<UsageWarning> FindUsageWarning(const char *name) {
- return ScanEnum<UsageWarning, UsageWarning_enumSize>(name);
+std::optional<std::pair<bool, UsageWarning>> parseCLIUsageWarning(
+ llvm::StringRef input) {
+ return parseCLIEnum<UsageWarning>(input, FindUsageWarningIndex);
+}
+
+// Take a string from the CLI and apply it to the LanguageFeatureControl.
+// Return true if the option was applied recognized.
+bool LanguageFeatureControl::applyCLIOption(llvm::StringRef input) {
+ if (auto result = parseCLILanguageFeature(input)) {
+ EnableWarning(result->second, result->first);
+ return true;
+ } else if (auto result = parseCLIUsageWarning(input)) {
+ EnableWarning(result->second, result->first);
+ return true;
+ }
+ return false;
}
std::vector<const char *> LanguageFeatureControl::GetNames(
@@ -201,4 +269,32 @@ std::vector<const char *> LanguageFeatureControl::GetNames(
}
}
+template <typename ENUM, std::size_t N>
+void ForEachEnum(std::function<void(ENUM)> f) {
+ for (size_t j{0}; j < N; ++j) {
+ f(static_cast<ENUM>(j));
+ }
+}
+
+void LanguageFeatureControl::WarnOnAllNonstandard(bool yes) {
+ warnAllLanguage_ = yes;
+ disableAllWarnings_ = yes ? false : disableAllWarnings_;
+ // should be equivalent to: reset().flip() set ...
+ ForEachEnum<LanguageFeature, LanguageFeature_enumSize>(
+ [&](LanguageFeature f) { warnLanguage_.set(f, yes); });
+ if (yes) {
+ // These three features do not need to be warned about,
+ // but we do want their feature flags.
+ warnLanguage_.set(LanguageFeature::OpenMP, false);
+ warnLanguage_.set(LanguageFeature::OpenACC, false);
+ warnLanguage_.set(LanguageFeature::CUDA, false);
+ }
+}
+
+void LanguageFeatureControl::WarnOnAllUsage(bool yes) {
+ warnAllUsage_ = yes;
+ disableAllWarnings_ = yes ? false : disableAllWarnings_;
+ ForEachEnum<UsageWarning, UsageWarning_enumSize>(
+ [&](UsageWarning w) { warnUsage_.set(w, yes); });
+}
} // namespace Fortran::common
diff --git a/flang/lib/Support/enum-class.cpp b/flang/lib/Support/enum-class.cpp
new file mode 100644
index 0000000000000..ed11318382b35
--- /dev/null
+++ b/flang/lib/Support/enum-class.cpp
@@ -0,0 +1,24 @@
+//===-- lib/Support/enum-class.cpp -------------------------------*- 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "flang/Common/enum-class.h"
+#include <optional>
+#include <functional>
+namespace Fortran::common {
+
+std::optional<int> FindEnumIndex(std::function<bool(const std::string_view)> pred, int size, const std::string_view *names) {
+ for (int i = 0; i < size; ++i) {
+ if (pred(names[i])) {
+ return i;
+ }
+ }
+ return std::nullopt;
+}
+
+
+} // namespace Fortran::common
\ No newline at end of file
diff --git a/flang/test/Driver/disable-diagnostic.f90 b/flang/test/Driver/disable-diagnostic.f90
new file mode 100644
index 0000000000000..8a58e63cfa3ac
--- /dev/null
+++ b/flang/test/Driver/disable-diagnostic.f90
@@ -0,0 +1,19 @@
+! RUN: %flang -Wknown-bad-implicit-interface %s -c 2>&1 | FileCheck %s --check-prefix=WARN
+! RUN: %flang -pedantic -Wno-known-bad-implicit-interface %s -c 2>&1 | FileCheck %s --allow-empty
+! RUN: not %flang -WKnownBadImplicitInterface %s -c 2>&1 | FileCheck %s --check-prefix=ERROR1
+! RUN: not %flang -WKnown-Bad-Implicit-Interface %s -c 2>&1 | FileCheck %s --check-prefix=ERROR2
+! ERROR1: error: Unknown diagnostic option: -WKnownBadImplicitInterface
+! ERROR2: error: Unknown diagnostic option: -WKnown-Bad-Implicit-Interface
+
+program disable_diagnostic
+ REAL :: x
+ INTEGER :: y
+ ! CHECK-NOT: warning
+ ! WARN: warning: If the procedure's interface were explicit, this reference would be in error
+ call sub(x)
+ ! WARN: warning: If the procedure's interface were explicit, this reference would be in error
+ call sub(y)
+end program disable_diagnostic
+
+subroutine sub()
+end subroutine sub
\ No newline at end of file
diff --git a/flang/test/Driver/werror-wrong.f90 b/flang/test/Driver/werror-wrong.f90
index 58adf6f745d5e..33f0aff8a1739 100644
--- a/flang/test/Driver/werror-wrong.f90
+++ b/flang/test/Driver/werror-wrong.f90
@@ -1,6 +1,7 @@
! 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
+! RUN: not %flang_fc1 -fsyntax-only -Wall %s 2>&1 | FileCheck %s --check-prefix=WRONG1
+! RUN: not %flang_fc1 -fsyntax-only -WX %s 2>&1 | FileCheck %s --check-prefix=WRONG2
-! WRONG: Only `-Werror` is supported currently.
+! WRONG1: error: Unknown diagnostic option: -Wall
+! WRONG2: error: Unknown diagnostic option: -WX
\ No newline at end of file
diff --git a/flang/test/Driver/wextra-ok.f90 b/flang/test/Driver/wextra-ok.f90
index 441029aa0af27..db15c7f14aa35 100644
--- a/flang/test/Driver/wextra-ok.f90
+++ b/flang/test/Driver/wextra-ok.f90
@@ -5,7 +5,7 @@
! RUN: not %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 diagnostic option: -Wblah
program wextra_ok
end program wextra_ok
diff --git a/flang/unittests/Common/CMakeLists.txt b/flang/unittests/Common/CMakeLists.txt
index bda02ed29a5ef..19cc5a20fecf4 100644
--- a/flang/unittests/Common/CMakeLists.txt
+++ b/flang/unittests/Common/CMakeLists.txt
@@ -1,3 +1,6 @@
add_flang_unittest(FlangCommonTests
+ EnumClassTests.cpp
FastIntSetTest.cpp
+ FortranFeaturesTest.cpp
)
+target_link_libraries(FlangCommonTests PRIVATE FortranSupport)
\ No newline at end of file
diff --git a/flang/unittests/Common/EnumClassTests.cpp b/flang/unittests/Common/EnumClassTests.cpp
new file mode 100644
index 0000000000000..f67c453cfad15
--- /dev/null
+++ b/flang/unittests/Common/EnumClassTests.cpp
@@ -0,0 +1,45 @@
+//===-- flang/unittests/Common/FastIntSetTest.cpp ---------------*- 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "flang/Common/enum-class.h"
+#include "flang/Common/template.h"
+#include "gtest/gtest.h"
+
+using namespace Fortran::common;
+using namespace std;
+
+ENUM_CLASS(TestEnum, One, Two,
+ Three)
+ENUM_CLASS_EXTRA(TestEnum)
+
+TEST(EnumClassTest, EnumToString) {
+ ASSERT_EQ(EnumToString(TestEnum::One), "One");
+ ASSERT_EQ(EnumToString(TestEnum::Two), "Two");
+ ASSERT_EQ(EnumToString(TestEnum::Three), "Three");
+}
+
+TEST(EnumClassTest, EnumToStringData) {
+ ASSERT_STREQ(EnumToString(TestEnum::One).data(), "One, Two, Three");
+}
+
+TEST(EnumClassTest, StringToEnum) {
+ ASSERT_EQ(StringToTestEnum("One"), std::optional{TestEnum::One});
+ ASSERT_EQ(StringToTestEnum("Two"), std::optional{TestEnum::Two});
+ ASSERT_EQ(StringToTestEnum("Three"), std::optional{TestEnum::Three});
+ ASSERT_EQ(StringToTestEnum("Four"), std::nullopt);
+ ASSERT_EQ(StringToTestEnum(""), std::nullopt);
+ ASSERT_EQ(StringToTestEnum("One, Two, Three"), std::nullopt);
+}
+
+ENUM_CLASS(TestEnumExtra, TwentyOne, FortyTwo, SevenSevenSeven)
+ENUM_CLASS_EXTRA(TestEnumExtra)
+
+TEST(EnumClassTest, FindNameNormal) {
+ auto p1 = [](auto s) { return s == "TwentyOne"; };
+ ASSERT_EQ(FindTestEnumExtra(p1), std::optional{TestEnumExtra::TwentyOne});
+}
diff --git a/flang/unittests/Common/FortranFeaturesTest.cpp b/flang/unittests/Common/FortranFeaturesTest.cpp
new file mode 100644
index 0000000000000..7ec7054f14f6e
--- /dev/null
+++ b/flang/unittests/Common/FortranFeaturesTest.cpp
@@ -0,0 +1,142 @@
+//===-- flang/unittests/Common/FastIntSetTest.cpp ---------------*- 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "flang/Common/enum-class.h"
+#include "flang/Support/Fortran-features.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "gtest/gtest.h"
+
+namespace Fortran::common {
+
+// Not currently exported from Fortran-features.h
+llvm::SmallVector<llvm::StringRef> splitCamelCase(llvm::StringRef input);
+llvm::SmallVector<llvm::StringRef> splitHyphenated(llvm::StringRef input);
+bool equalLowerCaseWithCamelCaseWord(llvm::StringRef l, llvm::StringRef r);
+
+ENUM_CLASS(TestEnumExtra, TwentyOne, FortyTwo, SevenSevenSeven)
+ENUM_CLASS_EXTRA(TestEnumExtra)
+
+TEST(EnumClassTest, SplitCamelCase) {
+
+ auto parts = splitCamelCase("oP");
+ ASSERT_EQ(parts.size(), (size_t)2);
+
+ if (parts[0].compare(llvm::StringRef("o", 1))) {
+ ADD_FAILURE() << "First part is not OP";
+ }
+ if (parts[1].compare(llvm::StringRef("P", 1))) {
+ ADD_FAILURE() << "Second part is not Name";
+ }
+
+ parts = splitCamelCase("OPName");
+ ASSERT_EQ(parts.size(), (size_t)2);
+
+ if (parts[0].compare(llvm::StringRef("OP", 2))) {
+ ADD_FAILURE() << "First part is not OP";
+ }
+ if (parts[1].compare(llvm::StringRef("Name", 4))) {
+ ADD_FAILURE() << "Second part is not Name";
+ }
+
+ parts = splitCamelCase("OpName");
+ ASSERT_EQ(parts.size(), (size_t)2);
+ if (parts[0].compare(llvm::StringRef("Op", 2))) {
+ ADD_FAILURE() << "First part is not Op";
+ }
+ if (parts[1].compare(llvm::StringRef("Name", 4))) {
+ ADD_FAILURE() << "Second part is not Name";
+ }
+
+ parts = splitCamelCase("opName");
+ ASSERT_EQ(parts.size(), (size_t)2);
+ if (parts[0].compare(llvm::StringRef("op", 2))) {
+ ADD_FAILURE() << "First part is not op";
+ }
+ if (parts[1].compare(llvm::StringRef("Name", 4))) {
+ ADD_FAILURE() << "Second part is not Name";
+ }
+
+ parts = splitCamelCase("FlangTestProgram123");
+ ASSERT_EQ(parts.size(), (size_t)3);
+ if (parts[0].compare(llvm::StringRef("Flang", 5))) {
+ ADD_FAILURE() << "First part is not Flang";
+ }
+ if (parts[1].compare(llvm::StringRef("Test", 4))) {
+ ADD_FAILURE() << "Second part is not Test";
+ }
+ if (parts[2].compare(llvm::StringRef("Program123", 10))) {
+ ADD_FAILURE() << "Third part is not Program123";
+ }
+ for (auto p : parts) {
+ llvm::errs() << p << " " << p.size() << "\n";
+ }
+}
+
+TEST(EnumClassTest, SplitHyphenated) {
+ auto parts = splitHyphenated("no-twenty-one");
+ ASSERT_EQ(parts.size(), (size_t)3);
+ if (parts[0].compare(llvm::StringRef("no", 2))) {
+ ADD_FAILURE() << "First part is not twenty";
+ }
+ if (parts[1].compare(llvm::StringRef("twenty", 6))) {
+ ADD_FAILURE() << "Second part is not one";
+ }
+ if (parts[2].compare(llvm::StringRef("one", 3))) {
+ ADD_FAILURE() << "Third part is not one";
+ }
+ for (auto p : parts) {
+ llvm::errs() << p << " " << p.size() << "\n";
+ }
+}
+
+TEST(EnumClassTest, equalLowerCaseWithCamelCaseWord) {
+ EXPECT_FALSE(equalLowerCaseWithCamelCaseWord("O", "O"));
+ EXPECT_FALSE(equalLowerCaseWithCamelCaseWord("o", "p"));
+ EXPECT_FALSE(equalLowerCaseWithCamelCaseWord("o", "P"));
+ EXPECT_FALSE(equalLowerCaseWithCamelCaseWord("1", "2"));
+ EXPECT_FALSE(equalLowerCaseWithCamelCaseWord("Op", "op"));
+ EXPECT_FALSE(equalLowerCaseWithCamelCaseWord("op", "Oplss"));
+ EXPECT_FALSE(equalLowerCaseWithCamelCaseWord("oplss", "OplSS"));
+ EXPECT_FALSE(equalLowerCaseWithCamelCaseWord("OPLSS", "oplss"));
+ EXPECT_FALSE(equalLowerCaseWithCamelCaseWord("OPLSS", "OPLSS"));
+
+ EXPECT_TRUE(equalLowerCaseWithCamelCaseWord("o", "O"));
+ EXPECT_TRUE(equalLowerCaseWithCamelCaseWord("oplss", "OPLSS"));
+ EXPECT_TRUE(equalLowerCaseWithCamelCaseWord("oplss", "oplss"));
+ EXPECT_TRUE(equalLowerCaseWithCamelCaseWord("op555", "OP555"));
+ EXPECT_TRUE(equalLowerCaseWithCamelCaseWord("op555", "op555"));
+}
+
+std::optional<std::pair<bool, TestEnumExtra>> parseCLITestEnumExtraOption(llvm::StringRef input) {
+ return parseCLIEnum<TestEnumExtra>(input, FindTestEnumExtraIndex);
+}
+
+TEST(EnumClassTest, parseCLIEnumOption) {
+ auto result = parseCLITestEnumExtraOption("no-twenty-one");
+ auto expected = std::pair<bool, TestEnumExtra>(false, TestEnumExtra::TwentyOne);
+ ASSERT_EQ(result, std::optional{expected});
+ result = parseCLITestEnumExtraOption("twenty-one");
+ expected = std::pair<bool, TestEnumExtra>(true, TestEnumExtra::TwentyOne);
+ ASSERT_EQ(result, std::optional{expected});
+ result = parseCLITestEnumExtraOption("no-forty-two");
+ expected = std::pair<bool, TestEnumExtra>(false, TestEnumExtra::FortyTwo);
+ ASSERT_EQ(result, std::optional{expected});
+ result = parseCLITestEnumExtraOption("forty-two");
+ expected = std::pair<bool, TestEnumExtra>(true, TestEnumExtra::FortyTwo);
+ ASSERT_EQ(result, std::optional{expected});
+ result = parseCLITestEnumExtraOption("no-seven-seven-seven");
+ expected = std::pair<bool, TestEnumExtra>(false, TestEnumExtra::SevenSevenSeven);
+ ASSERT_EQ(result, std::optional{expected});
+ result = parseCLITestEnumExtraOption("seven-seven-seven");
+ expected = std::pair<bool, TestEnumExtra>(true, TestEnumExtra::SevenSevenSeven);
+ ASSERT_EQ(result, std::optional{expected});
+}
+
+} // namespace Fortran::common
>From 49a0579f9477936b72f0580823b4dd6824697512 Mon Sep 17 00:00:00 2001
From: Andre Kuhlenschmidt <akuhlenschmi at nvidia.com>
Date: Thu, 29 May 2025 12:56:14 -0700
Subject: [PATCH 2/8] adjust headers
---
flang/include/flang/Support/Fortran-features.h | 4 +---
flang/lib/Frontend/CompilerInvocation.cpp | 5 -----
flang/lib/Support/Fortran-features.cpp | 1 -
3 files changed, 1 insertion(+), 9 deletions(-)
diff --git a/flang/include/flang/Support/Fortran-features.h b/flang/include/flang/Support/Fortran-features.h
index d5aa7357ffea0..4a8b0da4c0d4d 100644
--- a/flang/include/flang/Support/Fortran-features.h
+++ b/flang/include/flang/Support/Fortran-features.h
@@ -11,9 +11,7 @@
#include "Fortran.h"
#include "flang/Common/enum-set.h"
-#include "flang/Common/idioms.h"
-#include "llvm/Support/Error.h"
-#include "llvm/Support/raw_ostream.h"
+#include "llvm/ADT/StringRef.h"
#include <optional>
#include <vector>
diff --git a/flang/lib/Frontend/CompilerInvocation.cpp b/flang/lib/Frontend/CompilerInvocation.cpp
index 9ea568549bd6c..d8bf601d0171d 100644
--- a/flang/lib/Frontend/CompilerInvocation.cpp
+++ b/flang/lib/Frontend/CompilerInvocation.cpp
@@ -20,11 +20,9 @@
#include "flang/Support/Version.h"
#include "flang/Tools/TargetSetup.h"
#include "flang/Version.inc"
-#include "clang/Basic/AllDiagnostics.h"
#include "clang/Basic/DiagnosticDriver.h"
#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Driver/Driver.h"
-#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/OptionUtils.h"
#include "clang/Driver/Options.h"
#include "llvm/ADT/StringRef.h"
@@ -34,9 +32,7 @@
#include "llvm/Option/ArgList.h"
#include "llvm/Option/OptTable.h"
#include "llvm/Support/CodeGen.h"
-#include "llvm/Support/Error.h"
#include "llvm/Support/FileSystem.h"
-#include "llvm/Support/FileUtilities.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Process.h"
#include "llvm/Support/raw_ostream.h"
@@ -46,7 +42,6 @@
#include <cstdlib>
#include <memory>
#include <optional>
-#include <string>
using namespace Fortran::frontend;
diff --git a/flang/lib/Support/Fortran-features.cpp b/flang/lib/Support/Fortran-features.cpp
index 55abf0385d185..0e394162ef577 100644
--- a/flang/lib/Support/Fortran-features.cpp
+++ b/flang/lib/Support/Fortran-features.cpp
@@ -10,7 +10,6 @@
#include "flang/Common/idioms.h"
#include "flang/Support/Fortran.h"
#include "llvm/ADT/StringExtras.h"
-#include "llvm/Support/raw_ostream.h"
namespace Fortran::common {
>From fa2db7090c6d374ce1a835ad26d19a1d7bd42262 Mon Sep 17 00:00:00 2001
From: Andre Kuhlenschmidt <akuhlenschmi at nvidia.com>
Date: Thu, 29 May 2025 12:57:22 -0700
Subject: [PATCH 3/8] reformat
---
flang/lib/Support/enum-class.cpp | 20 ++++++++++---------
flang/unittests/Common/EnumClassTests.cpp | 5 ++---
.../unittests/Common/FortranFeaturesTest.cpp | 18 ++++++++++-------
3 files changed, 24 insertions(+), 19 deletions(-)
diff --git a/flang/lib/Support/enum-class.cpp b/flang/lib/Support/enum-class.cpp
index ed11318382b35..ac57f27ef1c9e 100644
--- a/flang/lib/Support/enum-class.cpp
+++ b/flang/lib/Support/enum-class.cpp
@@ -1,4 +1,5 @@
-//===-- lib/Support/enum-class.cpp -------------------------------*- C++ -*-===//
+//===-- lib/Support/enum-class.cpp -------------------------------*- C++
+//-*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -7,18 +8,19 @@
//===----------------------------------------------------------------------===//
#include "flang/Common/enum-class.h"
-#include <optional>
#include <functional>
+#include <optional>
namespace Fortran::common {
-std::optional<int> FindEnumIndex(std::function<bool(const std::string_view)> pred, int size, const std::string_view *names) {
- for (int i = 0; i < size; ++i) {
- if (pred(names[i])) {
- return i;
- }
+std::optional<int> FindEnumIndex(
+ std::function<bool(const std::string_view)> pred, int size,
+ const std::string_view *names) {
+ for (int i = 0; i < size; ++i) {
+ if (pred(names[i])) {
+ return i;
}
- return std::nullopt;
+ }
+ return std::nullopt;
}
-
} // namespace Fortran::common
\ No newline at end of file
diff --git a/flang/unittests/Common/EnumClassTests.cpp b/flang/unittests/Common/EnumClassTests.cpp
index f67c453cfad15..c9224a8ceba54 100644
--- a/flang/unittests/Common/EnumClassTests.cpp
+++ b/flang/unittests/Common/EnumClassTests.cpp
@@ -6,15 +6,14 @@
//
//===----------------------------------------------------------------------===//
+#include "gtest/gtest.h"
#include "flang/Common/enum-class.h"
#include "flang/Common/template.h"
-#include "gtest/gtest.h"
using namespace Fortran::common;
using namespace std;
-ENUM_CLASS(TestEnum, One, Two,
- Three)
+ENUM_CLASS(TestEnum, One, Two, Three)
ENUM_CLASS_EXTRA(TestEnum)
TEST(EnumClassTest, EnumToString) {
diff --git a/flang/unittests/Common/FortranFeaturesTest.cpp b/flang/unittests/Common/FortranFeaturesTest.cpp
index 7ec7054f14f6e..597928e7fe56e 100644
--- a/flang/unittests/Common/FortranFeaturesTest.cpp
+++ b/flang/unittests/Common/FortranFeaturesTest.cpp
@@ -6,12 +6,12 @@
//
//===----------------------------------------------------------------------===//
+#include "gtest/gtest.h"
#include "flang/Common/enum-class.h"
#include "flang/Support/Fortran-features.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/ErrorHandling.h"
-#include "gtest/gtest.h"
namespace Fortran::common {
@@ -34,7 +34,7 @@ TEST(EnumClassTest, SplitCamelCase) {
if (parts[1].compare(llvm::StringRef("P", 1))) {
ADD_FAILURE() << "Second part is not Name";
}
-
+
parts = splitCamelCase("OPName");
ASSERT_EQ(parts.size(), (size_t)2);
@@ -114,13 +114,15 @@ TEST(EnumClassTest, equalLowerCaseWithCamelCaseWord) {
EXPECT_TRUE(equalLowerCaseWithCamelCaseWord("op555", "op555"));
}
-std::optional<std::pair<bool, TestEnumExtra>> parseCLITestEnumExtraOption(llvm::StringRef input) {
- return parseCLIEnum<TestEnumExtra>(input, FindTestEnumExtraIndex);
+std::optional<std::pair<bool, TestEnumExtra>> parseCLITestEnumExtraOption(
+ llvm::StringRef input) {
+ return parseCLIEnum<TestEnumExtra>(input, FindTestEnumExtraIndex);
}
TEST(EnumClassTest, parseCLIEnumOption) {
auto result = parseCLITestEnumExtraOption("no-twenty-one");
- auto expected = std::pair<bool, TestEnumExtra>(false, TestEnumExtra::TwentyOne);
+ auto expected =
+ std::pair<bool, TestEnumExtra>(false, TestEnumExtra::TwentyOne);
ASSERT_EQ(result, std::optional{expected});
result = parseCLITestEnumExtraOption("twenty-one");
expected = std::pair<bool, TestEnumExtra>(true, TestEnumExtra::TwentyOne);
@@ -132,10 +134,12 @@ TEST(EnumClassTest, parseCLIEnumOption) {
expected = std::pair<bool, TestEnumExtra>(true, TestEnumExtra::FortyTwo);
ASSERT_EQ(result, std::optional{expected});
result = parseCLITestEnumExtraOption("no-seven-seven-seven");
- expected = std::pair<bool, TestEnumExtra>(false, TestEnumExtra::SevenSevenSeven);
+ expected =
+ std::pair<bool, TestEnumExtra>(false, TestEnumExtra::SevenSevenSeven);
ASSERT_EQ(result, std::optional{expected});
result = parseCLITestEnumExtraOption("seven-seven-seven");
- expected = std::pair<bool, TestEnumExtra>(true, TestEnumExtra::SevenSevenSeven);
+ expected =
+ std::pair<bool, TestEnumExtra>(true, TestEnumExtra::SevenSevenSeven);
ASSERT_EQ(result, std::optional{expected});
}
>From 5f3feb64c1a97500e2808114d44bb07aa4ccb00c Mon Sep 17 00:00:00 2001
From: Andre Kuhlenschmidt <akuhlenschmi at nvidia.com>
Date: Thu, 29 May 2025 15:58:43 -0700
Subject: [PATCH 4/8] addressing feedback
---
flang/include/flang/Common/enum-class.h | 53 +++---
flang/include/flang/Common/optional.h | 7 +
.../include/flang/Support/Fortran-features.h | 16 --
flang/lib/Support/Fortran-features.cpp | 175 ++++++++----------
flang/lib/Support/enum-class.cpp | 15 +-
flang/test/Driver/disable-diagnostic.f90 | 3 +-
flang/test/Driver/werror-wrong.f90 | 2 +-
flang/unittests/Common/CMakeLists.txt | 2 +-
.../unittests/Common/FortranFeaturesTest.cpp | 159 +++-------------
9 files changed, 153 insertions(+), 279 deletions(-)
diff --git a/flang/include/flang/Common/enum-class.h b/flang/include/flang/Common/enum-class.h
index baf9fe418141d..3dbd11bb4057c 100644
--- a/flang/include/flang/Common/enum-class.h
+++ b/flang/include/flang/Common/enum-class.h
@@ -17,9 +17,9 @@
#ifndef FORTRAN_COMMON_ENUM_CLASS_H_
#define FORTRAN_COMMON_ENUM_CLASS_H_
+#include "optional.h"
#include <array>
#include <functional>
-#include <optional>
#include <string_view>
namespace Fortran::common {
@@ -59,26 +59,6 @@ constexpr std::array<std::string_view, ITEMS> EnumNames(const char *p) {
return result;
}
-template <typename F, typename T>
-std::optional<T> inline fmap(std::optional<F> x, std::function<T(const F)> f) {
- return x ? std::optional<T>{f(*x)} : std::nullopt;
-}
-
-using Predicate = std::function<bool(const std::string_view)>;
-// Finds the first index for which the predicate returns true.
-std::optional<int> FindEnumIndex(
- Predicate pred, int size, const std::string_view *names);
-
-using FindEnumIndexType = std::optional<int>(
- Predicate, int, const std::string_view *);
-
-template <typename NAME>
-std::optional<NAME> inline FindEnum(
- Predicate pred, std::function<std::optional<int>(Predicate)> find) {
- std::function<NAME(int)> f = [](int x) { return static_cast<NAME>(x); };
- return fmap(find(pred), f);
-}
-
#define ENUM_CLASS(NAME, ...) \
enum class NAME { __VA_ARGS__ }; \
[[maybe_unused]] static constexpr std::size_t NAME##_enumSize{ \
@@ -90,17 +70,34 @@ std::optional<NAME> inline FindEnum(
return NAME##_names[static_cast<std::size_t>(e)]; \
}
+namespace EnumClass {
+
+using Predicate = std::function<bool(const std::string_view)>;
+// Finds the first index for which the predicate returns true.
+optional<std::size_t> FindIndex(
+ Predicate pred, std::size_t size, const std::string_view *names);
+
+using FindIndexType = std::function<optional<std::size_t>(Predicate)>;
+
+template <typename NAME>
+optional<NAME> inline Find(Predicate pred, FindIndexType findIndex) {
+ return MapOption<int, NAME>(
+ findIndex(pred), [](int x) { return static_cast<NAME>(x); });
+}
+
+} // namespace EnumClass
+
#define ENUM_CLASS_EXTRA(NAME) \
- [[maybe_unused]] inline std::optional<int> Find##NAME##Index( \
- ::Fortran::common::Predicate p) { \
- return ::Fortran::common::FindEnumIndex( \
+ [[maybe_unused]] inline optional<std::size_t> Find##NAME##Index( \
+ ::Fortran::common::EnumClass::Predicate p) { \
+ return ::Fortran::common::EnumClass::FindIndex( \
p, NAME##_enumSize, NAME##_names.data()); \
} \
- [[maybe_unused]] inline std::optional<NAME> Find##NAME( \
- ::Fortran::common::Predicate p) { \
- return ::Fortran::common::FindEnum<NAME>(p, Find##NAME##Index); \
+ [[maybe_unused]] inline optional<NAME> Find##NAME( \
+ ::Fortran::common::EnumClass::Predicate p) { \
+ return ::Fortran::common::EnumClass::Find<NAME>(p, Find##NAME##Index); \
} \
- [[maybe_unused]] inline std::optional<NAME> StringTo##NAME( \
+ [[maybe_unused]] inline optional<NAME> StringTo##NAME( \
const std::string_view name) { \
return Find##NAME( \
[name](const std::string_view s) -> bool { return name == s; }); \
diff --git a/flang/include/flang/Common/optional.h b/flang/include/flang/Common/optional.h
index c7c81f40cc8c8..5b623f01e828d 100644
--- a/flang/include/flang/Common/optional.h
+++ b/flang/include/flang/Common/optional.h
@@ -27,6 +27,7 @@
#define FORTRAN_COMMON_OPTIONAL_H
#include "api-attrs.h"
+#include <functional>
#include <optional>
#include <type_traits>
@@ -238,6 +239,12 @@ using std::nullopt_t;
using std::optional;
#endif // !STD_OPTIONAL_UNSUPPORTED
+template <typename T, typename U>
+std::optional<U> inline MapOption(
+ std::optional<T> x, std::function<U(const T)> f) {
+ return x ? std::optional<U>{f(*x)} : std::nullopt;
+}
+
} // namespace Fortran::common
#endif // FORTRAN_COMMON_OPTIONAL_H
diff --git a/flang/include/flang/Support/Fortran-features.h b/flang/include/flang/Support/Fortran-features.h
index 4a8b0da4c0d4d..fd6a9139b7ea7 100644
--- a/flang/include/flang/Support/Fortran-features.h
+++ b/flang/include/flang/Support/Fortran-features.h
@@ -133,21 +133,5 @@ class LanguageFeatureControl {
bool disableAllWarnings_{false};
};
-// Parse a CLI enum option return the enum index and whether it should be
-// enabled (true) or disabled (false). Just exposed for the template below.
-std::optional<std::pair<bool, int>> parseCLIEnumIndex(
- llvm::StringRef input, std::function<std::optional<int>(Predicate)> find);
-
-template <typename ENUM>
-std::optional<std::pair<bool, ENUM>> parseCLIEnum(
- llvm::StringRef input, std::function<std::optional<int>(Predicate)> find) {
- using To = std::pair<bool, ENUM>;
- using From = std::pair<bool, int>;
- static std::function<To(From)> cast = [](From x) {
- return std::pair{x.first, static_cast<ENUM>(x.second)};
- };
- return fmap(parseCLIEnumIndex(input, find), cast);
-}
-
} // namespace Fortran::common
#endif // FORTRAN_SUPPORT_FORTRAN_FEATURES_H_
diff --git a/flang/lib/Support/Fortran-features.cpp b/flang/lib/Support/Fortran-features.cpp
index 0e394162ef577..72ea6639adf51 100644
--- a/flang/lib/Support/Fortran-features.cpp
+++ b/flang/lib/Support/Fortran-features.cpp
@@ -11,6 +11,10 @@
#include "flang/Support/Fortran.h"
#include "llvm/ADT/StringExtras.h"
+// Debugging
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/raw_ostream.h"
+
namespace Fortran::common {
LanguageFeatureControl::LanguageFeatureControl() {
@@ -95,119 +99,99 @@ LanguageFeatureControl::LanguageFeatureControl() {
warnLanguage_.set(LanguageFeature::NullActualForAllocatable);
}
-// Split a string with camel case into the individual words.
-// Note, the small vector is just an array of a few pointers and lengths
-// into the original input string. So all this allocation should be pretty
-// cheap.
-llvm::SmallVector<llvm::StringRef> splitCamelCase(llvm::StringRef input) {
- using namespace llvm;
- if (input.empty()) {
- return {};
+// Namespace for helper functions for parsing CLI options
+// used instead of static so that there can be unit tests for these
+// functions.
+namespace FortranFeaturesHelpers {
+// Check if Lower Case Hyphenated words are equal to Camel Case words.
+// Because of out use case we know that 'r' the camel case string is
+// well formed in the sense that it is a sequence [a-zA-Z]+[a-zA-Z0-9]*.
+// This is checked in the enum-class.h file.
+bool LowerHyphEqualCamelCase(llvm::StringRef l, llvm::StringRef r) {
+ size_t ls{l.size()}, rs{r.size()};
+ if (ls < rs) {
+ return false;
}
- SmallVector<StringRef> parts{};
- parts.reserve(input.size());
- auto check = [&input](size_t j, function_ref<bool(char)> predicate) {
- return j < input.size() && predicate(input[j]);
- };
- size_t i{0};
- size_t startWord = i;
- for (; i < input.size(); i++) {
- if ((check(i, isUpper) && check(i + 1, isUpper) && check(i + 2, isLower)) ||
- ((check(i, isLower) || check(i, isDigit)) && check(i + 1, isUpper))) {
- parts.push_back(StringRef(input.data() + startWord, i - startWord + 1));
- startWord = i + 1;
+ bool atStartOfWord{true};
+ size_t wordCount{0}, j; // j is the number of word characters checked in r.
+ for (; j < rs; j++) {
+ if (wordCount + j >= ls) {
+ // `l` was shorter once the hiphens were removed.
+ // If r is null terminated, then we are good.
+ return r[j] == '\0';
}
- }
- parts.push_back(llvm::StringRef(input.data() + startWord, i - startWord));
- return parts;
-}
-
-// Split a string whith hyphens into the individual words.
-llvm::SmallVector<llvm::StringRef> splitHyphenated(llvm::StringRef input) {
- auto parts = llvm::SmallVector<llvm::StringRef>{};
- llvm::SplitString(input, parts, "-");
- return parts;
-}
-
-// Check if two strings are equal while normalizing case for the
-// right word which is assumed to be a single word in camel case.
-bool equalLowerCaseWithCamelCaseWord(llvm::StringRef l, llvm::StringRef r) {
- size_t ls = l.size();
- if (ls != r.size())
- return false;
- size_t j{0};
- // Process the upper case characters.
- for (; j < ls; j++) {
- char rc = r[j];
- char rc2l = llvm::toLower(rc);
- if (rc == rc2l) {
- // Past run of Uppers Case;
- break;
+ if (atStartOfWord) {
+ if (llvm::isUpper(r[j])) {
+ // Upper Case Run
+ if (l[wordCount + j] != llvm::toLower(r[j])) {
+ return false;
+ }
+ } else {
+ atStartOfWord = false;
+ if (l[wordCount + j] != r[j]) {
+ return false;
+ }
+ }
+ } else {
+ if (llvm::isUpper(r[j])) {
+ atStartOfWord = true;
+ if (l[wordCount + j] != '-') {
+ return false;
+ }
+ ++wordCount;
+ if (l[wordCount + j] != llvm::toLower(r[j])) {
+ return false;
+ }
+ } else if (l[wordCount + j] != r[j]) {
+ return false;
+ }
}
- if (l[j] != rc2l)
- return false;
}
- // Process the lower case characters.
- for (; j < ls; j++) {
- if (l[j] != r[j]) {
- return false;
- }
+ // If there are more characters in l after processing all the characters in r.
+ // then fail unless the string is null terminated.
+ if (ls > wordCount + j) {
+ return l[wordCount + j] == '\0';
}
return true;
}
// Parse a CLI enum option return the enum index and whether it should be
// enabled (true) or disabled (false).
-std::optional<std::pair<bool, int>> parseCLIEnumIndex(
- llvm::StringRef input, std::function<std::optional<int>(Predicate)> find) {
- auto parts = splitHyphenated(input);
- bool negated = false;
- if (parts.size() >= 1 && !parts[0].compare(llvm::StringRef("no", 2))) {
+template <typename T>
+optional<std::pair<bool, T>> ParseCLIEnum(
+ llvm::StringRef input, EnumClass::FindIndexType findIndex) {
+ bool negated{false};
+ if (input.starts_with("no-")) {
negated = true;
- // Remove the "no" part
- parts = llvm::SmallVector<llvm::StringRef>(parts.begin() + 1, parts.end());
- }
- size_t chars = 0;
- for (auto p : parts) {
- chars += p.size();
+ input = input.drop_front(3);
}
- auto pred = [&](auto s) {
- if (chars != s.size()) {
- return false;
- }
- auto ccParts = splitCamelCase(s);
- auto num_ccParts = ccParts.size();
- if (parts.size() != num_ccParts) {
- return false;
- }
- for (size_t i{0}; i < num_ccParts; i++) {
- if (!equalLowerCaseWithCamelCaseWord(parts[i], ccParts[i])) {
- return false;
- }
- }
- return true;
- };
- auto cast = [negated](int x) { return std::pair{!negated, x}; };
- return fmap<int, std::pair<bool, int>>(find(pred), cast);
+ EnumClass::Predicate predicate{
+ [input](llvm::StringRef r) { return LowerHyphEqualCamelCase(input, r); }};
+ optional<T> x = EnumClass::Find<T>(predicate, findIndex);
+ return MapOption<T, std::pair<bool, T>>(
+ x, [negated](T x) { return std::pair{!negated, x}; });
}
-std::optional<std::pair<bool, LanguageFeature>> parseCLILanguageFeature(
+optional<std::pair<bool, UsageWarning>> parseCLIUsageWarning(
llvm::StringRef input) {
- return parseCLIEnum<LanguageFeature>(input, FindLanguageFeatureIndex);
+ return ParseCLIEnum<UsageWarning>(input, FindUsageWarningIndex);
}
-std::optional<std::pair<bool, UsageWarning>> parseCLIUsageWarning(
+optional<std::pair<bool, LanguageFeature>> parseCLILanguageFeature(
llvm::StringRef input) {
- return parseCLIEnum<UsageWarning>(input, FindUsageWarningIndex);
+ return ParseCLIEnum<LanguageFeature>(input, FindLanguageFeatureIndex);
}
+} // namespace FortranFeaturesHelpers
+
// Take a string from the CLI and apply it to the LanguageFeatureControl.
// Return true if the option was applied recognized.
bool LanguageFeatureControl::applyCLIOption(llvm::StringRef input) {
- if (auto result = parseCLILanguageFeature(input)) {
+ if (auto result = FortranFeaturesHelpers::parseCLILanguageFeature(input)) {
EnableWarning(result->second, result->first);
return true;
- } else if (auto result = parseCLIUsageWarning(input)) {
+ } else if (auto result =
+ FortranFeaturesHelpers::parseCLIUsageWarning(input)) {
EnableWarning(result->second, result->first);
return true;
}
@@ -277,11 +261,10 @@ void ForEachEnum(std::function<void(ENUM)> f) {
void LanguageFeatureControl::WarnOnAllNonstandard(bool yes) {
warnAllLanguage_ = yes;
- disableAllWarnings_ = yes ? false : disableAllWarnings_;
- // should be equivalent to: reset().flip() set ...
- ForEachEnum<LanguageFeature, LanguageFeature_enumSize>(
- [&](LanguageFeature f) { warnLanguage_.set(f, yes); });
+ warnLanguage_.reset();
if (yes) {
+ disableAllWarnings_ = false;
+ warnLanguage_.flip();
// These three features do not need to be warned about,
// but we do want their feature flags.
warnLanguage_.set(LanguageFeature::OpenMP, false);
@@ -292,8 +275,10 @@ void LanguageFeatureControl::WarnOnAllNonstandard(bool yes) {
void LanguageFeatureControl::WarnOnAllUsage(bool yes) {
warnAllUsage_ = yes;
- disableAllWarnings_ = yes ? false : disableAllWarnings_;
- ForEachEnum<UsageWarning, UsageWarning_enumSize>(
- [&](UsageWarning w) { warnUsage_.set(w, yes); });
+ warnUsage_.reset();
+ if (yes) {
+ disableAllWarnings_ = false;
+ warnUsage_.flip();
+ }
}
} // namespace Fortran::common
diff --git a/flang/lib/Support/enum-class.cpp b/flang/lib/Support/enum-class.cpp
index ac57f27ef1c9e..d6d0ee758175b 100644
--- a/flang/lib/Support/enum-class.cpp
+++ b/flang/lib/Support/enum-class.cpp
@@ -8,19 +8,20 @@
//===----------------------------------------------------------------------===//
#include "flang/Common/enum-class.h"
+#include "flang/Common/optional.h"
#include <functional>
-#include <optional>
-namespace Fortran::common {
-std::optional<int> FindEnumIndex(
- std::function<bool(const std::string_view)> pred, int size,
+namespace Fortran::common::EnumClass {
+
+optional<std::size_t> FindIndex(
+ std::function<bool(const std::string_view)> pred, size_t size,
const std::string_view *names) {
- for (int i = 0; i < size; ++i) {
+ for (size_t i = 0; i < size; ++i) {
if (pred(names[i])) {
return i;
}
}
- return std::nullopt;
+ return nullopt;
}
-} // namespace Fortran::common
\ No newline at end of file
+} // namespace Fortran::common::EnumClass
diff --git a/flang/test/Driver/disable-diagnostic.f90 b/flang/test/Driver/disable-diagnostic.f90
index 8a58e63cfa3ac..849489377da12 100644
--- a/flang/test/Driver/disable-diagnostic.f90
+++ b/flang/test/Driver/disable-diagnostic.f90
@@ -2,6 +2,7 @@
! RUN: %flang -pedantic -Wno-known-bad-implicit-interface %s -c 2>&1 | FileCheck %s --allow-empty
! RUN: not %flang -WKnownBadImplicitInterface %s -c 2>&1 | FileCheck %s --check-prefix=ERROR1
! RUN: not %flang -WKnown-Bad-Implicit-Interface %s -c 2>&1 | FileCheck %s --check-prefix=ERROR2
+
! ERROR1: error: Unknown diagnostic option: -WKnownBadImplicitInterface
! ERROR2: error: Unknown diagnostic option: -WKnown-Bad-Implicit-Interface
@@ -16,4 +17,4 @@ program disable_diagnostic
end program disable_diagnostic
subroutine sub()
-end subroutine sub
\ No newline at end of file
+end subroutine sub
diff --git a/flang/test/Driver/werror-wrong.f90 b/flang/test/Driver/werror-wrong.f90
index 33f0aff8a1739..6e3c7cca15bc7 100644
--- a/flang/test/Driver/werror-wrong.f90
+++ b/flang/test/Driver/werror-wrong.f90
@@ -4,4 +4,4 @@
! RUN: not %flang_fc1 -fsyntax-only -WX %s 2>&1 | FileCheck %s --check-prefix=WRONG2
! WRONG1: error: Unknown diagnostic option: -Wall
-! WRONG2: error: Unknown diagnostic option: -WX
\ No newline at end of file
+! WRONG2: error: Unknown diagnostic option: -WX
diff --git a/flang/unittests/Common/CMakeLists.txt b/flang/unittests/Common/CMakeLists.txt
index 19cc5a20fecf4..3149cb9f7bc47 100644
--- a/flang/unittests/Common/CMakeLists.txt
+++ b/flang/unittests/Common/CMakeLists.txt
@@ -3,4 +3,4 @@ add_flang_unittest(FlangCommonTests
FastIntSetTest.cpp
FortranFeaturesTest.cpp
)
-target_link_libraries(FlangCommonTests PRIVATE FortranSupport)
\ No newline at end of file
+target_link_libraries(FlangCommonTests PRIVATE FortranSupport)
diff --git a/flang/unittests/Common/FortranFeaturesTest.cpp b/flang/unittests/Common/FortranFeaturesTest.cpp
index 597928e7fe56e..e12aff9f7b735 100644
--- a/flang/unittests/Common/FortranFeaturesTest.cpp
+++ b/flang/unittests/Common/FortranFeaturesTest.cpp
@@ -12,135 +12,34 @@
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/ErrorHandling.h"
-
-namespace Fortran::common {
-
-// Not currently exported from Fortran-features.h
-llvm::SmallVector<llvm::StringRef> splitCamelCase(llvm::StringRef input);
-llvm::SmallVector<llvm::StringRef> splitHyphenated(llvm::StringRef input);
-bool equalLowerCaseWithCamelCaseWord(llvm::StringRef l, llvm::StringRef r);
-
-ENUM_CLASS(TestEnumExtra, TwentyOne, FortyTwo, SevenSevenSeven)
-ENUM_CLASS_EXTRA(TestEnumExtra)
-
-TEST(EnumClassTest, SplitCamelCase) {
-
- auto parts = splitCamelCase("oP");
- ASSERT_EQ(parts.size(), (size_t)2);
-
- if (parts[0].compare(llvm::StringRef("o", 1))) {
- ADD_FAILURE() << "First part is not OP";
- }
- if (parts[1].compare(llvm::StringRef("P", 1))) {
- ADD_FAILURE() << "Second part is not Name";
- }
-
- parts = splitCamelCase("OPName");
- ASSERT_EQ(parts.size(), (size_t)2);
-
- if (parts[0].compare(llvm::StringRef("OP", 2))) {
- ADD_FAILURE() << "First part is not OP";
- }
- if (parts[1].compare(llvm::StringRef("Name", 4))) {
- ADD_FAILURE() << "Second part is not Name";
- }
-
- parts = splitCamelCase("OpName");
- ASSERT_EQ(parts.size(), (size_t)2);
- if (parts[0].compare(llvm::StringRef("Op", 2))) {
- ADD_FAILURE() << "First part is not Op";
- }
- if (parts[1].compare(llvm::StringRef("Name", 4))) {
- ADD_FAILURE() << "Second part is not Name";
- }
-
- parts = splitCamelCase("opName");
- ASSERT_EQ(parts.size(), (size_t)2);
- if (parts[0].compare(llvm::StringRef("op", 2))) {
- ADD_FAILURE() << "First part is not op";
- }
- if (parts[1].compare(llvm::StringRef("Name", 4))) {
- ADD_FAILURE() << "Second part is not Name";
- }
-
- parts = splitCamelCase("FlangTestProgram123");
- ASSERT_EQ(parts.size(), (size_t)3);
- if (parts[0].compare(llvm::StringRef("Flang", 5))) {
- ADD_FAILURE() << "First part is not Flang";
- }
- if (parts[1].compare(llvm::StringRef("Test", 4))) {
- ADD_FAILURE() << "Second part is not Test";
- }
- if (parts[2].compare(llvm::StringRef("Program123", 10))) {
- ADD_FAILURE() << "Third part is not Program123";
- }
- for (auto p : parts) {
- llvm::errs() << p << " " << p.size() << "\n";
- }
-}
-
-TEST(EnumClassTest, SplitHyphenated) {
- auto parts = splitHyphenated("no-twenty-one");
- ASSERT_EQ(parts.size(), (size_t)3);
- if (parts[0].compare(llvm::StringRef("no", 2))) {
- ADD_FAILURE() << "First part is not twenty";
- }
- if (parts[1].compare(llvm::StringRef("twenty", 6))) {
- ADD_FAILURE() << "Second part is not one";
- }
- if (parts[2].compare(llvm::StringRef("one", 3))) {
- ADD_FAILURE() << "Third part is not one";
- }
- for (auto p : parts) {
- llvm::errs() << p << " " << p.size() << "\n";
- }
-}
-
-TEST(EnumClassTest, equalLowerCaseWithCamelCaseWord) {
- EXPECT_FALSE(equalLowerCaseWithCamelCaseWord("O", "O"));
- EXPECT_FALSE(equalLowerCaseWithCamelCaseWord("o", "p"));
- EXPECT_FALSE(equalLowerCaseWithCamelCaseWord("o", "P"));
- EXPECT_FALSE(equalLowerCaseWithCamelCaseWord("1", "2"));
- EXPECT_FALSE(equalLowerCaseWithCamelCaseWord("Op", "op"));
- EXPECT_FALSE(equalLowerCaseWithCamelCaseWord("op", "Oplss"));
- EXPECT_FALSE(equalLowerCaseWithCamelCaseWord("oplss", "OplSS"));
- EXPECT_FALSE(equalLowerCaseWithCamelCaseWord("OPLSS", "oplss"));
- EXPECT_FALSE(equalLowerCaseWithCamelCaseWord("OPLSS", "OPLSS"));
-
- EXPECT_TRUE(equalLowerCaseWithCamelCaseWord("o", "O"));
- EXPECT_TRUE(equalLowerCaseWithCamelCaseWord("oplss", "OPLSS"));
- EXPECT_TRUE(equalLowerCaseWithCamelCaseWord("oplss", "oplss"));
- EXPECT_TRUE(equalLowerCaseWithCamelCaseWord("op555", "OP555"));
- EXPECT_TRUE(equalLowerCaseWithCamelCaseWord("op555", "op555"));
-}
-
-std::optional<std::pair<bool, TestEnumExtra>> parseCLITestEnumExtraOption(
- llvm::StringRef input) {
- return parseCLIEnum<TestEnumExtra>(input, FindTestEnumExtraIndex);
-}
-
-TEST(EnumClassTest, parseCLIEnumOption) {
- auto result = parseCLITestEnumExtraOption("no-twenty-one");
- auto expected =
- std::pair<bool, TestEnumExtra>(false, TestEnumExtra::TwentyOne);
- ASSERT_EQ(result, std::optional{expected});
- result = parseCLITestEnumExtraOption("twenty-one");
- expected = std::pair<bool, TestEnumExtra>(true, TestEnumExtra::TwentyOne);
- ASSERT_EQ(result, std::optional{expected});
- result = parseCLITestEnumExtraOption("no-forty-two");
- expected = std::pair<bool, TestEnumExtra>(false, TestEnumExtra::FortyTwo);
- ASSERT_EQ(result, std::optional{expected});
- result = parseCLITestEnumExtraOption("forty-two");
- expected = std::pair<bool, TestEnumExtra>(true, TestEnumExtra::FortyTwo);
- ASSERT_EQ(result, std::optional{expected});
- result = parseCLITestEnumExtraOption("no-seven-seven-seven");
- expected =
- std::pair<bool, TestEnumExtra>(false, TestEnumExtra::SevenSevenSeven);
- ASSERT_EQ(result, std::optional{expected});
- result = parseCLITestEnumExtraOption("seven-seven-seven");
- expected =
- std::pair<bool, TestEnumExtra>(true, TestEnumExtra::SevenSevenSeven);
- ASSERT_EQ(result, std::optional{expected});
+#include <optional>
+
+namespace Fortran::common::FortranFeaturesHelpers {
+
+optional<std::pair<bool, UsageWarning>> parseCLIUsageWarning(
+ llvm::StringRef input);
+TEST(EnumClassTest, ParseCLIUsageWarning) {
+ EXPECT_EQ((parseCLIUsageWarning("no-twenty-one")), std::nullopt);
+ EXPECT_EQ((parseCLIUsageWarning("twenty-one")), std::nullopt);
+ EXPECT_EQ((parseCLIUsageWarning("no-seven-seven-seven")), std::nullopt);
+ EXPECT_EQ((parseCLIUsageWarning("seven-seven-seven")), std::nullopt);
+ EXPECT_EQ((parseCLIUsageWarning("no")), std::nullopt);
+ EXPECT_EQ((parseCLIUsageWarning("")), std::nullopt);
+ EXPECT_EQ((parseCLIUsageWarning("no-")), std::nullopt);
+ EXPECT_EQ(parseCLIUsageWarning("Portability"), std::nullopt);
+ auto expect{std::pair{false, UsageWarning::Portability}};
+ ASSERT_EQ(parseCLIUsageWarning("no-portability"), expect);
+ expect.first = true;
+ ASSERT_EQ((parseCLIUsageWarning("portability")), expect);
+ expect =
+ std::pair{false, Fortran::common::UsageWarning::PointerToUndefinable};
+ ASSERT_EQ((parseCLIUsageWarning("no-pointer-to-undefinable")), expect);
+ expect.first = true;
+ ASSERT_EQ((parseCLIUsageWarning("pointer-to-undefinable")), expect);
+ EXPECT_EQ(parseCLIUsageWarning("PointerToUndefinable"), std::nullopt);
+ EXPECT_EQ(parseCLIUsageWarning("NoPointerToUndefinable"), std::nullopt);
+ EXPECT_EQ(parseCLIUsageWarning("pointertoundefinable"), std::nullopt);
+ EXPECT_EQ(parseCLIUsageWarning("nopointertoundefinable"), std::nullopt);
}
-} // namespace Fortran::common
+} // namespace Fortran::common::FortranFeaturesHelpers
>From 79303b42f7cfd3806c22bd34e5eced5f27d27f32 Mon Sep 17 00:00:00 2001
From: Andre Kuhlenschmidt <akuhlenschmi at nvidia.com>
Date: Fri, 30 May 2025 15:42:27 -0700
Subject: [PATCH 5/8] removing debugging statement
---
flang/lib/Support/Fortran-features.cpp | 4 ----
1 file changed, 4 deletions(-)
diff --git a/flang/lib/Support/Fortran-features.cpp b/flang/lib/Support/Fortran-features.cpp
index 72ea6639adf51..75baa0b096af0 100644
--- a/flang/lib/Support/Fortran-features.cpp
+++ b/flang/lib/Support/Fortran-features.cpp
@@ -11,10 +11,6 @@
#include "flang/Support/Fortran.h"
#include "llvm/ADT/StringExtras.h"
-// Debugging
-#include "llvm/ADT/StringRef.h"
-#include "llvm/Support/raw_ostream.h"
-
namespace Fortran::common {
LanguageFeatureControl::LanguageFeatureControl() {
>From 8f0aa22125528a755ec61af2bd45b6c314cfe45c Mon Sep 17 00:00:00 2001
From: Andre Kuhlenschmidt <akuhlenschmi at nvidia.com>
Date: Fri, 30 May 2025 15:59:18 -0700
Subject: [PATCH 6/8] more feedback
---
flang/include/flang/Support/Fortran-features.h | 4 +---
flang/lib/Support/Fortran-features.cpp | 16 +++++++++-------
flang/unittests/Common/FortranFeaturesTest.cpp | 4 ----
3 files changed, 10 insertions(+), 14 deletions(-)
diff --git a/flang/include/flang/Support/Fortran-features.h b/flang/include/flang/Support/Fortran-features.h
index fd6a9139b7ea7..501b183cceeec 100644
--- a/flang/include/flang/Support/Fortran-features.h
+++ b/flang/include/flang/Support/Fortran-features.h
@@ -11,8 +11,6 @@
#include "Fortran.h"
#include "flang/Common/enum-set.h"
-#include "llvm/ADT/StringRef.h"
-#include <optional>
#include <vector>
namespace Fortran::common {
@@ -115,7 +113,7 @@ class LanguageFeatureControl {
DisableAllNonstandardWarnings();
DisableAllUsageWarnings();
}
- bool applyCLIOption(llvm::StringRef input);
+ bool applyCLIOption(std::string_view input);
bool AreWarningsDisabled() const { return disableAllWarnings_; }
bool IsEnabled(LanguageFeature f) const { return !disable_.test(f); }
bool ShouldWarn(LanguageFeature f) const { return warnLanguage_.test(f); }
diff --git a/flang/lib/Support/Fortran-features.cpp b/flang/lib/Support/Fortran-features.cpp
index 75baa0b096af0..d140ecdff7f24 100644
--- a/flang/lib/Support/Fortran-features.cpp
+++ b/flang/lib/Support/Fortran-features.cpp
@@ -99,11 +99,11 @@ LanguageFeatureControl::LanguageFeatureControl() {
// used instead of static so that there can be unit tests for these
// functions.
namespace FortranFeaturesHelpers {
-// Check if Lower Case Hyphenated words are equal to Camel Case words.
+// Check if lower case hyphenated words are equal to camel case words.
// Because of out use case we know that 'r' the camel case string is
// well formed in the sense that it is a sequence [a-zA-Z]+[a-zA-Z0-9]*.
// This is checked in the enum-class.h file.
-bool LowerHyphEqualCamelCase(llvm::StringRef l, llvm::StringRef r) {
+static bool LowerHyphEqualCamelCase(llvm::StringRef l, llvm::StringRef r) {
size_t ls{l.size()}, rs{r.size()};
if (ls < rs) {
return false;
@@ -161,8 +161,9 @@ optional<std::pair<bool, T>> ParseCLIEnum(
negated = true;
input = input.drop_front(3);
}
- EnumClass::Predicate predicate{
- [input](llvm::StringRef r) { return LowerHyphEqualCamelCase(input, r); }};
+ EnumClass::Predicate predicate{[input](std::string_view r) {
+ return LowerHyphEqualCamelCase(input, r);
+ }};
optional<T> x = EnumClass::Find<T>(predicate, findIndex);
return MapOption<T, std::pair<bool, T>>(
x, [negated](T x) { return std::pair{!negated, x}; });
@@ -182,12 +183,13 @@ optional<std::pair<bool, LanguageFeature>> parseCLILanguageFeature(
// Take a string from the CLI and apply it to the LanguageFeatureControl.
// Return true if the option was applied recognized.
-bool LanguageFeatureControl::applyCLIOption(llvm::StringRef input) {
- if (auto result = FortranFeaturesHelpers::parseCLILanguageFeature(input)) {
+bool LanguageFeatureControl::applyCLIOption(std::string_view input) {
+ llvm::StringRef inputRef{input};
+ if (auto result = FortranFeaturesHelpers::parseCLILanguageFeature(inputRef)) {
EnableWarning(result->second, result->first);
return true;
} else if (auto result =
- FortranFeaturesHelpers::parseCLIUsageWarning(input)) {
+ FortranFeaturesHelpers::parseCLIUsageWarning(inputRef)) {
EnableWarning(result->second, result->first);
return true;
}
diff --git a/flang/unittests/Common/FortranFeaturesTest.cpp b/flang/unittests/Common/FortranFeaturesTest.cpp
index e12aff9f7b735..b3f0c31a57025 100644
--- a/flang/unittests/Common/FortranFeaturesTest.cpp
+++ b/flang/unittests/Common/FortranFeaturesTest.cpp
@@ -7,11 +7,7 @@
//===----------------------------------------------------------------------===//
#include "gtest/gtest.h"
-#include "flang/Common/enum-class.h"
#include "flang/Support/Fortran-features.h"
-#include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/Support/ErrorHandling.h"
#include <optional>
namespace Fortran::common::FortranFeaturesHelpers {
>From a0317745bca77a1134e116fd570b4ecca60e4d95 Mon Sep 17 00:00:00 2001
From: Andre Kuhlenschmidt <akuhlenschmi at nvidia.com>
Date: Fri, 30 May 2025 17:02:17 -0700
Subject: [PATCH 7/8] adding insensitive match back
---
.../include/flang/Support/Fortran-features.h | 2 +-
flang/lib/Support/Fortran-features.cpp | 86 +++++++++++++++----
.../unittests/Common/FortranFeaturesTest.cpp | 75 +++++++++++-----
3 files changed, 123 insertions(+), 40 deletions(-)
diff --git a/flang/include/flang/Support/Fortran-features.h b/flang/include/flang/Support/Fortran-features.h
index 501b183cceeec..0b55a3175580a 100644
--- a/flang/include/flang/Support/Fortran-features.h
+++ b/flang/include/flang/Support/Fortran-features.h
@@ -113,7 +113,7 @@ class LanguageFeatureControl {
DisableAllNonstandardWarnings();
DisableAllUsageWarnings();
}
- bool applyCLIOption(std::string_view input);
+ bool applyCLIOption(std::string_view input, bool insensitive = false);
bool AreWarningsDisabled() const { return disableAllWarnings_; }
bool IsEnabled(LanguageFeature f) const { return !disable_.test(f); }
bool ShouldWarn(LanguageFeature f) const { return warnLanguage_.test(f); }
diff --git a/flang/lib/Support/Fortran-features.cpp b/flang/lib/Support/Fortran-features.cpp
index d140ecdff7f24..80e87615697df 100644
--- a/flang/lib/Support/Fortran-features.cpp
+++ b/flang/lib/Support/Fortran-features.cpp
@@ -8,6 +8,7 @@
#include "flang/Support/Fortran-features.h"
#include "flang/Common/idioms.h"
+#include "flang/Common/optional.h"
#include "flang/Support/Fortran.h"
#include "llvm/ADT/StringExtras.h"
@@ -99,11 +100,48 @@ LanguageFeatureControl::LanguageFeatureControl() {
// used instead of static so that there can be unit tests for these
// functions.
namespace FortranFeaturesHelpers {
+
+// Ignore case and any inserted punctuation (like '-'/'_')
+static std::optional<char> GetWarningChar(char ch) {
+ if (ch >= 'a' && ch <= 'z') {
+ return ch;
+ } else if (ch >= 'A' && ch <= 'Z') {
+ return ch - 'A' + 'a';
+ } else if (ch >= '0' && ch <= '9') {
+ return ch;
+ } else {
+ return std::nullopt;
+ }
+}
+
+// Check for case and punctuation insensitive string equality.
+// NB, b is probably not null terminated, so don't treat is like a C string.
+static bool InsensitiveWarningNameMatch(
+ std::string_view a, std::string_view b) {
+ size_t j{0}, aSize{a.size()}, k{0}, bSize{b.size()};
+ while (true) {
+ optional<char> ach{nullopt};
+ while (!ach && j < aSize) {
+ ach = GetWarningChar(a[j++]);
+ }
+ optional<char> bch{};
+ while (!bch && k < bSize) {
+ bch = GetWarningChar(b[k++]);
+ }
+ if (!ach && !bch) {
+ return true;
+ } else if (!ach || !bch || *ach != *bch) {
+ return false;
+ }
+ ach = bch = nullopt;
+ }
+}
+
// Check if lower case hyphenated words are equal to camel case words.
// Because of out use case we know that 'r' the camel case string is
// well formed in the sense that it is a sequence [a-zA-Z]+[a-zA-Z0-9]*.
// This is checked in the enum-class.h file.
-static bool LowerHyphEqualCamelCase(llvm::StringRef l, llvm::StringRef r) {
+static bool SensitiveWarningNameMatch(llvm::StringRef l, llvm::StringRef r) {
size_t ls{l.size()}, rs{r.size()};
if (ls < rs) {
return false;
@@ -154,42 +192,56 @@ static bool LowerHyphEqualCamelCase(llvm::StringRef l, llvm::StringRef r) {
// Parse a CLI enum option return the enum index and whether it should be
// enabled (true) or disabled (false).
template <typename T>
-optional<std::pair<bool, T>> ParseCLIEnum(
- llvm::StringRef input, EnumClass::FindIndexType findIndex) {
+optional<std::pair<bool, T>> ParseCLIEnum(llvm::StringRef input,
+ EnumClass::FindIndexType findIndex, bool insensitive) {
bool negated{false};
- if (input.starts_with("no-")) {
- negated = true;
- input = input.drop_front(3);
+ EnumClass::Predicate predicate;
+ if (insensitive) {
+ if (input.starts_with_insensitive("no")) {
+ negated = true;
+ input = input.drop_front(2);
+ }
+ predicate = [input](std::string_view r) {
+ return InsensitiveWarningNameMatch(input, r);
+ };
+ } else {
+ if (input.starts_with("no-")) {
+ negated = true;
+ input = input.drop_front(3);
+ }
+ predicate = [input](std::string_view r) {
+ return SensitiveWarningNameMatch(input, r);
+ };
}
- EnumClass::Predicate predicate{[input](std::string_view r) {
- return LowerHyphEqualCamelCase(input, r);
- }};
optional<T> x = EnumClass::Find<T>(predicate, findIndex);
return MapOption<T, std::pair<bool, T>>(
x, [negated](T x) { return std::pair{!negated, x}; });
}
optional<std::pair<bool, UsageWarning>> parseCLIUsageWarning(
- llvm::StringRef input) {
- return ParseCLIEnum<UsageWarning>(input, FindUsageWarningIndex);
+ llvm::StringRef input, bool insensitive) {
+ return ParseCLIEnum<UsageWarning>(input, FindUsageWarningIndex, insensitive);
}
optional<std::pair<bool, LanguageFeature>> parseCLILanguageFeature(
- llvm::StringRef input) {
- return ParseCLIEnum<LanguageFeature>(input, FindLanguageFeatureIndex);
+ llvm::StringRef input, bool insensitive) {
+ return ParseCLIEnum<LanguageFeature>(
+ input, FindLanguageFeatureIndex, insensitive);
}
} // namespace FortranFeaturesHelpers
// Take a string from the CLI and apply it to the LanguageFeatureControl.
// Return true if the option was applied recognized.
-bool LanguageFeatureControl::applyCLIOption(std::string_view input) {
+bool LanguageFeatureControl::applyCLIOption(
+ std::string_view input, bool insensitive) {
llvm::StringRef inputRef{input};
- if (auto result = FortranFeaturesHelpers::parseCLILanguageFeature(inputRef)) {
+ if (auto result = FortranFeaturesHelpers::parseCLILanguageFeature(
+ inputRef, insensitive)) {
EnableWarning(result->second, result->first);
return true;
- } else if (auto result =
- FortranFeaturesHelpers::parseCLIUsageWarning(inputRef)) {
+ } else if (auto result = FortranFeaturesHelpers::parseCLIUsageWarning(
+ inputRef, insensitive)) {
EnableWarning(result->second, result->first);
return true;
}
diff --git a/flang/unittests/Common/FortranFeaturesTest.cpp b/flang/unittests/Common/FortranFeaturesTest.cpp
index b3f0c31a57025..4e9529d633ad9 100644
--- a/flang/unittests/Common/FortranFeaturesTest.cpp
+++ b/flang/unittests/Common/FortranFeaturesTest.cpp
@@ -13,29 +13,60 @@
namespace Fortran::common::FortranFeaturesHelpers {
optional<std::pair<bool, UsageWarning>> parseCLIUsageWarning(
- llvm::StringRef input);
+ llvm::StringRef input, bool insensitive);
TEST(EnumClassTest, ParseCLIUsageWarning) {
- EXPECT_EQ((parseCLIUsageWarning("no-twenty-one")), std::nullopt);
- EXPECT_EQ((parseCLIUsageWarning("twenty-one")), std::nullopt);
- EXPECT_EQ((parseCLIUsageWarning("no-seven-seven-seven")), std::nullopt);
- EXPECT_EQ((parseCLIUsageWarning("seven-seven-seven")), std::nullopt);
- EXPECT_EQ((parseCLIUsageWarning("no")), std::nullopt);
- EXPECT_EQ((parseCLIUsageWarning("")), std::nullopt);
- EXPECT_EQ((parseCLIUsageWarning("no-")), std::nullopt);
- EXPECT_EQ(parseCLIUsageWarning("Portability"), std::nullopt);
- auto expect{std::pair{false, UsageWarning::Portability}};
- ASSERT_EQ(parseCLIUsageWarning("no-portability"), expect);
- expect.first = true;
- ASSERT_EQ((parseCLIUsageWarning("portability")), expect);
- expect =
- std::pair{false, Fortran::common::UsageWarning::PointerToUndefinable};
- ASSERT_EQ((parseCLIUsageWarning("no-pointer-to-undefinable")), expect);
- expect.first = true;
- ASSERT_EQ((parseCLIUsageWarning("pointer-to-undefinable")), expect);
- EXPECT_EQ(parseCLIUsageWarning("PointerToUndefinable"), std::nullopt);
- EXPECT_EQ(parseCLIUsageWarning("NoPointerToUndefinable"), std::nullopt);
- EXPECT_EQ(parseCLIUsageWarning("pointertoundefinable"), std::nullopt);
- EXPECT_EQ(parseCLIUsageWarning("nopointertoundefinable"), std::nullopt);
+ EXPECT_EQ((parseCLIUsageWarning("no-twenty-one", false)), std::nullopt);
+ EXPECT_EQ((parseCLIUsageWarning("twenty-one", false)), std::nullopt);
+ EXPECT_EQ(
+ (parseCLIUsageWarning("no-seven-seven-seven", false)), std::nullopt);
+ EXPECT_EQ((parseCLIUsageWarning("seven-seven-seven", false)), std::nullopt);
+ EXPECT_EQ((parseCLIUsageWarning("no", false)), std::nullopt);
+ EXPECT_EQ((parseCLIUsageWarning("", false)), std::nullopt);
+ EXPECT_EQ((parseCLIUsageWarning("no-", false)), std::nullopt);
+
+ EXPECT_EQ(parseCLIUsageWarning("Portability", false), std::nullopt);
+ EXPECT_EQ((parseCLIUsageWarning("no-portability", false)),
+ (std::optional{std::pair{false, UsageWarning::Portability}}));
+ EXPECT_EQ((parseCLIUsageWarning("portability", false)),
+ (std::optional{std::pair{true, UsageWarning::Portability}}));
+ EXPECT_EQ((parseCLIUsageWarning("no-pointer-to-undefinable", false)),
+ (std::optional{std::pair{false, UsageWarning::PointerToUndefinable}}));
+ EXPECT_EQ((parseCLIUsageWarning("pointer-to-undefinable", false)),
+ (std::optional{std::pair{true, UsageWarning::PointerToUndefinable}}));
+ EXPECT_EQ(parseCLIUsageWarning("PointerToUndefinable", false), std::nullopt);
+ EXPECT_EQ(
+ parseCLIUsageWarning("NoPointerToUndefinable", false), std::nullopt);
+ EXPECT_EQ(parseCLIUsageWarning("pointertoundefinable", false), std::nullopt);
+ EXPECT_EQ(
+ parseCLIUsageWarning("nopointertoundefinable", false), std::nullopt);
+
+ EXPECT_EQ((parseCLIUsageWarning("no-twenty-one", false)), std::nullopt);
+ EXPECT_EQ((parseCLIUsageWarning("twenty-one", true)), std::nullopt);
+ EXPECT_EQ((parseCLIUsageWarning("no-seven-seven-seven", true)), std::nullopt);
+ EXPECT_EQ((parseCLIUsageWarning("seven-seven-seven", true)), std::nullopt);
+ EXPECT_EQ((parseCLIUsageWarning("no", true)), std::nullopt);
+ EXPECT_EQ((parseCLIUsageWarning("", true)), std::nullopt);
+ EXPECT_EQ((parseCLIUsageWarning("no-", true)), std::nullopt);
+
+ EXPECT_EQ(parseCLIUsageWarning("Portability", true),
+ (std::optional{std::pair{true, UsageWarning::Portability}}));
+ EXPECT_EQ(parseCLIUsageWarning("no-portability", true),
+ (std::optional{std::pair{false, UsageWarning::Portability}}));
+
+ EXPECT_EQ((parseCLIUsageWarning("portability", true)),
+ (std::optional{std::pair{true, UsageWarning::Portability}}));
+ EXPECT_EQ((parseCLIUsageWarning("no-pointer-to-undefinable", true)),
+ (std::optional{std::pair{false, UsageWarning::PointerToUndefinable}}));
+ EXPECT_EQ((parseCLIUsageWarning("pointer-to-undefinable", true)),
+ (std::optional{std::pair{true, UsageWarning::PointerToUndefinable}}));
+ EXPECT_EQ(parseCLIUsageWarning("PointerToUndefinable", true),
+ (std::optional{std::pair{true, UsageWarning::PointerToUndefinable}}));
+ EXPECT_EQ(parseCLIUsageWarning("NoPointerToUndefinable", true),
+ (std::optional{std::pair{false, UsageWarning::PointerToUndefinable}}));
+ EXPECT_EQ(parseCLIUsageWarning("pointertoundefinable", true),
+ (std::optional{std::pair{true, UsageWarning::PointerToUndefinable}}));
+ EXPECT_EQ(parseCLIUsageWarning("nopointertoundefinable", true),
+ (std::optional{std::pair{false, UsageWarning::PointerToUndefinable}}));
}
} // namespace Fortran::common::FortranFeaturesHelpers
>From d37976f4167677294227c976b4aea03fdb130462 Mon Sep 17 00:00:00 2001
From: Andre Kuhlenschmidt <akuhlenschmi at nvidia.com>
Date: Fri, 30 May 2025 18:01:35 -0700
Subject: [PATCH 8/8] fixing enum name
---
flang/include/flang/Support/Fortran-features.h | 2 +-
flang/lib/Semantics/tools.cpp | 2 +-
flang/unittests/Common/FortranFeaturesTest.cpp | 5 ++++-
3 files changed, 6 insertions(+), 3 deletions(-)
diff --git a/flang/include/flang/Support/Fortran-features.h b/flang/include/flang/Support/Fortran-features.h
index 0b55a3175580a..899959ad8a435 100644
--- a/flang/include/flang/Support/Fortran-features.h
+++ b/flang/include/flang/Support/Fortran-features.h
@@ -60,7 +60,7 @@ ENUM_CLASS(UsageWarning, Portability, PointerToUndefinable,
NonTargetPassedToTarget, PointerToPossibleNoncontiguous,
ShortCharacterActual, ShortArrayActual, ImplicitInterfaceActual,
PolymorphicTransferArg, PointerComponentTransferArg, TransferSizePresence,
- F202XAllocatableBreakingChange, OptionalMustBePresent, CommonBlockPadding,
+ F202xAllocatableBreakingChange, OptionalMustBePresent, CommonBlockPadding,
LogicalVsCBool, BindCCharLength, ProcDummyArgShapes, ExternalNameConflict,
FoldingException, FoldingAvoidsRuntimeCrash, FoldingValueChecks,
FoldingFailure, FoldingLimit, Interoperability, CharacterInteroperability,
diff --git a/flang/lib/Semantics/tools.cpp b/flang/lib/Semantics/tools.cpp
index 1d1e3ac044166..e8da757416cc6 100644
--- a/flang/lib/Semantics/tools.cpp
+++ b/flang/lib/Semantics/tools.cpp
@@ -1672,7 +1672,7 @@ std::forward_list<std::string> GetAllNames(
void WarnOnDeferredLengthCharacterScalar(SemanticsContext &context,
const SomeExpr *expr, parser::CharBlock at, const char *what) {
if (context.languageFeatures().ShouldWarn(
- common::UsageWarning::F202XAllocatableBreakingChange)) {
+ common::UsageWarning::F202xAllocatableBreakingChange)) {
if (const Symbol *
symbol{evaluate::UnwrapWholeSymbolOrComponentDataRef(expr)}) {
const Symbol &ultimate{ResolveAssociations(*symbol)};
diff --git a/flang/unittests/Common/FortranFeaturesTest.cpp b/flang/unittests/Common/FortranFeaturesTest.cpp
index 4e9529d633ad9..0e48697182ff5 100644
--- a/flang/unittests/Common/FortranFeaturesTest.cpp
+++ b/flang/unittests/Common/FortranFeaturesTest.cpp
@@ -52,7 +52,6 @@ TEST(EnumClassTest, ParseCLIUsageWarning) {
(std::optional{std::pair{true, UsageWarning::Portability}}));
EXPECT_EQ(parseCLIUsageWarning("no-portability", true),
(std::optional{std::pair{false, UsageWarning::Portability}}));
-
EXPECT_EQ((parseCLIUsageWarning("portability", true)),
(std::optional{std::pair{true, UsageWarning::Portability}}));
EXPECT_EQ((parseCLIUsageWarning("no-pointer-to-undefinable", true)),
@@ -67,6 +66,10 @@ TEST(EnumClassTest, ParseCLIUsageWarning) {
(std::optional{std::pair{true, UsageWarning::PointerToUndefinable}}));
EXPECT_EQ(parseCLIUsageWarning("nopointertoundefinable", true),
(std::optional{std::pair{false, UsageWarning::PointerToUndefinable}}));
+
+ EXPECT_EQ(parseCLIUsageWarning("f202x-allocatable-breaking-change", false),
+ (std::optional{
+ std::pair{true, UsageWarning::F202xAllocatableBreakingChange}}));
}
} // namespace Fortran::common::FortranFeaturesHelpers
More information about the flang-commits
mailing list