[flang] Restore ENUM_CLASS() to be compilation-time code
Rework some recent changes to the ENUM_CLASS() macro so that all of the construction of enumerator-to-name string mapping data structures is again performed at compilation time. Differential Revision: https://reviews.llvm.org/D137859
This commit is contained in:
73
flang/include/flang/Common/enum-class.h
Normal file
73
flang/include/flang/Common/enum-class.h
Normal file
@@ -0,0 +1,73 @@
|
||||
//===-- include/flang/Common/enum-class.h -----------------------*- 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// The macro
|
||||
// ENUM_CLASS(className, enum1, enum2, ..., enumN)
|
||||
// defines
|
||||
// enum class className { enum1, enum2, ... , enumN };
|
||||
// as well as the introspective utilities
|
||||
// static constexpr std::size_t className_enumSize{N};
|
||||
// static inline const std::string &EnumToString(className);
|
||||
|
||||
#ifndef FORTRAN_COMMON_ENUM_CLASS_H_
|
||||
#define FORTRAN_COMMON_ENUM_CLASS_H_
|
||||
|
||||
#include <array>
|
||||
#include <string>
|
||||
|
||||
namespace Fortran::common {
|
||||
|
||||
constexpr std::size_t CountEnumNames(const char *p) {
|
||||
std::size_t n{0};
|
||||
std::size_t any{0};
|
||||
for (; *p; ++p) {
|
||||
if (*p == ',') {
|
||||
n += any;
|
||||
any = 0;
|
||||
} else if (*p != ' ') {
|
||||
any = 1;
|
||||
}
|
||||
}
|
||||
return n + any;
|
||||
}
|
||||
|
||||
template <std::size_t ITEMS>
|
||||
constexpr std::array<std::string_view, ITEMS> EnumNames(const char *p) {
|
||||
std::array<std::string_view, ITEMS> result{""};
|
||||
std::size_t at{0};
|
||||
const char *start{nullptr};
|
||||
for (; *p; ++p) {
|
||||
if (*p == ',' || *p == ' ') {
|
||||
if (start) {
|
||||
result[at++] =
|
||||
std::string_view{start, static_cast<std::size_t>(p - start)};
|
||||
start = nullptr;
|
||||
}
|
||||
} else if (!start) {
|
||||
start = p;
|
||||
}
|
||||
}
|
||||
if (start) {
|
||||
result[at] = std::string_view{start, static_cast<std::size_t>(p - start)};
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#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 inline std::string_view EnumToString(NAME e) { \
|
||||
static const constexpr char vaArgs[]{#__VA_ARGS__}; \
|
||||
static const constexpr auto names{ \
|
||||
::Fortran::common::EnumNames<NAME##_enumSize>(vaArgs)}; \
|
||||
return names[static_cast<std::size_t>(e)]; \
|
||||
}
|
||||
|
||||
} // namespace Fortran::common
|
||||
#endif // FORTRAN_COMMON_ENUM_CLASS_H_
|
||||
@@ -207,7 +207,7 @@ public:
|
||||
|
||||
template <typename STREAM>
|
||||
STREAM &Dump(
|
||||
STREAM &o, const std::string &EnumToString(enumerationType)) const {
|
||||
STREAM &o, std::string_view EnumToString(enumerationType)) const {
|
||||
char sep{'{'};
|
||||
IterateOverMembers([&](auto e) {
|
||||
o << sep << EnumToString(e);
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#error g++ >= 7.2 is required
|
||||
#endif
|
||||
|
||||
#include "enum-class.h"
|
||||
#include "visit.h"
|
||||
#include <array>
|
||||
#include <functional>
|
||||
@@ -125,32 +126,6 @@ template <typename A> struct ListItemCount {
|
||||
const std::size_t value;
|
||||
};
|
||||
|
||||
#define ENUM_CLASS(NAME, ...) \
|
||||
enum class NAME { __VA_ARGS__ }; \
|
||||
[[maybe_unused]] static constexpr std::size_t NAME##_enumSize{[] { \
|
||||
enum { __VA_ARGS__ }; \
|
||||
return Fortran::common::ListItemCount{__VA_ARGS__}.value; \
|
||||
}()}; \
|
||||
struct NAME##_struct { \
|
||||
NAME##_struct(const NAME##_struct &) = delete; \
|
||||
NAME##_struct &operator=(const NAME##_struct &) = delete; \
|
||||
static NAME##_struct &instance() { \
|
||||
static NAME##_struct s; \
|
||||
return s; \
|
||||
} \
|
||||
std::array<std::string, NAME##_enumSize> _enumNames; \
|
||||
\
|
||||
private: \
|
||||
NAME##_struct() { \
|
||||
Fortran::common::BuildIndexToString( \
|
||||
#__VA_ARGS__, _enumNames.data(), NAME##_enumSize); \
|
||||
} \
|
||||
~NAME##_struct() {} \
|
||||
}; \
|
||||
[[maybe_unused]] static inline const std::string &EnumToString(NAME e) { \
|
||||
return NAME##_struct::instance()._enumNames[static_cast<int>(e)]; \
|
||||
}
|
||||
|
||||
// Check that a pointer is non-null and dereference it
|
||||
#define DEREF(p) Fortran::common::Deref(p, __FILE__, __LINE__)
|
||||
|
||||
|
||||
@@ -373,7 +373,7 @@ template <TypeCategory CATEGORY> struct SomeKind {
|
||||
static constexpr TypeCategory category{CATEGORY};
|
||||
constexpr bool operator==(const SomeKind &) const { return true; }
|
||||
static std::string AsFortran() {
|
||||
return "Some"s + common::EnumToString(category);
|
||||
return "Some"s + std::string{common::EnumToString(category)};
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@ inline constexpr char ToLowerCaseLetter(char &&ch) {
|
||||
return IsUpperCaseLetter(ch) ? ch - 'A' + 'a' : ch;
|
||||
}
|
||||
|
||||
inline std::string ToLowerCaseLetters(const std::string &str) {
|
||||
inline std::string ToLowerCaseLetters(std::string_view str) {
|
||||
std::string lowered{str};
|
||||
for (char &ch : lowered) {
|
||||
ch = ToLowerCaseLetter(ch);
|
||||
@@ -81,7 +81,7 @@ inline constexpr char ToUpperCaseLetter(char &&ch) {
|
||||
return IsLowerCaseLetter(ch) ? ch - 'a' + 'A' : ch;
|
||||
}
|
||||
|
||||
inline std::string ToUpperCaseLetters(const std::string &str) {
|
||||
inline std::string ToUpperCaseLetters(std::string_view str) {
|
||||
std::string raised{str};
|
||||
for (char &ch : raised) {
|
||||
ch = ToUpperCaseLetter(ch);
|
||||
|
||||
@@ -37,7 +37,7 @@ public:
|
||||
static constexpr const char *GetNodeName(const T &) { return N; }
|
||||
#define NODE_ENUM(T, E) \
|
||||
static std::string GetNodeName(const T::E &x) { \
|
||||
return #E " = "s + T::EnumToString(x); \
|
||||
return #E " = "s + std::string{T::EnumToString(x)}; \
|
||||
}
|
||||
#define NODE(T1, T2) NODE_NAME(T1::T2, #T2)
|
||||
NODE_NAME(bool, "bool")
|
||||
|
||||
@@ -96,9 +96,9 @@ constexpr MessageFixedText operator""_en_US(const char str[], std::size_t n) {
|
||||
|
||||
// The construction of a MessageFormattedText uses a MessageFixedText
|
||||
// as a vsnprintf() formatting string that is applied to the
|
||||
// following arguments. CharBlock and std::string argument
|
||||
// values are also supported; they are automatically converted into
|
||||
// char pointers that are suitable for '%s' formatting.
|
||||
// following arguments. CharBlock, std::string, and std::string_view
|
||||
// argument values are also supported; they are automatically converted
|
||||
// into char pointers that are suitable for '%s' formatting.
|
||||
class MessageFormattedText {
|
||||
public:
|
||||
template <typename... A>
|
||||
@@ -128,10 +128,6 @@ private:
|
||||
static_assert(!std::is_class_v<std::decay_t<A>>);
|
||||
return x;
|
||||
}
|
||||
template <typename A> A Convert(A &x) {
|
||||
static_assert(!std::is_class_v<std::decay_t<A>>);
|
||||
return x;
|
||||
}
|
||||
template <typename A> common::IfNoLvalue<A, A> Convert(A &&x) {
|
||||
static_assert(!std::is_class_v<std::decay_t<A>>);
|
||||
return std::move(x);
|
||||
@@ -139,8 +135,9 @@ private:
|
||||
const char *Convert(const char *s) { return s; }
|
||||
const char *Convert(char *s) { return s; }
|
||||
const char *Convert(const std::string &);
|
||||
const char *Convert(std::string &);
|
||||
const char *Convert(std::string &&);
|
||||
const char *Convert(const std::string_view &);
|
||||
const char *Convert(std::string_view &&);
|
||||
const char *Convert(CharBlock);
|
||||
std::intmax_t Convert(std::int64_t x) { return x; }
|
||||
std::uintmax_t Convert(std::uint64_t x) { return x; }
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
#include <cstdarg>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <regex>
|
||||
|
||||
namespace Fortran::common {
|
||||
|
||||
@@ -24,22 +23,4 @@ namespace Fortran::common {
|
||||
std::abort();
|
||||
}
|
||||
|
||||
// Converts the comma separated list of enumerators into tokens which are then
|
||||
// stored into the provided array of strings. This is intended for use from the
|
||||
// expansion of ENUM_CLASS.
|
||||
void BuildIndexToString(
|
||||
const char *commaSeparated, std::string enumNames[], int enumSize) {
|
||||
std::string input(commaSeparated);
|
||||
std::regex reg("\\s*,\\s*");
|
||||
|
||||
std::sregex_token_iterator iter(input.begin(), input.end(), reg, -1);
|
||||
std::sregex_token_iterator end;
|
||||
int index = 0;
|
||||
while (iter != end) {
|
||||
enumNames[index] = *iter;
|
||||
iter++;
|
||||
index++;
|
||||
}
|
||||
CHECK(index == enumSize);
|
||||
}
|
||||
} // namespace Fortran::common
|
||||
|
||||
@@ -1000,7 +1000,7 @@ bool Procedure::IsCompatibleWith(const Procedure &actual, std::string *whyNot,
|
||||
auto sep{": "s};
|
||||
*whyNot = "incompatible procedure attributes";
|
||||
differences.IterateOverMembers([&](Attr x) {
|
||||
*whyNot += sep + EnumToString(x);
|
||||
*whyNot += sep + std::string{EnumToString(x)};
|
||||
sep = ", ";
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2091,10 +2091,10 @@ mlir::Value genInquireSpec<Fortran::parser::InquireSpec::CharVar>(
|
||||
builder.createConvert(loc, specFuncTy.getInput(0), cookie),
|
||||
builder.createIntegerConstant(
|
||||
loc, specFuncTy.getInput(1),
|
||||
Fortran::runtime::io::HashInquiryKeyword(
|
||||
Fortran::runtime::io::HashInquiryKeyword(std::string{
|
||||
Fortran::parser::InquireSpec::CharVar::EnumToString(
|
||||
std::get<Fortran::parser::InquireSpec::CharVar::Kind>(var.t))
|
||||
.c_str())),
|
||||
std::get<Fortran::parser::InquireSpec::CharVar::Kind>(var.t))}
|
||||
.c_str())),
|
||||
builder.createConvert(loc, specFuncTy.getInput(2), fir::getBase(str)),
|
||||
builder.createConvert(loc, specFuncTy.getInput(3), fir::getLen(str))};
|
||||
return builder.create<fir::CallOp>(loc, specFunc, args).getResult(0);
|
||||
@@ -2128,10 +2128,10 @@ mlir::Value genInquireSpec<Fortran::parser::InquireSpec::IntVar>(
|
||||
builder.createConvert(loc, specFuncTy.getInput(0), cookie),
|
||||
builder.createIntegerConstant(
|
||||
loc, specFuncTy.getInput(1),
|
||||
Fortran::runtime::io::HashInquiryKeyword(
|
||||
Fortran::runtime::io::HashInquiryKeyword(std::string{
|
||||
Fortran::parser::InquireSpec::IntVar::EnumToString(
|
||||
std::get<Fortran::parser::InquireSpec::IntVar::Kind>(var.t))
|
||||
.c_str())),
|
||||
std::get<Fortran::parser::InquireSpec::IntVar::Kind>(var.t))}
|
||||
.c_str())),
|
||||
builder.createConvert(loc, specFuncTy.getInput(2), addr),
|
||||
builder.createConvert(loc, specFuncTy.getInput(3), kind)};
|
||||
return builder.create<fir::CallOp>(loc, specFunc, args).getResult(0);
|
||||
@@ -2165,9 +2165,9 @@ mlir::Value genInquireSpec<Fortran::parser::InquireSpec::LogVar>(
|
||||
else
|
||||
args.push_back(builder.createIntegerConstant(
|
||||
loc, specFuncTy.getInput(1),
|
||||
Fortran::runtime::io::HashInquiryKeyword(
|
||||
Fortran::parser::InquireSpec::LogVar::EnumToString(logVarKind)
|
||||
.c_str())));
|
||||
Fortran::runtime::io::HashInquiryKeyword(std::string{
|
||||
Fortran::parser::InquireSpec::LogVar::EnumToString(logVarKind)}
|
||||
.c_str())));
|
||||
args.push_back(builder.createConvert(loc, specFuncTy.getInput(2), addr));
|
||||
auto call = builder.create<fir::CallOp>(loc, specFunc, args);
|
||||
boolRefToLogical(loc, builder, addr);
|
||||
|
||||
@@ -70,13 +70,18 @@ const char *MessageFormattedText::Convert(const std::string &s) {
|
||||
return conversions_.front().c_str();
|
||||
}
|
||||
|
||||
const char *MessageFormattedText::Convert(std::string &s) {
|
||||
const char *MessageFormattedText::Convert(std::string &&s) {
|
||||
conversions_.emplace_front(std::move(s));
|
||||
return conversions_.front().c_str();
|
||||
}
|
||||
|
||||
const char *MessageFormattedText::Convert(const std::string_view &s) {
|
||||
conversions_.emplace_front(s);
|
||||
return conversions_.front().c_str();
|
||||
}
|
||||
|
||||
const char *MessageFormattedText::Convert(std::string &&s) {
|
||||
conversions_.emplace_front(std::move(s));
|
||||
const char *MessageFormattedText::Convert(std::string_view &&s) {
|
||||
conversions_.emplace_front(s);
|
||||
return conversions_.front().c_str();
|
||||
}
|
||||
|
||||
|
||||
@@ -2621,6 +2621,7 @@ private:
|
||||
void PutKeywordLetter(char);
|
||||
void Word(const char *);
|
||||
void Word(const std::string &);
|
||||
void Word(const std::string_view &);
|
||||
void Indent() { indent_ += indentationAmount_; }
|
||||
void Outdent() {
|
||||
CHECK(indent_ >= indentationAmount_);
|
||||
@@ -2777,6 +2778,12 @@ void UnparseVisitor::Word(const char *str) {
|
||||
|
||||
void UnparseVisitor::Word(const std::string &str) { Word(str.c_str()); }
|
||||
|
||||
void UnparseVisitor::Word(const std::string_view &str) {
|
||||
for (std::size_t j{0}; j < str.length(); ++j) {
|
||||
PutKeywordLetter(str[j]);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename A>
|
||||
void Unparse(llvm::raw_ostream &out, const A &root, Encoding encoding,
|
||||
bool capitalizeKeywords, bool backslashEscapes,
|
||||
|
||||
@@ -30,7 +30,7 @@ std::string AttrToString(Attr attr) {
|
||||
case Attr::INTENT_OUT:
|
||||
return "INTENT(OUT)";
|
||||
default:
|
||||
return EnumToString(attr);
|
||||
return std::string{EnumToString(attr)};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ using common::LanguageFeature;
|
||||
using common::NumericOperator;
|
||||
using common::TypeCategory;
|
||||
|
||||
static inline std::string ToUpperCase(const std::string &str) {
|
||||
static inline std::string ToUpperCase(std::string_view str) {
|
||||
return parser::ToUpperCaseLetters(str);
|
||||
}
|
||||
|
||||
|
||||
@@ -59,7 +59,7 @@ llvm::raw_ostream &PutAttrs(llvm::raw_ostream &, Attrs,
|
||||
|
||||
static llvm::raw_ostream &PutAttr(llvm::raw_ostream &, Attr);
|
||||
static llvm::raw_ostream &PutType(llvm::raw_ostream &, const DeclTypeSpec &);
|
||||
static llvm::raw_ostream &PutLower(llvm::raw_ostream &, const std::string &);
|
||||
static llvm::raw_ostream &PutLower(llvm::raw_ostream &, std::string_view);
|
||||
static std::error_code WriteFile(
|
||||
const std::string &, const std::string &, bool = true);
|
||||
static bool FileContentsMatch(
|
||||
@@ -797,7 +797,7 @@ llvm::raw_ostream &PutType(llvm::raw_ostream &os, const DeclTypeSpec &type) {
|
||||
return PutLower(os, type.AsFortran());
|
||||
}
|
||||
|
||||
llvm::raw_ostream &PutLower(llvm::raw_ostream &os, const std::string &str) {
|
||||
llvm::raw_ostream &PutLower(llvm::raw_ostream &os, std::string_view str) {
|
||||
for (char c : str) {
|
||||
os << parser::ToLowerCaseLetter(c);
|
||||
}
|
||||
|
||||
@@ -671,20 +671,20 @@ bool GenericKind::IsOperator() const {
|
||||
std::string GenericKind::ToString() const {
|
||||
return common::visit(
|
||||
common::visitors {
|
||||
[](const OtherKind &x) { return EnumToString(x); },
|
||||
[](const OtherKind &x) { return std::string{EnumToString(x)}; },
|
||||
[](const DefinedIo &x) { return AsFortran(x).ToString(); },
|
||||
#if !__clang__ && __GNUC__ == 7 && __GNUC_MINOR__ == 2
|
||||
[](const common::NumericOperator &x) {
|
||||
return common::EnumToString(x);
|
||||
return std::string{common::EnumToString(x)};
|
||||
},
|
||||
[](const common::LogicalOperator &x) {
|
||||
return common::EnumToString(x);
|
||||
return std::string{common::EnumToString(x)};
|
||||
},
|
||||
[](const common::RelationalOperator &x) {
|
||||
return common::EnumToString(x);
|
||||
return std::string{common::EnumToString(x)};
|
||||
},
|
||||
#else
|
||||
[](const auto &x) { return common::EnumToString(x); },
|
||||
[](const auto &x) { return std::string{common::EnumToString(x)}; },
|
||||
#endif
|
||||
},
|
||||
u);
|
||||
|
||||
Reference in New Issue
Block a user