Skip to content

Commit bcba39a

Browse files
committed
[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
1 parent 64e4d03 commit bcba39a

File tree

16 files changed

+118
-80
lines changed

16 files changed

+118
-80
lines changed
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
//===-- include/flang/Common/enum-class.h -----------------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
// The macro
10+
// ENUM_CLASS(className, enum1, enum2, ..., enumN)
11+
// defines
12+
// enum class className { enum1, enum2, ... , enumN };
13+
// as well as the introspective utilities
14+
// static constexpr std::size_t className_enumSize{N};
15+
// static inline const std::string &EnumToString(className);
16+
17+
#ifndef FORTRAN_COMMON_ENUM_CLASS_H_
18+
#define FORTRAN_COMMON_ENUM_CLASS_H_
19+
20+
#include <array>
21+
#include <string>
22+
23+
namespace Fortran::common {
24+
25+
constexpr std::size_t CountEnumNames(const char *p) {
26+
std::size_t n{0};
27+
std::size_t any{0};
28+
for (; *p; ++p) {
29+
if (*p == ',') {
30+
n += any;
31+
any = 0;
32+
} else if (*p != ' ') {
33+
any = 1;
34+
}
35+
}
36+
return n + any;
37+
}
38+
39+
template <std::size_t ITEMS>
40+
constexpr std::array<std::string_view, ITEMS> EnumNames(const char *p) {
41+
std::array<std::string_view, ITEMS> result{""};
42+
std::size_t at{0};
43+
const char *start{nullptr};
44+
for (; *p; ++p) {
45+
if (*p == ',' || *p == ' ') {
46+
if (start) {
47+
result[at++] =
48+
std::string_view{start, static_cast<std::size_t>(p - start)};
49+
start = nullptr;
50+
}
51+
} else if (!start) {
52+
start = p;
53+
}
54+
}
55+
if (start) {
56+
result[at] = std::string_view{start, static_cast<std::size_t>(p - start)};
57+
}
58+
return result;
59+
}
60+
61+
#define ENUM_CLASS(NAME, ...) \
62+
enum class NAME { __VA_ARGS__ }; \
63+
[[maybe_unused]] static constexpr std::size_t NAME##_enumSize{ \
64+
::Fortran::common::CountEnumNames(#__VA_ARGS__)}; \
65+
[[maybe_unused]] static inline std::string_view EnumToString(NAME e) { \
66+
static const constexpr char vaArgs[]{#__VA_ARGS__}; \
67+
static const constexpr auto names{ \
68+
::Fortran::common::EnumNames<NAME##_enumSize>(vaArgs)}; \
69+
return names[static_cast<std::size_t>(e)]; \
70+
}
71+
72+
} // namespace Fortran::common
73+
#endif // FORTRAN_COMMON_ENUM_CLASS_H_

flang/include/flang/Common/enum-set.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ template <typename ENUM, std::size_t BITS> class EnumSet {
207207

208208
template <typename STREAM>
209209
STREAM &Dump(
210-
STREAM &o, const std::string &EnumToString(enumerationType)) const {
210+
STREAM &o, std::string_view EnumToString(enumerationType)) const {
211211
char sep{'{'};
212212
IterateOverMembers([&](auto e) {
213213
o << sep << EnumToString(e);

flang/include/flang/Common/idioms.h

Lines changed: 1 addition & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#error g++ >= 7.2 is required
2424
#endif
2525

26+
#include "enum-class.h"
2627
#include "visit.h"
2728
#include <array>
2829
#include <functional>
@@ -125,32 +126,6 @@ template <typename A> struct ListItemCount {
125126
const std::size_t value;
126127
};
127128

128-
#define ENUM_CLASS(NAME, ...) \
129-
enum class NAME { __VA_ARGS__ }; \
130-
[[maybe_unused]] static constexpr std::size_t NAME##_enumSize{[] { \
131-
enum { __VA_ARGS__ }; \
132-
return Fortran::common::ListItemCount{__VA_ARGS__}.value; \
133-
}()}; \
134-
struct NAME##_struct { \
135-
NAME##_struct(const NAME##_struct &) = delete; \
136-
NAME##_struct &operator=(const NAME##_struct &) = delete; \
137-
static NAME##_struct &instance() { \
138-
static NAME##_struct s; \
139-
return s; \
140-
} \
141-
std::array<std::string, NAME##_enumSize> _enumNames; \
142-
\
143-
private: \
144-
NAME##_struct() { \
145-
Fortran::common::BuildIndexToString( \
146-
#__VA_ARGS__, _enumNames.data(), NAME##_enumSize); \
147-
} \
148-
~NAME##_struct() {} \
149-
}; \
150-
[[maybe_unused]] static inline const std::string &EnumToString(NAME e) { \
151-
return NAME##_struct::instance()._enumNames[static_cast<int>(e)]; \
152-
}
153-
154129
// Check that a pointer is non-null and dereference it
155130
#define DEREF(p) Fortran::common::Deref(p, __FILE__, __LINE__)
156131

flang/include/flang/Evaluate/type.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -373,7 +373,7 @@ template <TypeCategory CATEGORY> struct SomeKind {
373373
static constexpr TypeCategory category{CATEGORY};
374374
constexpr bool operator==(const SomeKind &) const { return true; }
375375
static std::string AsFortran() {
376-
return "Some"s + common::EnumToString(category);
376+
return "Some"s + std::string{common::EnumToString(category)};
377377
}
378378
};
379379

flang/include/flang/Parser/characters.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ inline constexpr char ToLowerCaseLetter(char &&ch) {
6565
return IsUpperCaseLetter(ch) ? ch - 'A' + 'a' : ch;
6666
}
6767

68-
inline std::string ToLowerCaseLetters(const std::string &str) {
68+
inline std::string ToLowerCaseLetters(std::string_view str) {
6969
std::string lowered{str};
7070
for (char &ch : lowered) {
7171
ch = ToLowerCaseLetter(ch);
@@ -81,7 +81,7 @@ inline constexpr char ToUpperCaseLetter(char &&ch) {
8181
return IsLowerCaseLetter(ch) ? ch - 'a' + 'A' : ch;
8282
}
8383

84-
inline std::string ToUpperCaseLetters(const std::string &str) {
84+
inline std::string ToUpperCaseLetters(std::string_view str) {
8585
std::string raised{str};
8686
for (char &ch : raised) {
8787
ch = ToUpperCaseLetter(ch);

flang/include/flang/Parser/dump-parse-tree.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ class ParseTreeDumper {
3737
static constexpr const char *GetNodeName(const T &) { return N; }
3838
#define NODE_ENUM(T, E) \
3939
static std::string GetNodeName(const T::E &x) { \
40-
return #E " = "s + T::EnumToString(x); \
40+
return #E " = "s + std::string{T::EnumToString(x)}; \
4141
}
4242
#define NODE(T1, T2) NODE_NAME(T1::T2, #T2)
4343
NODE_NAME(bool, "bool")

flang/include/flang/Parser/message.h

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -96,9 +96,9 @@ constexpr MessageFixedText operator""_en_US(const char str[], std::size_t n) {
9696

9797
// The construction of a MessageFormattedText uses a MessageFixedText
9898
// as a vsnprintf() formatting string that is applied to the
99-
// following arguments. CharBlock and std::string argument
100-
// values are also supported; they are automatically converted into
101-
// char pointers that are suitable for '%s' formatting.
99+
// following arguments. CharBlock, std::string, and std::string_view
100+
// argument values are also supported; they are automatically converted
101+
// into char pointers that are suitable for '%s' formatting.
102102
class MessageFormattedText {
103103
public:
104104
template <typename... A>
@@ -128,19 +128,16 @@ class MessageFormattedText {
128128
static_assert(!std::is_class_v<std::decay_t<A>>);
129129
return x;
130130
}
131-
template <typename A> A Convert(A &x) {
132-
static_assert(!std::is_class_v<std::decay_t<A>>);
133-
return x;
134-
}
135131
template <typename A> common::IfNoLvalue<A, A> Convert(A &&x) {
136132
static_assert(!std::is_class_v<std::decay_t<A>>);
137133
return std::move(x);
138134
}
139135
const char *Convert(const char *s) { return s; }
140136
const char *Convert(char *s) { return s; }
141137
const char *Convert(const std::string &);
142-
const char *Convert(std::string &);
143138
const char *Convert(std::string &&);
139+
const char *Convert(const std::string_view &);
140+
const char *Convert(std::string_view &&);
144141
const char *Convert(CharBlock);
145142
std::intmax_t Convert(std::int64_t x) { return x; }
146143
std::uintmax_t Convert(std::uint64_t x) { return x; }

flang/lib/Common/idioms.cpp

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
#include <cstdarg>
1111
#include <cstdio>
1212
#include <cstdlib>
13-
#include <regex>
1413

1514
namespace Fortran::common {
1615

@@ -24,22 +23,4 @@ namespace Fortran::common {
2423
std::abort();
2524
}
2625

27-
// Converts the comma separated list of enumerators into tokens which are then
28-
// stored into the provided array of strings. This is intended for use from the
29-
// expansion of ENUM_CLASS.
30-
void BuildIndexToString(
31-
const char *commaSeparated, std::string enumNames[], int enumSize) {
32-
std::string input(commaSeparated);
33-
std::regex reg("\\s*,\\s*");
34-
35-
std::sregex_token_iterator iter(input.begin(), input.end(), reg, -1);
36-
std::sregex_token_iterator end;
37-
int index = 0;
38-
while (iter != end) {
39-
enumNames[index] = *iter;
40-
iter++;
41-
index++;
42-
}
43-
CHECK(index == enumSize);
44-
}
4526
} // namespace Fortran::common

flang/lib/Evaluate/characteristics.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1000,7 +1000,7 @@ bool Procedure::IsCompatibleWith(const Procedure &actual, std::string *whyNot,
10001000
auto sep{": "s};
10011001
*whyNot = "incompatible procedure attributes";
10021002
differences.IterateOverMembers([&](Attr x) {
1003-
*whyNot += sep + EnumToString(x);
1003+
*whyNot += sep + std::string{EnumToString(x)};
10041004
sep = ", ";
10051005
});
10061006
}

flang/lib/Lower/IO.cpp

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2091,10 +2091,10 @@ mlir::Value genInquireSpec<Fortran::parser::InquireSpec::CharVar>(
20912091
builder.createConvert(loc, specFuncTy.getInput(0), cookie),
20922092
builder.createIntegerConstant(
20932093
loc, specFuncTy.getInput(1),
2094-
Fortran::runtime::io::HashInquiryKeyword(
2094+
Fortran::runtime::io::HashInquiryKeyword(std::string{
20952095
Fortran::parser::InquireSpec::CharVar::EnumToString(
2096-
std::get<Fortran::parser::InquireSpec::CharVar::Kind>(var.t))
2097-
.c_str())),
2096+
std::get<Fortran::parser::InquireSpec::CharVar::Kind>(var.t))}
2097+
.c_str())),
20982098
builder.createConvert(loc, specFuncTy.getInput(2), fir::getBase(str)),
20992099
builder.createConvert(loc, specFuncTy.getInput(3), fir::getLen(str))};
21002100
return builder.create<fir::CallOp>(loc, specFunc, args).getResult(0);
@@ -2128,10 +2128,10 @@ mlir::Value genInquireSpec<Fortran::parser::InquireSpec::IntVar>(
21282128
builder.createConvert(loc, specFuncTy.getInput(0), cookie),
21292129
builder.createIntegerConstant(
21302130
loc, specFuncTy.getInput(1),
2131-
Fortran::runtime::io::HashInquiryKeyword(
2131+
Fortran::runtime::io::HashInquiryKeyword(std::string{
21322132
Fortran::parser::InquireSpec::IntVar::EnumToString(
2133-
std::get<Fortran::parser::InquireSpec::IntVar::Kind>(var.t))
2134-
.c_str())),
2133+
std::get<Fortran::parser::InquireSpec::IntVar::Kind>(var.t))}
2134+
.c_str())),
21352135
builder.createConvert(loc, specFuncTy.getInput(2), addr),
21362136
builder.createConvert(loc, specFuncTy.getInput(3), kind)};
21372137
return builder.create<fir::CallOp>(loc, specFunc, args).getResult(0);
@@ -2165,9 +2165,9 @@ mlir::Value genInquireSpec<Fortran::parser::InquireSpec::LogVar>(
21652165
else
21662166
args.push_back(builder.createIntegerConstant(
21672167
loc, specFuncTy.getInput(1),
2168-
Fortran::runtime::io::HashInquiryKeyword(
2169-
Fortran::parser::InquireSpec::LogVar::EnumToString(logVarKind)
2170-
.c_str())));
2168+
Fortran::runtime::io::HashInquiryKeyword(std::string{
2169+
Fortran::parser::InquireSpec::LogVar::EnumToString(logVarKind)}
2170+
.c_str())));
21712171
args.push_back(builder.createConvert(loc, specFuncTy.getInput(2), addr));
21722172
auto call = builder.create<fir::CallOp>(loc, specFunc, args);
21732173
boolRefToLogical(loc, builder, addr);

flang/lib/Parser/message.cpp

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,13 +70,18 @@ const char *MessageFormattedText::Convert(const std::string &s) {
7070
return conversions_.front().c_str();
7171
}
7272

73-
const char *MessageFormattedText::Convert(std::string &s) {
73+
const char *MessageFormattedText::Convert(std::string &&s) {
74+
conversions_.emplace_front(std::move(s));
75+
return conversions_.front().c_str();
76+
}
77+
78+
const char *MessageFormattedText::Convert(const std::string_view &s) {
7479
conversions_.emplace_front(s);
7580
return conversions_.front().c_str();
7681
}
7782

78-
const char *MessageFormattedText::Convert(std::string &&s) {
79-
conversions_.emplace_front(std::move(s));
83+
const char *MessageFormattedText::Convert(std::string_view &&s) {
84+
conversions_.emplace_front(s);
8085
return conversions_.front().c_str();
8186
}
8287

flang/lib/Parser/unparse.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2621,6 +2621,7 @@ class UnparseVisitor {
26212621
void PutKeywordLetter(char);
26222622
void Word(const char *);
26232623
void Word(const std::string &);
2624+
void Word(const std::string_view &);
26242625
void Indent() { indent_ += indentationAmount_; }
26252626
void Outdent() {
26262627
CHECK(indent_ >= indentationAmount_);
@@ -2777,6 +2778,12 @@ void UnparseVisitor::Word(const char *str) {
27772778

27782779
void UnparseVisitor::Word(const std::string &str) { Word(str.c_str()); }
27792780

2781+
void UnparseVisitor::Word(const std::string_view &str) {
2782+
for (std::size_t j{0}; j < str.length(); ++j) {
2783+
PutKeywordLetter(str[j]);
2784+
}
2785+
}
2786+
27802787
template <typename A>
27812788
void Unparse(llvm::raw_ostream &out, const A &root, Encoding encoding,
27822789
bool capitalizeKeywords, bool backslashEscapes,

flang/lib/Semantics/attr.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ std::string AttrToString(Attr attr) {
3030
case Attr::INTENT_OUT:
3131
return "INTENT(OUT)";
3232
default:
33-
return EnumToString(attr);
33+
return std::string{EnumToString(attr)};
3434
}
3535
}
3636

flang/lib/Semantics/expression.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ using common::LanguageFeature;
4343
using common::NumericOperator;
4444
using common::TypeCategory;
4545

46-
static inline std::string ToUpperCase(const std::string &str) {
46+
static inline std::string ToUpperCase(std::string_view str) {
4747
return parser::ToUpperCaseLetters(str);
4848
}
4949

flang/lib/Semantics/mod-file.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ llvm::raw_ostream &PutAttrs(llvm::raw_ostream &, Attrs,
5959

6060
static llvm::raw_ostream &PutAttr(llvm::raw_ostream &, Attr);
6161
static llvm::raw_ostream &PutType(llvm::raw_ostream &, const DeclTypeSpec &);
62-
static llvm::raw_ostream &PutLower(llvm::raw_ostream &, const std::string &);
62+
static llvm::raw_ostream &PutLower(llvm::raw_ostream &, std::string_view);
6363
static std::error_code WriteFile(
6464
const std::string &, const std::string &, bool = true);
6565
static bool FileContentsMatch(
@@ -797,7 +797,7 @@ llvm::raw_ostream &PutType(llvm::raw_ostream &os, const DeclTypeSpec &type) {
797797
return PutLower(os, type.AsFortran());
798798
}
799799

800-
llvm::raw_ostream &PutLower(llvm::raw_ostream &os, const std::string &str) {
800+
llvm::raw_ostream &PutLower(llvm::raw_ostream &os, std::string_view str) {
801801
for (char c : str) {
802802
os << parser::ToLowerCaseLetter(c);
803803
}

flang/lib/Semantics/symbol.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -671,20 +671,20 @@ bool GenericKind::IsOperator() const {
671671
std::string GenericKind::ToString() const {
672672
return common::visit(
673673
common::visitors {
674-
[](const OtherKind &x) { return EnumToString(x); },
674+
[](const OtherKind &x) { return std::string{EnumToString(x)}; },
675675
[](const DefinedIo &x) { return AsFortran(x).ToString(); },
676676
#if !__clang__ && __GNUC__ == 7 && __GNUC_MINOR__ == 2
677677
[](const common::NumericOperator &x) {
678-
return common::EnumToString(x);
678+
return std::string{common::EnumToString(x)};
679679
},
680680
[](const common::LogicalOperator &x) {
681-
return common::EnumToString(x);
681+
return std::string{common::EnumToString(x)};
682682
},
683683
[](const common::RelationalOperator &x) {
684-
return common::EnumToString(x);
684+
return std::string{common::EnumToString(x)};
685685
},
686686
#else
687-
[](const auto &x) { return common::EnumToString(x); },
687+
[](const auto &x) { return std::string{common::EnumToString(x)}; },
688688
#endif
689689
},
690690
u);

0 commit comments

Comments
 (0)