[flang-commits] [flang] bcba39a - [flang] Restore ENUM_CLASS() to be compilation-time code

Peter Klausler via flang-commits flang-commits at lists.llvm.org
Fri Dec 2 09:55:58 PST 2022


Author: Peter Klausler
Date: 2022-12-02T09:55:45-08:00
New Revision: bcba39a56fd4e1debe3854d564c3e03bf0a50ee6

URL: https://github.com/llvm/llvm-project/commit/bcba39a56fd4e1debe3854d564c3e03bf0a50ee6
DIFF: https://github.com/llvm/llvm-project/commit/bcba39a56fd4e1debe3854d564c3e03bf0a50ee6.diff

LOG: [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

Added: 
    flang/include/flang/Common/enum-class.h

Modified: 
    flang/include/flang/Common/enum-set.h
    flang/include/flang/Common/idioms.h
    flang/include/flang/Evaluate/type.h
    flang/include/flang/Parser/characters.h
    flang/include/flang/Parser/dump-parse-tree.h
    flang/include/flang/Parser/message.h
    flang/lib/Common/idioms.cpp
    flang/lib/Evaluate/characteristics.cpp
    flang/lib/Lower/IO.cpp
    flang/lib/Parser/message.cpp
    flang/lib/Parser/unparse.cpp
    flang/lib/Semantics/attr.cpp
    flang/lib/Semantics/expression.cpp
    flang/lib/Semantics/mod-file.cpp
    flang/lib/Semantics/symbol.cpp

Removed: 
    


################################################################################
diff  --git a/flang/include/flang/Common/enum-class.h b/flang/include/flang/Common/enum-class.h
new file mode 100644
index 0000000000000..8077520938b31
--- /dev/null
+++ b/flang/include/flang/Common/enum-class.h
@@ -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_

diff  --git a/flang/include/flang/Common/enum-set.h b/flang/include/flang/Common/enum-set.h
index 3b0229104d9f3..5290b76debee8 100644
--- a/flang/include/flang/Common/enum-set.h
+++ b/flang/include/flang/Common/enum-set.h
@@ -207,7 +207,7 @@ template <typename ENUM, std::size_t BITS> class EnumSet {
 
   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);

diff  --git a/flang/include/flang/Common/idioms.h b/flang/include/flang/Common/idioms.h
index e23ea2c9bda59..7695ebb47dbba 100644
--- a/flang/include/flang/Common/idioms.h
+++ b/flang/include/flang/Common/idioms.h
@@ -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__)
 

diff  --git a/flang/include/flang/Evaluate/type.h b/flang/include/flang/Evaluate/type.h
index 47ab714c03970..6ebf54be5ba49 100644
--- a/flang/include/flang/Evaluate/type.h
+++ b/flang/include/flang/Evaluate/type.h
@@ -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)};
   }
 };
 

diff  --git a/flang/include/flang/Parser/characters.h b/flang/include/flang/Parser/characters.h
index 120560625da29..1a7d395be2bf7 100644
--- a/flang/include/flang/Parser/characters.h
+++ b/flang/include/flang/Parser/characters.h
@@ -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);

diff  --git a/flang/include/flang/Parser/dump-parse-tree.h b/flang/include/flang/Parser/dump-parse-tree.h
index 66ab5dd6d0237..f96632f3064b6 100644
--- a/flang/include/flang/Parser/dump-parse-tree.h
+++ b/flang/include/flang/Parser/dump-parse-tree.h
@@ -37,7 +37,7 @@ class ParseTreeDumper {
   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")

diff  --git a/flang/include/flang/Parser/message.h b/flang/include/flang/Parser/message.h
index 5ff5b98dba840..0659e04d51df0 100644
--- a/flang/include/flang/Parser/message.h
+++ b/flang/include/flang/Parser/message.h
@@ -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 @@ class MessageFormattedText {
     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 @@ class MessageFormattedText {
   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; }

diff  --git a/flang/lib/Common/idioms.cpp b/flang/lib/Common/idioms.cpp
index 95aebd1ec80a4..536a5c2e5479d 100644
--- a/flang/lib/Common/idioms.cpp
+++ b/flang/lib/Common/idioms.cpp
@@ -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

diff  --git a/flang/lib/Evaluate/characteristics.cpp b/flang/lib/Evaluate/characteristics.cpp
index 1795751fbf045..25a427914b5cb 100644
--- a/flang/lib/Evaluate/characteristics.cpp
+++ b/flang/lib/Evaluate/characteristics.cpp
@@ -1000,7 +1000,7 @@ bool Procedure::IsCompatibleWith(const Procedure &actual, std::string *whyNot,
       auto sep{": "s};
       *whyNot = "incompatible procedure attributes";
       
diff erences.IterateOverMembers([&](Attr x) {
-        *whyNot += sep + EnumToString(x);
+        *whyNot += sep + std::string{EnumToString(x)};
         sep = ", ";
       });
     }

diff  --git a/flang/lib/Lower/IO.cpp b/flang/lib/Lower/IO.cpp
index 4b08b06e013d3..317bd5d9597d6 100644
--- a/flang/lib/Lower/IO.cpp
+++ b/flang/lib/Lower/IO.cpp
@@ -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);

diff  --git a/flang/lib/Parser/message.cpp b/flang/lib/Parser/message.cpp
index d729c8464bbce..a56337d65e5f3 100644
--- a/flang/lib/Parser/message.cpp
+++ b/flang/lib/Parser/message.cpp
@@ -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();
 }
 

diff  --git a/flang/lib/Parser/unparse.cpp b/flang/lib/Parser/unparse.cpp
index 9c7990845350f..a8fb6676ada3e 100644
--- a/flang/lib/Parser/unparse.cpp
+++ b/flang/lib/Parser/unparse.cpp
@@ -2621,6 +2621,7 @@ class UnparseVisitor {
   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,

diff  --git a/flang/lib/Semantics/attr.cpp b/flang/lib/Semantics/attr.cpp
index b9b0f327352da..a447672c39cc2 100644
--- a/flang/lib/Semantics/attr.cpp
+++ b/flang/lib/Semantics/attr.cpp
@@ -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)};
   }
 }
 

diff  --git a/flang/lib/Semantics/expression.cpp b/flang/lib/Semantics/expression.cpp
index 182e83eeea944..c59a5f543c606 100644
--- a/flang/lib/Semantics/expression.cpp
+++ b/flang/lib/Semantics/expression.cpp
@@ -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);
 }
 

diff  --git a/flang/lib/Semantics/mod-file.cpp b/flang/lib/Semantics/mod-file.cpp
index 3659ead0a568d..0f6117b26a614 100644
--- a/flang/lib/Semantics/mod-file.cpp
+++ b/flang/lib/Semantics/mod-file.cpp
@@ -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);
   }

diff  --git a/flang/lib/Semantics/symbol.cpp b/flang/lib/Semantics/symbol.cpp
index 4fe6ee4bd0076..67acf24cd254d 100644
--- a/flang/lib/Semantics/symbol.cpp
+++ b/flang/lib/Semantics/symbol.cpp
@@ -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);


        


More information about the flang-commits mailing list