diff --git a/flang/lib/parser/idioms.cc b/flang/lib/parser/idioms.cc index 4600ee196244..af238791efd7 100644 --- a/flang/lib/parser/idioms.cc +++ b/flang/lib/parser/idioms.cc @@ -15,5 +15,24 @@ namespace parser { fputc('\n', stderr); std::abort(); } + +// Convert the int index of an enumerator to a string. +// enumNames is a list of the names, separated by commas with optional spaces. +// This is intended for use from the expansion of ENUM_CLASS. +std::string EnumIndexToString(int index, const char *enumNames) { + const char *p{enumNames}; + for (; index > 0; --index, ++p) { + for (; *p && *p != ','; ++p) { + } + } + for (; *p == ' '; ++p) { + } + CHECK(*p != '\0'); + const char *q = p; + for (; *q && *q != ' ' && *q != ','; ++q) { + } + return std::string(p, q - p); +} + } // namespace parser } // namespace Fortran diff --git a/flang/lib/parser/idioms.h b/flang/lib/parser/idioms.h index 04fa18ec028f..0048e6e81db7 100644 --- a/flang/lib/parser/idioms.h +++ b/flang/lib/parser/idioms.h @@ -102,6 +102,16 @@ template struct BadType : std::false_type {}; } \ } \ template constexpr bool T { class_trait_ns_##T::trait_value() } + +// Define enum class NAME with the given enumerators, and also a +// static function EnumToString that maps enumerators to std::string. +std::string EnumIndexToString(int index, const char *names); +#define ENUM_CLASS(NAME, ...) \ + enum class NAME { __VA_ARGS__ }; \ + static inline std::string EnumToString(NAME e) \ + { return Fortran::parser::EnumIndexToString( \ + static_cast(e), #__VA_ARGS__); } + } // namespace parser } // namespace Fortran #endif // FORTRAN_PARSER_IDIOMS_H_ diff --git a/flang/lib/parser/parse-tree.h b/flang/lib/parser/parse-tree.h index 56cc0715603b..41a704dfddc4 100644 --- a/flang/lib/parser/parse-tree.h +++ b/flang/lib/parser/parse-tree.h @@ -94,14 +94,6 @@ CLASS_TRAIT(TupleTrait); WRAPPER_CLASS_BOILERPLATE(classname, type); \ } -// Enumeration types in classes can be defined with this macro, -// which also captures the names of the enums for formatting. -// Invocations an be followed by declarators and must be followed by -// a semicolon. -#define DEFINE_NESTED_ENUM_CLASS(ENUMTYPE, ...) \ - static constexpr const char *ENUMTYPE##AsString{#__VA_ARGS__}; \ - enum class ENUMTYPE { __VA_ARGS__ } - namespace Fortran { namespace parser { @@ -517,8 +509,8 @@ WRAPPER_CLASS(DefinedOpName, Name); // R610 extended-intrinsic-op -> intrinsic-operator struct DefinedOperator { UNION_CLASS_BOILERPLATE(DefinedOperator); - DEFINE_NESTED_ENUM_CLASS(IntrinsicOperator, Power, Multiply, Divide, Add, - Subtract, Concat, LT, LE, EQ, NE, GE, GT, NOT, AND, OR, XOR, EQV, NEQV); + ENUM_CLASS(IntrinsicOperator, Power, Multiply, Divide, Add, Subtract, Concat, + LT, LE, EQ, NE, GE, GT, NOT, AND, OR, XOR, EQV, NEQV) std::variant u; }; @@ -530,10 +522,11 @@ using ObjectName = Name; // IMPORT , ONLY : import-name-list | IMPORT , NONE | IMPORT , ALL struct ImportStmt { BOILERPLATE(ImportStmt); - DEFINE_NESTED_ENUM_CLASS(Kind, Default, Only, None, All) kind{Kind::Default}; + ENUM_CLASS(Kind, Default, Only, None, All) ImportStmt(Kind &&k) : kind{k} {} ImportStmt(std::list &&n) : names(std::move(n)) {} ImportStmt(Kind &&, std::list &&); + Kind kind{Kind::Default}; std::list names; }; @@ -802,7 +795,7 @@ struct ConstantValue { // R807 access-spec -> PUBLIC | PRIVATE struct AccessSpec { - DEFINE_NESTED_ENUM_CLASS(Kind, Public, Private); + ENUM_CLASS(Kind, Public, Private) WRAPPER_CLASS_BOILERPLATE(AccessSpec, Kind); }; @@ -846,7 +839,7 @@ struct TypeParamDecl { // integer-type-spec , type-param-attr-spec :: type-param-decl-list // R734 type-param-attr-spec -> KIND | LEN struct TypeParamDefStmt { - DEFINE_NESTED_ENUM_CLASS(KindOrLen, Kind, Len); // R734 + ENUM_CLASS(KindOrLen, Kind, Len) // R734 TUPLE_CLASS_BOILERPLATE(TypeParamDefStmt); std::tuple> t; }; @@ -1226,7 +1219,7 @@ struct ArraySpec { // R826 intent-spec -> IN | OUT | INOUT struct IntentSpec { - DEFINE_NESTED_ENUM_CLASS(Intent, In, Out, InOut); + ENUM_CLASS(Intent, In, Out, InOut) WRAPPER_CLASS_BOILERPLATE(IntentSpec, Intent); }; @@ -1303,7 +1296,7 @@ WRAPPER_CLASS(AsynchronousStmt, std::list); // R833 bind-entity -> entity-name | / common-block-name / struct BindEntity { TUPLE_CLASS_BOILERPLATE(BindEntity); - DEFINE_NESTED_ENUM_CLASS(Kind, Object, Common); + ENUM_CLASS(Kind, Object, Common) std::tuple t; }; @@ -1430,7 +1423,7 @@ WRAPPER_CLASS(ProtectedStmt, std::list); // R858 proc-pointer-name -> name struct SavedEntity { TUPLE_CLASS_BOILERPLATE(SavedEntity); - DEFINE_NESTED_ENUM_CLASS(Kind, Object, ProcPointer, Common); + ENUM_CLASS(Kind, Object, ProcPointer, Common) std::tuple t; }; @@ -1464,7 +1457,7 @@ struct ImplicitSpec { // R866 implicit-name-spec -> EXTERNAL | TYPE struct ImplicitStmt { UNION_CLASS_BOILERPLATE(ImplicitStmt); - DEFINE_NESTED_ENUM_CLASS(ImplicitNoneNameSpec, External, Type); // R866 + ENUM_CLASS(ImplicitNoneNameSpec, External, Type) // R866 std::variant, std::list> u; }; @@ -2353,7 +2346,7 @@ struct StopCode { // R1161 error-stop-stmt -> // ERROR STOP [stop-code] [, QUIET = scalar-logical-expr] struct StopStmt { - DEFINE_NESTED_ENUM_CLASS(Kind, Stop, ErrorStop); + ENUM_CLASS(Kind, Stop, ErrorStop) TUPLE_CLASS_BOILERPLATE(StopStmt); std::tuple, std::optional> t; }; @@ -2469,9 +2462,8 @@ WRAPPER_CLASS(ErrLabel, Label); struct ConnectSpec { UNION_CLASS_BOILERPLATE(ConnectSpec); struct CharExpr { - DEFINE_NESTED_ENUM_CLASS(Kind, Access, Action, Asynchronous, Blank, Decimal, - Delim, Encoding, Form, Pad, Position, Round, Sign, - Dispose /*extension*/); + ENUM_CLASS(Kind, Access, Action, Asynchronous, Blank, Decimal, Delim, + Encoding, Form, Pad, Position, Round, Sign, Dispose /*extension*/) TUPLE_CLASS_BOILERPLATE(CharExpr); std::tuple t; }; @@ -2526,8 +2518,7 @@ WRAPPER_CLASS(EorLabel, Label); struct IoControlSpec { UNION_CLASS_BOILERPLATE(IoControlSpec); struct CharExpr { - DEFINE_NESTED_ENUM_CLASS( - Kind, Advance, Blank, Decimal, Delim, Pad, Round, Sign); + ENUM_CLASS(Kind, Advance, Blank, Decimal, Delim, Pad, Round, Sign) TUPLE_CLASS_BOILERPLATE(CharExpr); std::tuple t; }; @@ -2680,20 +2671,19 @@ WRAPPER_CLASS(FlushStmt, std::list); struct InquireSpec { UNION_CLASS_BOILERPLATE(InquireSpec); struct CharVar { - DEFINE_NESTED_ENUM_CLASS(Kind, Access, Action, Asynchronous, Blank, Decimal, - Delim, Direct, Encoding, Form, Formatted, Iomsg, Name, Pad, Position, - Read, Readwrite, Round, Sequential, Sign, Stream, Status, Unformatted, - Write); + ENUM_CLASS(Kind, Access, Action, Asynchronous, Blank, Decimal, Delim, + Direct, Encoding, Form, Formatted, Iomsg, Name, Pad, Position, Read, + Readwrite, Round, Sequential, Sign, Stream, Status, Unformatted, Write) TUPLE_CLASS_BOILERPLATE(CharVar); std::tuple t; }; struct IntVar { - DEFINE_NESTED_ENUM_CLASS(Kind, Iostat, Nextrec, Number, Pos, Recl, Size); + ENUM_CLASS(Kind, Iostat, Nextrec, Number, Pos, Recl, Size) TUPLE_CLASS_BOILERPLATE(IntVar); std::tuple t; }; struct LogVar { - DEFINE_NESTED_ENUM_CLASS(Kind, Exist, Named, Opened, Pending); + ENUM_CLASS(Kind, Exist, Named, Opened, Pending) TUPLE_CLASS_BOILERPLATE(LogVar); std::tuple>> t; }; @@ -2866,7 +2856,7 @@ struct Only { // R1410 module-nature -> INTRINSIC | NON_INTRINSIC struct UseStmt { BOILERPLATE(UseStmt); - DEFINE_NESTED_ENUM_CLASS(ModuleNature, Intrinsic, Non_Intrinsic); // R1410 + ENUM_CLASS(ModuleNature, Intrinsic, Non_Intrinsic) // R1410 template UseStmt(std::optional &&nat, Name &&n, std::list &&x) : nature(std::move(nat)), moduleName(std::move(n)), u(std::move(x)) {} @@ -2979,7 +2969,7 @@ struct InterfaceBody { // R1506 procedure-stmt -> [MODULE] PROCEDURE [::] specific-procedure-list struct ProcedureStmt { - DEFINE_NESTED_ENUM_CLASS(Kind, ModuleProcedure, Procedure); + ENUM_CLASS(Kind, ModuleProcedure, Procedure) TUPLE_CLASS_BOILERPLATE(ProcedureStmt); std::tuple> t; }; diff --git a/flang/lib/parser/unparse.cc b/flang/lib/parser/unparse.cc index eaee8cd741c6..0d9841984d0c 100644 --- a/flang/lib/parser/unparse.cc +++ b/flang/lib/parser/unparse.cc @@ -82,7 +82,7 @@ public: case DefinedOperator::IntrinsicOperator::GT: Put('>'); break; default: Put('.'); - PutEnum(static_cast(x), DefinedOperator::IntrinsicOperatorAsString); + Word(DefinedOperator::EnumToString(x)); Put('.'); } return false; @@ -1994,22 +1994,22 @@ public: return false; } -#define WALK_NESTED_ENUM(ENUMTYPE) \ - bool Pre(const ENUMTYPE &x) { \ - PutEnum(static_cast(x), ENUMTYPE##AsString); \ +#define WALK_NESTED_ENUM(CLASS, ENUM) \ + bool Pre(const CLASS::ENUM &x) { \ + Word(CLASS::EnumToString(x)); \ return false; \ } - WALK_NESTED_ENUM(AccessSpec::Kind) // R807 - WALK_NESTED_ENUM(TypeParamDefStmt::KindOrLen) // R734 - WALK_NESTED_ENUM(IntentSpec::Intent) // R826 - WALK_NESTED_ENUM(ImplicitStmt::ImplicitNoneNameSpec) // R866 - WALK_NESTED_ENUM(ConnectSpec::CharExpr::Kind) // R1205 - WALK_NESTED_ENUM(IoControlSpec::CharExpr::Kind) - WALK_NESTED_ENUM(InquireSpec::CharVar::Kind) - WALK_NESTED_ENUM(InquireSpec::IntVar::Kind) - WALK_NESTED_ENUM(InquireSpec::LogVar::Kind) - WALK_NESTED_ENUM(ProcedureStmt::Kind) // R1506 - WALK_NESTED_ENUM(UseStmt::ModuleNature) // R1410 + WALK_NESTED_ENUM(AccessSpec, Kind) // R807 + WALK_NESTED_ENUM(TypeParamDefStmt, KindOrLen) // R734 + WALK_NESTED_ENUM(IntentSpec, Intent) // R826 + WALK_NESTED_ENUM(ImplicitStmt, ImplicitNoneNameSpec) // R866 + WALK_NESTED_ENUM(ConnectSpec::CharExpr, Kind) // R1205 + WALK_NESTED_ENUM(IoControlSpec::CharExpr, Kind) + WALK_NESTED_ENUM(InquireSpec::CharVar, Kind) + WALK_NESTED_ENUM(InquireSpec::IntVar, Kind) + WALK_NESTED_ENUM(InquireSpec::LogVar, Kind) + WALK_NESTED_ENUM(ProcedureStmt, Kind) // R1506 + WALK_NESTED_ENUM(UseStmt, ModuleNature) // R1410 #undef WALK_NESTED_ENUM void Done() const { CHECK(indent_ == 0); } @@ -2020,8 +2020,8 @@ private: void Put(const std::string &); void PutKeywordLetter(char); void PutQuoted(const std::string &); - void PutEnum(int, const char *); void Word(const char *); + void Word(const std::string &); void Indent() { indent_ += indentationAmount_; } void Outdent() { CHECK(indent_ >= indentationAmount_); @@ -2144,27 +2144,16 @@ void UnparseVisitor::PutQuoted(const std::string &str) { Put('"'); } -void UnparseVisitor::PutEnum(int n, const char *enumNames) { - const char *p{enumNames}; - for (; n > 0; --n, ++p) { - for (; *p && *p != ','; ++p) { - } - } - while (*p == ' ') { - ++p; - } - CHECK(*p != '\0'); - for (; *p && *p != ' ' && *p != ','; ++p) { - PutKeywordLetter(*p); - } -} - void UnparseVisitor::Word(const char *str) { for (; *str != '\0'; ++str) { PutKeywordLetter(*str); } } +void UnparseVisitor::Word(const std::string &str) { + Word(str.c_str()); +} + void Unparse(std::ostream &out, const Program &program, Encoding encoding, bool capitalizeKeywords) { UnparseVisitor visitor{out, 1, encoding, capitalizeKeywords}; diff --git a/flang/lib/semantics/attr.cc b/flang/lib/semantics/attr.cc index 234832060bcc..b492c3f9477c 100644 --- a/flang/lib/semantics/attr.cc +++ b/flang/lib/semantics/attr.cc @@ -7,38 +7,6 @@ namespace semantics { constexpr static size_t toInt(Attr attr) { return static_cast(attr); } -static const char *attrToString[] = { - [toInt(Attr::ABSTRACT)] = "ABSTRACT", - [toInt(Attr::ALLOCATABLE)] = "ALLOCATABLE", - [toInt(Attr::ASYNCHRONOUS)] = "ASYNCHRONOUS", - [toInt(Attr::BIND_C)] = "BIND_C", - [toInt(Attr::CONTIGUOUS)] = "CONTIGUOUS", - [toInt(Attr::DEFERRED)] = "DEFERRED", - [toInt(Attr::ELEMENTAL)] = "ELEMENTAL", - [toInt(Attr::EXTERNAL)] = "EXTERNAL", - [toInt(Attr::IMPURE)] = "IMPURE", - [toInt(Attr::INTENT_IN)] = "INTENT_IN", - [toInt(Attr::INTENT_OUT)] = "INTENT_OUT", - [toInt(Attr::INTRINSIC)] = "INTRINSIC", - [toInt(Attr::MODULE)] = "MODULE", - [toInt(Attr::NON_OVERRIDABLE)] = "NON_OVERRIDABLE", - [toInt(Attr::NON_RECURSIVE)] = "NON_RECURSIVE", - [toInt(Attr::NOPASS)] = "NOPASS", - [toInt(Attr::OPTIONAL)] = "OPTIONAL", - [toInt(Attr::PARAMETER)] = "PARAMETER", - [toInt(Attr::PASS)] = "PASS", - [toInt(Attr::POINTER)] = "POINTER", - [toInt(Attr::PRIVATE)] = "PRIVATE", - [toInt(Attr::PROTECTED)] = "PROTECTED", - [toInt(Attr::PUBLIC)] = "PUBLIC", - [toInt(Attr::PURE)] = "PURE", - [toInt(Attr::RECURSIVE)] = "RECURSIVE", - [toInt(Attr::SAVE)] = "SAVE", - [toInt(Attr::TARGET)] = "TARGET", - [toInt(Attr::VALUE)] = "VALUE", - [toInt(Attr::VOLATILE)] = "VOLATILE", -}; - const Attrs Attrs::EMPTY; Attrs::Attrs(std::initializer_list attrs) { @@ -74,7 +42,7 @@ void Attrs::CheckValid(const Attrs &allowed) const { } std::ostream &operator<<(std::ostream &o, Attr attr) { - return o << attrToString[toInt(attr)]; + return o << EnumToString(attr); } std::ostream &operator<<(std::ostream &o, const Attrs &attrs) { @@ -84,7 +52,7 @@ std::ostream &operator<<(std::ostream &o, const Attrs &attrs) { if (n++) { o << ", "; } - o << attrToString[i]; + o << EnumToString(static_cast(i)); } } return o; diff --git a/flang/lib/semantics/attr.h b/flang/lib/semantics/attr.h index 80de37a1b1ab..e6ff77e400c0 100644 --- a/flang/lib/semantics/attr.h +++ b/flang/lib/semantics/attr.h @@ -1,6 +1,7 @@ #ifndef FORTRAN_ATTR_H_ #define FORTRAN_ATTR_H_ +#include "../parser/idioms.h" #include #include #include @@ -8,38 +9,13 @@ namespace Fortran { namespace semantics { + // All available attributes. -enum class Attr { - ABSTRACT, - ALLOCATABLE, - ASYNCHRONOUS, - BIND_C, - CONTIGUOUS, - DEFERRED, - ELEMENTAL, - EXTERNAL, - IMPURE, - INTENT_IN, - INTENT_OUT, - INTRINSIC, - MODULE, - NON_OVERRIDABLE, - NON_RECURSIVE, - NOPASS, - OPTIONAL, - PARAMETER, - PASS, - POINTER, - PRIVATE, - PROTECTED, - PUBLIC, - PURE, - RECURSIVE, - SAVE, - TARGET, - VALUE, - VOLATILE, -}; +ENUM_CLASS(Attr, ABSTRACT, ALLOCATABLE, ASYNCHRONOUS, BIND_C, CONTIGUOUS, + DEFERRED, ELEMENTAL, EXTERNAL, IMPURE, INTENT_IN, INTENT_OUT, INTRINSIC, + MODULE, NON_OVERRIDABLE, NON_RECURSIVE, NOPASS, OPTIONAL, PARAMETER, PASS, + POINTER, PRIVATE, PROTECTED, PUBLIC, PURE, RECURSIVE, SAVE, TARGET, VALUE, + VOLATILE) // Set of attributes class Attrs {