[flang-commits] [flang] [flang][cli] Add diagnostic flags to the CLI (PR #142022)
Andre Kuhlenschmidt via flang-commits
flang-commits at lists.llvm.org
Thu Jun 5 10:54:46 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 01/15] 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 02/15] 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 03/15] 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 04/15] 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 05/15] 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 06/15] 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 07/15] 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 08/15] 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
>From 9ae60472c9e005f0754f195ce1801b970e7244ea Mon Sep 17 00:00:00 2001
From: Andre Kuhlenschmidt <akuhlenschmi at nvidia.com>
Date: Fri, 30 May 2025 18:12:42 -0700
Subject: [PATCH 09/15] fixing uninitialized
---
flang/lib/Support/Fortran-features.cpp | 2 +-
flang/unittests/Common/FortranFeaturesTest.cpp | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/flang/lib/Support/Fortran-features.cpp b/flang/lib/Support/Fortran-features.cpp
index 80e87615697df..dd1798e90051c 100644
--- a/flang/lib/Support/Fortran-features.cpp
+++ b/flang/lib/Support/Fortran-features.cpp
@@ -147,7 +147,7 @@ static bool SensitiveWarningNameMatch(llvm::StringRef l, llvm::StringRef r) {
return false;
}
bool atStartOfWord{true};
- size_t wordCount{0}, j; // j is the number of word characters checked in r.
+ size_t wordCount{0}, j{0}; // 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.
diff --git a/flang/unittests/Common/FortranFeaturesTest.cpp b/flang/unittests/Common/FortranFeaturesTest.cpp
index 0e48697182ff5..367500e46af20 100644
--- a/flang/unittests/Common/FortranFeaturesTest.cpp
+++ b/flang/unittests/Common/FortranFeaturesTest.cpp
@@ -40,7 +40,7 @@ TEST(EnumClassTest, ParseCLIUsageWarning) {
EXPECT_EQ(
parseCLIUsageWarning("nopointertoundefinable", false), std::nullopt);
- EXPECT_EQ((parseCLIUsageWarning("no-twenty-one", false)), std::nullopt);
+ EXPECT_EQ((parseCLIUsageWarning("no-twenty-one", true)), 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);
>From 8b126eecb0b1c18e702dee2923d4d68bfb0307ae Mon Sep 17 00:00:00 2001
From: Andre Kuhlenschmidt <akuhlenschmi at nvidia.com>
Date: Wed, 4 Jun 2025 13:57:45 -0700
Subject: [PATCH 10/15] now uses table
---
flang/include/flang/Common/enum-class.h | 39 +-
flang/include/flang/Common/optional.h | 6 -
.../include/flang/Support/Fortran-features.h | 34 +-
flang/lib/Frontend/CompilerInvocation.cpp | 4 +-
flang/lib/Semantics/tools.cpp | 2 +-
flang/lib/Support/Fortran-features.cpp | 238 +++----
flang/unittests/Common/EnumClassTests.cpp | 31 +-
.../unittests/Common/FortranFeaturesTest.cpp | 606 ++++++++++++++++--
8 files changed, 689 insertions(+), 271 deletions(-)
diff --git a/flang/include/flang/Common/enum-class.h b/flang/include/flang/Common/enum-class.h
index 3dbd11bb4057c..c6cdebf00dec2 100644
--- a/flang/include/flang/Common/enum-class.h
+++ b/flang/include/flang/Common/enum-class.h
@@ -66,41 +66,16 @@ constexpr std::array<std::string_view, ITEMS> EnumNames(const char *p) {
[[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::size_t EnumToInt(NAME e) { \
+ return static_cast<std::size_t>(e); \
+ } \
[[maybe_unused]] static inline std::string_view EnumToString(NAME e) { \
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 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 optional<NAME> Find##NAME( \
- ::Fortran::common::EnumClass::Predicate p) { \
- return ::Fortran::common::EnumClass::Find<NAME>(p, Find##NAME##Index); \
} \
- [[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; }); \
+ [[maybe_unused]] inline void ForEach##NAME(std::function<void(NAME)> f) { \
+ for (std::size_t i = 0; i < NAME##_enumSize; ++i) { \
+ f(static_cast<NAME>(i)); \
+ } \
}
} // namespace Fortran::common
#endif // FORTRAN_COMMON_ENUM_CLASS_H_
diff --git a/flang/include/flang/Common/optional.h b/flang/include/flang/Common/optional.h
index 5b623f01e828d..fbf0f66b59a65 100644
--- a/flang/include/flang/Common/optional.h
+++ b/flang/include/flang/Common/optional.h
@@ -239,12 +239,6 @@ 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 899959ad8a435..61e7031b85988 100644
--- a/flang/include/flang/Support/Fortran-features.h
+++ b/flang/include/flang/Support/Fortran-features.h
@@ -11,6 +11,8 @@
#include "Fortran.h"
#include "flang/Common/enum-set.h"
+#include <llvm/Support/raw_ostream.h>
+#include <string_view>
#include <vector>
namespace Fortran::common {
@@ -60,7 +62,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,
@@ -77,10 +79,6 @@ 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>;
@@ -113,16 +111,40 @@ class LanguageFeatureControl {
DisableAllNonstandardWarnings();
DisableAllUsageWarnings();
}
- 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); }
bool ShouldWarn(UsageWarning w) const { return warnUsage_.test(w); }
+ // CLI options
+ bool applyCLIOption(std::string input);
+ void addAlternativeCliSpelling(LanguageFeature f, std::string input) {
+ cliOptions_.insert({input, {f}});
+ }
+ void addAlternativeCliSpelling(UsageWarning w, std::string input) {
+ cliOptions_.insert({input, {w}});
+ }
+ void replaceCliCanonicalSpelling(LanguageFeature f, std::string input);
+ void replaceCliCanonicalSpelling(UsageWarning w, std::string input);
+ std::string_view getDefaultCliSpelling(LanguageFeature f) const {
+ return languageFeatureCliCanonicalSpelling_[EnumToInt(f)];
+ };
+ std::string_view getDefaultCliSpelling(UsageWarning w) const {
+ return usageWarningCliCanonicalSpelling_[EnumToInt(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;
private:
+ // Map from CLI syntax of language features and usage warnings to their enum
+ // values.
+ std::unordered_map<std::string, std::variant<LanguageFeature, UsageWarning>>
+ cliOptions_;
+ // These two arrays map the enum values to their cannonical CLI spellings.
+ std::array<std::string_view, LanguageFeature_enumSize>
+ languageFeatureCliCanonicalSpelling_;
+ std::array<std::string_view, UsageWarning_enumSize>
+ usageWarningCliCanonicalSpelling_;
LanguageFeatures disable_;
LanguageFeatures warnLanguage_;
bool warnAllLanguage_{false};
diff --git a/flang/lib/Frontend/CompilerInvocation.cpp b/flang/lib/Frontend/CompilerInvocation.cpp
index d8bf601d0171d..6fa7b98ebb5dd 100644
--- a/flang/lib/Frontend/CompilerInvocation.cpp
+++ b/flang/lib/Frontend/CompilerInvocation.cpp
@@ -995,7 +995,7 @@ static bool parseDiagArgs(CompilerInvocation &res, llvm::opt::ArgList &args,
if (wArg == "error") {
res.setWarnAsErr(true);
// -W(no-)<feature>
- } else if (!features.applyCLIOption(wArg)) {
+ } else if (!res.getFrontendOpts().features.applyCLIOption(wArg)) {
const unsigned diagID = diags.getCustomDiagID(
clang::DiagnosticsEngine::Error, "Unknown diagnostic option: -W%0");
diags.Report(diagID) << wArg;
@@ -1011,11 +1011,9 @@ static bool parseDiagArgs(CompilerInvocation &res, llvm::opt::ArgList &args,
// Default to off for `flang -fc1`.
bool showColors = parseShowColorsArgs(args, false);
-
diags.getDiagnosticOptions().ShowColors = showColors;
res.getDiagnosticOpts().ShowColors = showColors;
res.getFrontendOpts().showColors = showColors;
-
return diags.getNumErrors() == numErrorsBefore;
}
diff --git a/flang/lib/Semantics/tools.cpp b/flang/lib/Semantics/tools.cpp
index e8da757416cc6..1d1e3ac044166 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/lib/Support/Fortran-features.cpp b/flang/lib/Support/Fortran-features.cpp
index dd1798e90051c..cb3282f7b6a90 100644
--- a/flang/lib/Support/Fortran-features.cpp
+++ b/flang/lib/Support/Fortran-features.cpp
@@ -8,13 +8,80 @@
#include "flang/Support/Fortran-features.h"
#include "flang/Common/idioms.h"
-#include "flang/Common/optional.h"
+#include "flang/Parser/characters.h"
#include "flang/Support/Fortran.h"
-#include "llvm/ADT/StringExtras.h"
+#include <string>
+#include <string_view>
namespace Fortran::common {
+// Namespace for helper functions for parsing CLI options
+// used instead of static so that there can be unit tests for these
+// functions.
+namespace featuresHelpers {
+
+static std::vector<std::string_view> SplitCamelCase(std::string_view x) {
+ std::vector<std::string_view> result;
+ // NB, we start at 1 because the first character is never a word boundary.
+ size_t xSize{x.size()}, wordStart{0}, wordEnd{1};
+ for (; wordEnd < xSize; ++wordEnd) {
+ // Identify when wordEnd is at the start of a new word.
+ if ((!parser::IsUpperCaseLetter(x[wordEnd - 1]) &&
+ parser::IsUpperCaseLetter(x[wordEnd])) ||
+ // ACCUsage => ACC-Usage, CComment => C-Comment, etc.
+ (parser::IsUpperCaseLetter(x[wordEnd]) && wordEnd + 1 < xSize &&
+ parser::IsLowerCaseLetter(x[wordEnd + 1]))) {
+ result.push_back(
+ std::string_view(x.begin() + wordStart, wordEnd - wordStart));
+ wordStart = wordEnd;
+ }
+ }
+ // We went one past the end of the last word.
+ result.push_back(
+ std::string_view(x.begin() + wordStart, wordEnd - wordStart));
+ return result;
+}
+
+std::string CamelCaseToLowerCaseHyphenated(std::string_view x) {
+ std::vector<std::string_view> words{SplitCamelCase(x)};
+ std::string result{};
+ result.reserve(x.size() + words.size() + 1);
+ for (size_t i{0}; i < words.size(); ++i) {
+ std::string word{parser::ToLowerCaseLetters(words[i])};
+ result += i == 0 ? "" : "-";
+ result += word;
+ }
+ return result;
+}
+} // namespace featuresHelpers
+
LanguageFeatureControl::LanguageFeatureControl() {
+
+ // Initialize the bidirectional maps with the default spellings.
+ cliOptions_.reserve(LanguageFeature_enumSize + UsageWarning_enumSize);
+ ForEachLanguageFeature([&](auto feature) {
+ std::string_view name{Fortran::common::EnumToString(feature)};
+ std::string cliOption{
+ featuresHelpers::CamelCaseToLowerCaseHyphenated(name)};
+ cliOptions_.insert({cliOption, {feature}});
+ languageFeatureCliCanonicalSpelling_[EnumToInt(feature)] =
+ std::string_view{cliOption};
+ });
+
+ ForEachUsageWarning([&](auto warning) {
+ std::string_view name{Fortran::common::EnumToString(warning)};
+ std::string cliOption{
+ featuresHelpers::CamelCaseToLowerCaseHyphenated(name)};
+ cliOptions_.insert({cliOption, {warning}});
+ usageWarningCliCanonicalSpelling_[EnumToInt(warning)] =
+ std::string_view{cliOption};
+ });
+
+ replaceCliCanonicalSpelling(UsageWarning::F202XAllocatableBreakingChange,
+ "f202x-allocatable-breaking-change");
+
+ // If we need to
+
// These features must be explicitly enabled by command line options.
disable_.set(LanguageFeature::OldDebugLines);
disable_.set(LanguageFeature::OpenACC);
@@ -96,156 +163,41 @@ LanguageFeatureControl::LanguageFeatureControl() {
warnLanguage_.set(LanguageFeature::NullActualForAllocatable);
}
-// Namespace for helper functions for parsing CLI options
-// 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;
+// 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 input) {
+ bool negated{false};
+ if (input.size() > 3 && input.substr(0, 3) == "no-") {
+ negated = true;
+ input = input.substr(3);
}
-}
-
-// 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) {
+ if (auto it = cliOptions_.find(input); it != cliOptions_.end()) {
+ if (std::holds_alternative<LanguageFeature>(it->second)) {
+ EnableWarning(std::get<LanguageFeature>(it->second), !negated);
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 SensitiveWarningNameMatch(llvm::StringRef l, llvm::StringRef r) {
- size_t ls{l.size()}, rs{r.size()};
- if (ls < rs) {
- return false;
- }
- bool atStartOfWord{true};
- size_t wordCount{0}, j{0}; // 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';
- }
- 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 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).
-template <typename T>
-optional<std::pair<bool, T>> ParseCLIEnum(llvm::StringRef input,
- EnumClass::FindIndexType findIndex, bool insensitive) {
- bool negated{false};
- 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);
+ if (std::holds_alternative<UsageWarning>(it->second)) {
+ EnableWarning(std::get<UsageWarning>(it->second), !negated);
+ return true;
}
- predicate = [input](std::string_view r) {
- return SensitiveWarningNameMatch(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, bool insensitive) {
- return ParseCLIEnum<UsageWarning>(input, FindUsageWarningIndex, insensitive);
+ return false;
}
-optional<std::pair<bool, LanguageFeature>> parseCLILanguageFeature(
- llvm::StringRef input, bool insensitive) {
- return ParseCLIEnum<LanguageFeature>(
- input, FindLanguageFeatureIndex, insensitive);
+void LanguageFeatureControl::replaceCliCanonicalSpelling(
+ LanguageFeature f, std::string input) {
+ std::string_view old{languageFeatureCliCanonicalSpelling_[EnumToInt(f)]};
+ cliOptions_.erase(std::string{old});
+ languageFeatureCliCanonicalSpelling_[EnumToInt(f)] = input;
+ cliOptions_.insert({input, {f}});
}
-} // 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 insensitive) {
- llvm::StringRef inputRef{input};
- if (auto result = FortranFeaturesHelpers::parseCLILanguageFeature(
- inputRef, insensitive)) {
- EnableWarning(result->second, result->first);
- return true;
- } else if (auto result = FortranFeaturesHelpers::parseCLIUsageWarning(
- inputRef, insensitive)) {
- EnableWarning(result->second, result->first);
- return true;
- }
- return false;
+void LanguageFeatureControl::replaceCliCanonicalSpelling(
+ UsageWarning w, std::string input) {
+ std::string_view old{usageWarningCliCanonicalSpelling_[EnumToInt(w)]};
+ cliOptions_.erase(std::string{old});
+ usageWarningCliCanonicalSpelling_[EnumToInt(w)] = input;
+ cliOptions_.insert({input, {w}});
}
std::vector<const char *> LanguageFeatureControl::GetNames(
diff --git a/flang/unittests/Common/EnumClassTests.cpp b/flang/unittests/Common/EnumClassTests.cpp
index c9224a8ceba54..5034ff4f0179e 100644
--- a/flang/unittests/Common/EnumClassTests.cpp
+++ b/flang/unittests/Common/EnumClassTests.cpp
@@ -14,7 +14,6 @@ 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");
@@ -22,23 +21,15 @@ TEST(EnumClassTest, EnumToString) {
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});
+TEST(EnumClassTest, EnumClassForEach) {
+ std::string result;
+ bool first{true};
+ ForEachTestEnum([&](auto e) {
+ if (!first) {
+ result += ", ";
+ }
+ result += EnumToString(e);
+ first = false;
+ });
+ ASSERT_EQ(result, "One, Two, Three");
}
diff --git a/flang/unittests/Common/FortranFeaturesTest.cpp b/flang/unittests/Common/FortranFeaturesTest.cpp
index 367500e46af20..2093c42a449eb 100644
--- a/flang/unittests/Common/FortranFeaturesTest.cpp
+++ b/flang/unittests/Common/FortranFeaturesTest.cpp
@@ -8,68 +8,554 @@
#include "gtest/gtest.h"
#include "flang/Support/Fortran-features.h"
-#include <optional>
-namespace Fortran::common::FortranFeaturesHelpers {
+namespace Fortran::common::featuresHelpers {
-optional<std::pair<bool, UsageWarning>> parseCLIUsageWarning(
- llvm::StringRef input, bool insensitive);
-TEST(EnumClassTest, ParseCLIUsageWarning) {
- 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);
+std::string CamelCaseToLowerCaseHyphenated(std::string_view x);
- 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", true)), 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}}));
-
- EXPECT_EQ(parseCLIUsageWarning("f202x-allocatable-breaking-change", false),
- (std::optional{
- std::pair{true, UsageWarning::F202xAllocatableBreakingChange}}));
+TEST(FortranFeaturesTest, CamelCaseToLowerCaseHyphenated) {
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::BackslashEscapes)),
+ "backslash-escapes");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::OldDebugLines)),
+ "old-debug-lines");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(EnumToString(
+ LanguageFeature::FixedFormContinuationWithColumn1Ampersand)),
+ "fixed-form-continuation-with-column1-ampersand");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::LogicalAbbreviations)),
+ "logical-abbreviations");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::XOROperator)),
+ "xor-operator");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::PunctuationInNames)),
+ "punctuation-in-names");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::OptionalFreeFormSpace)),
+ "optional-free-form-space");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::BOZExtensions)),
+ "boz-extensions");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::EmptyStatement)),
+ "empty-statement");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::AlternativeNE)),
+ "alternative-ne");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::ExecutionPartNamelist)),
+ "execution-part-namelist");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::DECStructures)),
+ "dec-structures");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::DoubleComplex)),
+ "double-complex");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(EnumToString(LanguageFeature::Byte)),
+ "byte");
+ EXPECT_EQ(
+ CamelCaseToLowerCaseHyphenated(EnumToString(LanguageFeature::StarKind)),
+ "star-kind");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::ExponentMatchingKindParam)),
+ "exponent-matching-kind-param");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::QuadPrecision)),
+ "quad-precision");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::SlashInitialization)),
+ "slash-initialization");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::TripletInArrayConstructor)),
+ "triplet-in-array-constructor");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::MissingColons)),
+ "missing-colons");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::SignedComplexLiteral)),
+ "signed-complex-literal");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::OldStyleParameter)),
+ "old-style-parameter");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::ComplexConstructor)),
+ "complex-constructor");
+ EXPECT_EQ(
+ CamelCaseToLowerCaseHyphenated(EnumToString(LanguageFeature::PercentLOC)),
+ "percent-loc");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::SignedMultOperand)),
+ "signed-mult-operand");
+ EXPECT_EQ(
+ CamelCaseToLowerCaseHyphenated(EnumToString(LanguageFeature::FileName)),
+ "file-name");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::Carriagecontrol)),
+ "carriagecontrol");
+ EXPECT_EQ(
+ CamelCaseToLowerCaseHyphenated(EnumToString(LanguageFeature::Convert)),
+ "convert");
+ EXPECT_EQ(
+ CamelCaseToLowerCaseHyphenated(EnumToString(LanguageFeature::Dispose)),
+ "dispose");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::IOListLeadingComma)),
+ "io-list-leading-comma");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::AbbreviatedEditDescriptor)),
+ "abbreviated-edit-descriptor");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::ProgramParentheses)),
+ "program-parentheses");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::PercentRefAndVal)),
+ "percent-ref-and-val");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::OmitFunctionDummies)),
+ "omit-function-dummies");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::CrayPointer)),
+ "cray-pointer");
+ EXPECT_EQ(
+ CamelCaseToLowerCaseHyphenated(EnumToString(LanguageFeature::Hollerith)),
+ "hollerith");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::ArithmeticIF)),
+ "arithmetic-if");
+ EXPECT_EQ(
+ CamelCaseToLowerCaseHyphenated(EnumToString(LanguageFeature::Assign)),
+ "assign");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::AssignedGOTO)),
+ "assigned-goto");
+ EXPECT_EQ(
+ CamelCaseToLowerCaseHyphenated(EnumToString(LanguageFeature::Pause)),
+ "pause");
+ EXPECT_EQ(
+ CamelCaseToLowerCaseHyphenated(EnumToString(LanguageFeature::OpenACC)),
+ "open-acc");
+ EXPECT_EQ(
+ CamelCaseToLowerCaseHyphenated(EnumToString(LanguageFeature::OpenMP)),
+ "open-mp");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(EnumToString(LanguageFeature::CUDA)),
+ "cuda");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::CruftAfterAmpersand)),
+ "cruft-after-ampersand");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::ClassicCComments)),
+ "classic-c-comments");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::AdditionalFormats)),
+ "additional-formats");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::BigIntLiterals)),
+ "big-int-literals");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::RealDoControls)),
+ "real-do-controls");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::EquivalenceNumericWithCharacter)),
+ "equivalence-numeric-with-character");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::EquivalenceNonDefaultNumeric)),
+ "equivalence-non-default-numeric");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::EquivalenceSameNonSequence)),
+ "equivalence-same-non-sequence");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::AdditionalIntrinsics)),
+ "additional-intrinsics");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::AnonymousParents)),
+ "anonymous-parents");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::OldLabelDoEndStatements)),
+ "old-label-do-end-statements");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::LogicalIntegerAssignment)),
+ "logical-integer-assignment");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::EmptySourceFile)),
+ "empty-source-file");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::ProgramReturn)),
+ "program-return");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::ImplicitNoneTypeNever)),
+ "implicit-none-type-never");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::ImplicitNoneTypeAlways)),
+ "implicit-none-type-always");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::ImplicitNoneExternal)),
+ "implicit-none-external");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::ForwardRefImplicitNone)),
+ "forward-ref-implicit-none");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::OpenAccessAppend)),
+ "open-access-append");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::BOZAsDefaultInteger)),
+ "boz-as-default-integer");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::DistinguishableSpecifics)),
+ "distinguishable-specifics");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::DefaultSave)),
+ "default-save");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::PointerInSeqType)),
+ "pointer-in-seq-type");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::NonCharacterFormat)),
+ "non-character-format");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::SaveMainProgram)),
+ "save-main-program");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::SaveBigMainProgramVariables)),
+ "save-big-main-program-variables");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::DistinctArrayConstructorLengths)),
+ "distinct-array-constructor-lengths");
+ EXPECT_EQ(
+ CamelCaseToLowerCaseHyphenated(EnumToString(LanguageFeature::PPCVector)),
+ "ppc-vector");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::RelaxedIntentInChecking)),
+ "relaxed-intent-in-checking");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::ForwardRefImplicitNoneData)),
+ "forward-ref-implicit-none-data");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::NullActualForAllocatable)),
+ "null-actual-for-allocatable");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(EnumToString(
+ LanguageFeature::ActualIntegerConvertedToSmallerKind)),
+ "actual-integer-converted-to-smaller-kind");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::HollerithOrCharacterAsBOZ)),
+ "hollerith-or-character-as-boz");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::BindingAsProcedure)),
+ "binding-as-procedure");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::StatementFunctionExtensions)),
+ "statement-function-extensions");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(EnumToString(
+ LanguageFeature::UseGenericIntrinsicWhenSpecificDoesntMatch)),
+ "use-generic-intrinsic-when-specific-doesnt-match");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::DataStmtExtensions)),
+ "data-stmt-extensions");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::RedundantContiguous)),
+ "redundant-contiguous");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::RedundantAttribute)),
+ "redundant-attribute");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::InitBlankCommon)),
+ "init-blank-common");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::EmptyBindCDerivedType)),
+ "empty-bind-c-derived-type");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::MiscSourceExtensions)),
+ "misc-source-extensions");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::AllocateToOtherLength)),
+ "allocate-to-other-length");
+ EXPECT_EQ(
+ CamelCaseToLowerCaseHyphenated(EnumToString(LanguageFeature::LongNames)),
+ "long-names");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::IntrinsicAsSpecific)),
+ "intrinsic-as-specific");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::BenignNameClash)),
+ "benign-name-clash");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::BenignRedundancy)),
+ "benign-redundancy");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(EnumToString(
+ LanguageFeature::NullMoldAllocatableComponentValue)),
+ "null-mold-allocatable-component-value");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::NopassScalarBase)),
+ "nopass-scalar-base");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::MiscUseExtensions)),
+ "misc-use-extensions");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::ImpliedDoIndexScope)),
+ "implied-do-index-scope");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::DistinctCommonSizes)),
+ "distinct-common-sizes");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::OddIndexVariableRestrictions)),
+ "odd-index-variable-restrictions");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::IndistinguishableSpecifics)),
+ "indistinguishable-specifics");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::SubroutineAndFunctionSpecifics)),
+ "subroutine-and-function-specifics");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::EmptySequenceType)),
+ "empty-sequence-type");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::NonSequenceCrayPointee)),
+ "non-sequence-cray-pointee");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::BranchIntoConstruct)),
+ "branch-into-construct");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::BadBranchTarget)),
+ "bad-branch-target");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::HollerithPolymorphic)),
+ "hollerith-polymorphic");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::ListDirectedSize)),
+ "list-directed-size");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::NonBindCInteroperability)),
+ "non-bind-c-interoperability");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::CudaManaged)),
+ "cuda-managed");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::CudaUnified)),
+ "cuda-unified");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(EnumToString(LanguageFeature::
+ PolymorphicActualAllocatableOrPointerToMonomorphicDummy)),
+ "polymorphic-actual-allocatable-or-pointer-to-monomorphic-dummy");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::RelaxedPureDummy)),
+ "relaxed-pure-dummy");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(EnumToString(
+ LanguageFeature::UndefinableAsynchronousOrVolatileActual)),
+ "undefinable-asynchronous-or-volatile-actual");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::AutomaticInMainProgram)),
+ "automatic-in-main-program");
+ EXPECT_EQ(
+ CamelCaseToLowerCaseHyphenated(EnumToString(LanguageFeature::PrintCptr)),
+ "print-cptr");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::SavedLocalInSpecExpr)),
+ "saved-local-in-spec-expr");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::PrintNamelist)),
+ "print-namelist");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(EnumToString(
+ LanguageFeature::AssumedRankPassedToNonAssumedRank)),
+ "assumed-rank-passed-to-non-assumed-rank");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::IgnoreIrrelevantAttributes)),
+ "ignore-irrelevant-attributes");
+ EXPECT_EQ(
+ CamelCaseToLowerCaseHyphenated(EnumToString(LanguageFeature::Unsigned)),
+ "unsigned");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::AmbiguousStructureConstructor)),
+ "ambiguous-structure-constructor");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::ContiguousOkForSeqAssociation)),
+ "contiguous-ok-for-seq-association");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(LanguageFeature::ForwardRefExplicitTypeDummy)),
+ "forward-ref-explicit-type-dummy");
+ EXPECT_EQ(
+ CamelCaseToLowerCaseHyphenated(EnumToString(UsageWarning::Portability)),
+ "portability");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(UsageWarning::PointerToUndefinable)),
+ "pointer-to-undefinable");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(UsageWarning::NonTargetPassedToTarget)),
+ "non-target-passed-to-target");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(UsageWarning::PointerToPossibleNoncontiguous)),
+ "pointer-to-possible-noncontiguous");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(UsageWarning::ShortCharacterActual)),
+ "short-character-actual");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(UsageWarning::ShortArrayActual)),
+ "short-array-actual");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(UsageWarning::ImplicitInterfaceActual)),
+ "implicit-interface-actual");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(UsageWarning::PolymorphicTransferArg)),
+ "polymorphic-transfer-arg");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(UsageWarning::PointerComponentTransferArg)),
+ "pointer-component-transfer-arg");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(UsageWarning::TransferSizePresence)),
+ "transfer-size-presence");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(UsageWarning::F202XAllocatableBreakingChange)),
+ "f202-x-allocatable-breaking-change");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(UsageWarning::OptionalMustBePresent)),
+ "optional-must-be-present");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(UsageWarning::CommonBlockPadding)),
+ "common-block-padding");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(UsageWarning::LogicalVsCBool)),
+ "logical-vs-c-bool");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(UsageWarning::BindCCharLength)),
+ "bind-c-char-length");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(UsageWarning::ProcDummyArgShapes)),
+ "proc-dummy-arg-shapes");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(UsageWarning::ExternalNameConflict)),
+ "external-name-conflict");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(UsageWarning::FoldingException)),
+ "folding-exception");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(UsageWarning::FoldingAvoidsRuntimeCrash)),
+ "folding-avoids-runtime-crash");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(UsageWarning::FoldingValueChecks)),
+ "folding-value-checks");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(UsageWarning::FoldingFailure)),
+ "folding-failure");
+ EXPECT_EQ(
+ CamelCaseToLowerCaseHyphenated(EnumToString(UsageWarning::FoldingLimit)),
+ "folding-limit");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(UsageWarning::Interoperability)),
+ "interoperability");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(UsageWarning::CharacterInteroperability)),
+ "character-interoperability");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(EnumToString(UsageWarning::Bounds)),
+ "bounds");
+ EXPECT_EQ(
+ CamelCaseToLowerCaseHyphenated(EnumToString(UsageWarning::Preprocessing)),
+ "preprocessing");
+ EXPECT_EQ(
+ CamelCaseToLowerCaseHyphenated(EnumToString(UsageWarning::Scanning)),
+ "scanning");
+ EXPECT_EQ(
+ CamelCaseToLowerCaseHyphenated(EnumToString(UsageWarning::OpenAccUsage)),
+ "open-acc-usage");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(UsageWarning::ProcPointerCompatibility)),
+ "proc-pointer-compatibility");
+ EXPECT_EQ(
+ CamelCaseToLowerCaseHyphenated(EnumToString(UsageWarning::VoidMold)),
+ "void-mold");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(UsageWarning::KnownBadImplicitInterface)),
+ "known-bad-implicit-interface");
+ EXPECT_EQ(
+ CamelCaseToLowerCaseHyphenated(EnumToString(UsageWarning::EmptyCase)),
+ "empty-case");
+ EXPECT_EQ(
+ CamelCaseToLowerCaseHyphenated(EnumToString(UsageWarning::CaseOverflow)),
+ "case-overflow");
+ EXPECT_EQ(
+ CamelCaseToLowerCaseHyphenated(EnumToString(UsageWarning::CUDAUsage)),
+ "cuda-usage");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(UsageWarning::IgnoreTKRUsage)),
+ "ignore-tkr-usage");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(UsageWarning::ExternalInterfaceMismatch)),
+ "external-interface-mismatch");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(UsageWarning::DefinedOperatorArgs)),
+ "defined-operator-args");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(EnumToString(UsageWarning::Final)),
+ "final");
+ EXPECT_EQ(
+ CamelCaseToLowerCaseHyphenated(EnumToString(UsageWarning::ZeroDoStep)),
+ "zero-do-step");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(UsageWarning::UnusedForallIndex)),
+ "unused-forall-index");
+ EXPECT_EQ(
+ CamelCaseToLowerCaseHyphenated(EnumToString(UsageWarning::OpenMPUsage)),
+ "open-mp-usage");
+ EXPECT_EQ(
+ CamelCaseToLowerCaseHyphenated(EnumToString(UsageWarning::DataLength)),
+ "data-length");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(UsageWarning::IgnoredDirective)),
+ "ignored-directive");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(UsageWarning::HomonymousSpecific)),
+ "homonymous-specific");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(UsageWarning::HomonymousResult)),
+ "homonymous-result");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(UsageWarning::IgnoredIntrinsicFunctionType)),
+ "ignored-intrinsic-function-type");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(UsageWarning::PreviousScalarUse)),
+ "previous-scalar-use");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(UsageWarning::RedeclaredInaccessibleComponent)),
+ "redeclared-inaccessible-component");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(UsageWarning::ImplicitShared)),
+ "implicit-shared");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(UsageWarning::IndexVarRedefinition)),
+ "index-var-redefinition");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(UsageWarning::IncompatibleImplicitInterfaces)),
+ "incompatible-implicit-interfaces");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(UsageWarning::VectorSubscriptFinalization)),
+ "vector-subscript-finalization");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(UsageWarning::UndefinedFunctionResult)),
+ "undefined-function-result");
+ EXPECT_EQ(
+ CamelCaseToLowerCaseHyphenated(EnumToString(UsageWarning::UselessIomsg)),
+ "useless-iomsg");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(UsageWarning::MismatchingDummyProcedure)),
+ "mismatching-dummy-procedure");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(UsageWarning::SubscriptedEmptyArray)),
+ "subscripted-empty-array");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(UsageWarning::UnsignedLiteralTruncation)),
+ "unsigned-literal-truncation");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(EnumToString(
+ UsageWarning::CompatibleDeclarationsFromDistinctModules)),
+ "compatible-declarations-from-distinct-modules");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(EnumToString(
+ UsageWarning::NullActualForDefaultIntentAllocatable)),
+ "null-actual-for-default-intent-allocatable");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(EnumToString(
+ UsageWarning::UseAssociationIntoSameNameSubprogram)),
+ "use-association-into-same-name-subprogram");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(UsageWarning::HostAssociatedIntentOutInSpecExpr)),
+ "host-associated-intent-out-in-spec-expr");
+ EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
+ EnumToString(UsageWarning::NonVolatilePointerToVolatile)),
+ "non-volatile-pointer-to-volatile");
}
-} // namespace Fortran::common::FortranFeaturesHelpers
+} // namespace Fortran::common::featuresHelpers
>From ef7ad5c01361667093fb22e21dc67e2738ade5b6 Mon Sep 17 00:00:00 2001
From: Andre Kuhlenschmidt <akuhlenschmi at nvidia.com>
Date: Wed, 4 Jun 2025 14:12:32 -0700
Subject: [PATCH 11/15] tidy-up
---
.../include/flang/Support/Fortran-features.h | 1 -
flang/lib/Frontend/CompilerInvocation.cpp | 1 -
flang/lib/Support/Fortran-features.cpp | 7 -----
flang/lib/Support/enum-class.cpp | 27 -------------------
flang/unittests/Common/EnumClassTests.cpp | 5 ++--
5 files changed, 2 insertions(+), 39 deletions(-)
delete mode 100644 flang/lib/Support/enum-class.cpp
diff --git a/flang/include/flang/Support/Fortran-features.h b/flang/include/flang/Support/Fortran-features.h
index 61e7031b85988..f2d0d276c06b4 100644
--- a/flang/include/flang/Support/Fortran-features.h
+++ b/flang/include/flang/Support/Fortran-features.h
@@ -11,7 +11,6 @@
#include "Fortran.h"
#include "flang/Common/enum-set.h"
-#include <llvm/Support/raw_ostream.h>
#include <string_view>
#include <vector>
diff --git a/flang/lib/Frontend/CompilerInvocation.cpp b/flang/lib/Frontend/CompilerInvocation.cpp
index 6fa7b98ebb5dd..2945d9d48ef41 100644
--- a/flang/lib/Frontend/CompilerInvocation.cpp
+++ b/flang/lib/Frontend/CompilerInvocation.cpp
@@ -1104,7 +1104,6 @@ static bool parseDialectArgs(CompilerInvocation &res, llvm::opt::ArgList &args,
diags.Report(diagID);
}
}
-
return diags.getNumErrors() == numErrorsBefore;
}
diff --git a/flang/lib/Support/Fortran-features.cpp b/flang/lib/Support/Fortran-features.cpp
index cb3282f7b6a90..2eef233b13332 100644
--- a/flang/lib/Support/Fortran-features.cpp
+++ b/flang/lib/Support/Fortran-features.cpp
@@ -254,13 +254,6 @@ 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;
warnLanguage_.reset();
diff --git a/flang/lib/Support/enum-class.cpp b/flang/lib/Support/enum-class.cpp
deleted file mode 100644
index d6d0ee758175b..0000000000000
--- a/flang/lib/Support/enum-class.cpp
+++ /dev/null
@@ -1,27 +0,0 @@
-//===-- 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 "flang/Common/optional.h"
-#include <functional>
-
-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 (size_t i = 0; i < size; ++i) {
- if (pred(names[i])) {
- return i;
- }
- }
- return nullopt;
-}
-
-} // namespace Fortran::common::EnumClass
diff --git a/flang/unittests/Common/EnumClassTests.cpp b/flang/unittests/Common/EnumClassTests.cpp
index 5034ff4f0179e..eafba542a3b84 100644
--- a/flang/unittests/Common/EnumClassTests.cpp
+++ b/flang/unittests/Common/EnumClassTests.cpp
@@ -8,10 +8,8 @@
#include "gtest/gtest.h"
#include "flang/Common/enum-class.h"
-#include "flang/Common/template.h"
-using namespace Fortran::common;
-using namespace std;
+namespace Fortran::common {
ENUM_CLASS(TestEnum, One, Two, Three)
@@ -33,3 +31,4 @@ TEST(EnumClassTest, EnumClassForEach) {
});
ASSERT_EQ(result, "One, Two, Three");
}
+} // namespace Fortran::common
>From 598c5d6e695a61093b60e4f62b61e078fd26155f Mon Sep 17 00:00:00 2001
From: Andre Kuhlenschmidt <akuhlenschmi at nvidia.com>
Date: Wed, 4 Jun 2025 14:32:37 -0700
Subject: [PATCH 12/15] delete unneeded code
---
flang/lib/Support/CMakeLists.txt | 1 -
flang/lib/Support/Fortran-features.cpp | 5 -----
2 files changed, 6 deletions(-)
diff --git a/flang/lib/Support/CMakeLists.txt b/flang/lib/Support/CMakeLists.txt
index 9ef31a2a6dcc7..363f57ce97dae 100644
--- a/flang/lib/Support/CMakeLists.txt
+++ b/flang/lib/Support/CMakeLists.txt
@@ -44,7 +44,6 @@ 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 2eef233b13332..39accf12c0318 100644
--- a/flang/lib/Support/Fortran-features.cpp
+++ b/flang/lib/Support/Fortran-features.cpp
@@ -77,11 +77,6 @@ LanguageFeatureControl::LanguageFeatureControl() {
std::string_view{cliOption};
});
- replaceCliCanonicalSpelling(UsageWarning::F202XAllocatableBreakingChange,
- "f202x-allocatable-breaking-change");
-
- // If we need to
-
// These features must be explicitly enabled by command line options.
disable_.set(LanguageFeature::OldDebugLines);
disable_.set(LanguageFeature::OpenACC);
>From 3e9e62b5150cd7c7420f023434412e5841717250 Mon Sep 17 00:00:00 2001
From: Andre Kuhlenschmidt <akuhlenschmi at nvidia.com>
Date: Wed, 4 Jun 2025 14:57:28 -0700
Subject: [PATCH 13/15] delete unneeded headers
---
flang/include/flang/Common/enum-class.h | 1 -
flang/include/flang/Common/optional.h | 2 --
2 files changed, 3 deletions(-)
diff --git a/flang/include/flang/Common/enum-class.h b/flang/include/flang/Common/enum-class.h
index c6cdebf00dec2..a07177596f6a4 100644
--- a/flang/include/flang/Common/enum-class.h
+++ b/flang/include/flang/Common/enum-class.h
@@ -17,7 +17,6 @@
#ifndef FORTRAN_COMMON_ENUM_CLASS_H_
#define FORTRAN_COMMON_ENUM_CLASS_H_
-#include "optional.h"
#include <array>
#include <functional>
#include <string_view>
diff --git a/flang/include/flang/Common/optional.h b/flang/include/flang/Common/optional.h
index fbf0f66b59a65..72991111be577 100644
--- a/flang/include/flang/Common/optional.h
+++ b/flang/include/flang/Common/optional.h
@@ -27,9 +27,7 @@
#define FORTRAN_COMMON_OPTIONAL_H
#include "api-attrs.h"
-#include <functional>
#include <optional>
-#include <type_traits>
#if !defined(STD_OPTIONAL_UNSUPPORTED) && \
(defined(__CUDACC__) || defined(__CUDA__)) && defined(__CUDA_ARCH__)
>From c43cf360623600e9bd2474b4d3b0d19e4dc7a7fb Mon Sep 17 00:00:00 2001
From: Andre Kuhlenschmidt <akuhlenschmi at nvidia.com>
Date: Wed, 4 Jun 2025 15:01:34 -0700
Subject: [PATCH 14/15] delete spurious newline
---
flang/include/flang/Support/Fortran-features.h | 1 -
1 file changed, 1 deletion(-)
diff --git a/flang/include/flang/Support/Fortran-features.h b/flang/include/flang/Support/Fortran-features.h
index f2d0d276c06b4..2de3a6a9509c8 100644
--- a/flang/include/flang/Support/Fortran-features.h
+++ b/flang/include/flang/Support/Fortran-features.h
@@ -151,6 +151,5 @@ class LanguageFeatureControl {
bool warnAllUsage_{false};
bool disableAllWarnings_{false};
};
-
} // namespace Fortran::common
#endif // FORTRAN_SUPPORT_FORTRAN_FEATURES_H_
>From b3b58854c63a4743d2fd03ea42a3cc9bce4e845b Mon Sep 17 00:00:00 2001
From: Andre Kuhlenschmidt <akuhlenschmi at nvidia.com>
Date: Wed, 4 Jun 2025 15:53:05 -0700
Subject: [PATCH 15/15] follow naming conventions
---
flang/include/flang/Support/Fortran-features.h | 10 +++++-----
flang/lib/Frontend/CompilerInvocation.cpp | 2 +-
flang/lib/Support/Fortran-features.cpp | 14 ++++++--------
3 files changed, 12 insertions(+), 14 deletions(-)
diff --git a/flang/include/flang/Support/Fortran-features.h b/flang/include/flang/Support/Fortran-features.h
index 2de3a6a9509c8..41ed3bb56c6b7 100644
--- a/flang/include/flang/Support/Fortran-features.h
+++ b/flang/include/flang/Support/Fortran-features.h
@@ -115,15 +115,15 @@ class LanguageFeatureControl {
bool ShouldWarn(LanguageFeature f) const { return warnLanguage_.test(f); }
bool ShouldWarn(UsageWarning w) const { return warnUsage_.test(w); }
// CLI options
- bool applyCLIOption(std::string input);
- void addAlternativeCliSpelling(LanguageFeature f, std::string input) {
+ bool ApplyCLIOption(std::string input);
+ void AddAlternativeCliSpelling(LanguageFeature f, std::string input) {
cliOptions_.insert({input, {f}});
}
- void addAlternativeCliSpelling(UsageWarning w, std::string input) {
+ void AddAlternativeCliSpelling(UsageWarning w, std::string input) {
cliOptions_.insert({input, {w}});
}
- void replaceCliCanonicalSpelling(LanguageFeature f, std::string input);
- void replaceCliCanonicalSpelling(UsageWarning w, std::string input);
+ void ReplaceCliCanonicalSpelling(LanguageFeature f, std::string input);
+ void ReplaceCliCanonicalSpelling(UsageWarning w, std::string input);
std::string_view getDefaultCliSpelling(LanguageFeature f) const {
return languageFeatureCliCanonicalSpelling_[EnumToInt(f)];
};
diff --git a/flang/lib/Frontend/CompilerInvocation.cpp b/flang/lib/Frontend/CompilerInvocation.cpp
index 2945d9d48ef41..08e7e983fc5dd 100644
--- a/flang/lib/Frontend/CompilerInvocation.cpp
+++ b/flang/lib/Frontend/CompilerInvocation.cpp
@@ -995,7 +995,7 @@ static bool parseDiagArgs(CompilerInvocation &res, llvm::opt::ArgList &args,
if (wArg == "error") {
res.setWarnAsErr(true);
// -W(no-)<feature>
- } else if (!res.getFrontendOpts().features.applyCLIOption(wArg)) {
+ } else if (!res.getFrontendOpts().features.ApplyCLIOption(wArg)) {
const unsigned diagID = diags.getCustomDiagID(
clang::DiagnosticsEngine::Error, "Unknown diagnostic option: -W%0");
diags.Report(diagID) << wArg;
diff --git a/flang/lib/Support/Fortran-features.cpp b/flang/lib/Support/Fortran-features.cpp
index 39accf12c0318..6a50a48e351a5 100644
--- a/flang/lib/Support/Fortran-features.cpp
+++ b/flang/lib/Support/Fortran-features.cpp
@@ -15,11 +15,6 @@
namespace Fortran::common {
-// Namespace for helper functions for parsing CLI options
-// used instead of static so that there can be unit tests for these
-// functions.
-namespace featuresHelpers {
-
static std::vector<std::string_view> SplitCamelCase(std::string_view x) {
std::vector<std::string_view> result;
// NB, we start at 1 because the first character is never a word boundary.
@@ -42,6 +37,9 @@ static std::vector<std::string_view> SplitCamelCase(std::string_view x) {
return result;
}
+// Namespace for helper functions for parsing CLI options used instead of static
+// so that there can be unit tests for this function.
+namespace featuresHelpers {
std::string CamelCaseToLowerCaseHyphenated(std::string_view x) {
std::vector<std::string_view> words{SplitCamelCase(x)};
std::string result{};
@@ -160,7 +158,7 @@ LanguageFeatureControl::LanguageFeatureControl() {
// 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 input) {
+bool LanguageFeatureControl::ApplyCLIOption(std::string input) {
bool negated{false};
if (input.size() > 3 && input.substr(0, 3) == "no-") {
negated = true;
@@ -179,7 +177,7 @@ bool LanguageFeatureControl::applyCLIOption(std::string input) {
return false;
}
-void LanguageFeatureControl::replaceCliCanonicalSpelling(
+void LanguageFeatureControl::ReplaceCliCanonicalSpelling(
LanguageFeature f, std::string input) {
std::string_view old{languageFeatureCliCanonicalSpelling_[EnumToInt(f)]};
cliOptions_.erase(std::string{old});
@@ -187,7 +185,7 @@ void LanguageFeatureControl::replaceCliCanonicalSpelling(
cliOptions_.insert({input, {f}});
}
-void LanguageFeatureControl::replaceCliCanonicalSpelling(
+void LanguageFeatureControl::ReplaceCliCanonicalSpelling(
UsageWarning w, std::string input) {
std::string_view old{usageWarningCliCanonicalSpelling_[EnumToInt(w)]};
cliOptions_.erase(std::string{old});
More information about the flang-commits
mailing list