diff --git a/flang/lib/Parser/basic-parsers.h b/flang/lib/Parser/basic-parsers.h --- a/flang/lib/Parser/basic-parsers.h +++ b/flang/lib/Parser/basic-parsers.h @@ -800,13 +800,21 @@ // must discard its result in order to be compatible in type with other // parsers in an alternative, e.g. "x >> ok || y >> ok" is type-safe even // when x and y have distinct result types. -constexpr struct OkParser { +#ifndef _MS_VER +constexpr +#endif +struct OkParser { using resultType = Success; constexpr OkParser() {} static constexpr std::optional Parse(ParseState &) { return Success{}; } -} ok; +} +#ifndef _MS_VER +ok; +#else +; constexpr OkParser ok; +#endif // A variant of recovery() above for convenience. template diff --git a/flang/lib/Parser/expr-parsers.cpp b/flang/lib/Parser/expr-parsers.cpp --- a/flang/lib/Parser/expr-parsers.cpp +++ b/flang/lib/Parser/expr-parsers.cpp @@ -119,7 +119,10 @@ // R1005 add-operand -> [add-operand mult-op] mult-operand // R1008 mult-op -> * | / // The left recursion in the grammar is implemented iteratively. -constexpr struct AddOperand { +#ifndef _MS_VER +constexpr +#endif +struct AddOperand { using resultType = Expr; constexpr AddOperand() {} static inline std::optional Parse(ParseState &state) { @@ -142,7 +145,12 @@ } return result; } -} addOperand; +} +#ifndef _MS_VER +addOperand; +#else +; constexpr AddOperand addOperand; +#endif // R1006 level-2-expr -> [[level-2-expr] add-op] add-operand // R1009 add-op -> + | - @@ -151,7 +159,10 @@ // by means of a missing first operand; e.g., 2*-3 is valid in C but not // standard Fortran. We accept unary + and - to appear before any primary // as an extension. -constexpr struct Level2Expr { +#ifndef _MS_VER +constexpr +#endif +struct Level2Expr { using resultType = Expr; constexpr Level2Expr() {} static inline std::optional Parse(ParseState &state) { @@ -179,13 +190,21 @@ } return result; } -} level2Expr; +} +#ifndef _MS_VER +level2Expr; +#else +; constexpr Level2Expr level2Expr; +#endif // R1010 level-3-expr -> [level-3-expr concat-op] level-2-expr // R1011 concat-op -> // // Concatenation (//) is left-associative for parsing performance, although // one would never notice if it were right-associated. -constexpr struct Level3Expr { +#ifndef _MS_VER +constexpr +#endif +struct Level3Expr { using resultType = Expr; constexpr Level3Expr() {} static inline std::optional Parse(ParseState &state) { @@ -203,14 +222,22 @@ } return result; } -} level3Expr; +} +#ifndef _MS_VER +level3Expr; +#else +; constexpr Level3Expr level3Expr; +#endif // R1012 level-4-expr -> [level-3-expr rel-op] level-3-expr // R1013 rel-op -> // .EQ. | .NE. | .LT. | .LE. | .GT. | .GE. | // == | /= | < | <= | > | >= @ | <> // N.B. relations are not recursive (i.e., LOGICAL is not ordered) -constexpr struct Level4Expr { +#ifndef _MS_VER +constexpr +#endif +struct Level4Expr { using resultType = Expr; constexpr Level4Expr() {} static inline std::optional Parse(ParseState &state) { @@ -252,17 +279,30 @@ } return result; } -} level4Expr; +} +#ifndef _MS_VER +level4Expr; +#else +; constexpr Level4Expr level4Expr; +#endif // R1014 and-operand -> [not-op] level-4-expr // R1018 not-op -> .NOT. // N.B. Fortran's .NOT. binds less tightly than its comparison operators do. // PGI/Intel extension: accept multiple .NOT. operators -constexpr struct AndOperand { +#ifndef _MS_VER +constexpr +#endif +struct AndOperand { using resultType = Expr; constexpr AndOperand() {} static inline std::optional Parse(ParseState &); -} andOperand; +} +#ifndef _MS_VER +andOperand; +#else +; constexpr AndOperand andOperand; +#endif // Match a logical operator or, optionally, its abbreviation. inline constexpr auto logicalOp(const char *op, const char *abbrev) { @@ -283,7 +323,10 @@ // R1015 or-operand -> [or-operand and-op] and-operand // R1019 and-op -> .AND. // .AND. is left-associative -constexpr struct OrOperand { +#ifndef _MS_VER +constexpr +#endif +struct OrOperand { using resultType = Expr; constexpr OrOperand() {} static inline std::optional Parse(ParseState &state) { @@ -303,12 +346,20 @@ } return result; } -} orOperand; +} +#ifndef _MS_VER +orOperand; +#else +; constexpr OrOperand orOperand; +#endif // R1016 equiv-operand -> [equiv-operand or-op] or-operand // R1020 or-op -> .OR. // .OR. is left-associative -constexpr struct EquivOperand { +#ifndef _MS_VER +constexpr +#endif +struct EquivOperand { using resultType = Expr; constexpr EquivOperand() {} static inline std::optional Parse(ParseState &state) { @@ -327,13 +378,21 @@ } return result; } -} equivOperand; +} +#ifndef _MS_VER +equivOperand; +#else +; constexpr EquivOperand equivOperand; +#endif // R1017 level-5-expr -> [level-5-expr equiv-op] equiv-operand // R1021 equiv-op -> .EQV. | .NEQV. // Logical equivalence is left-associative. // Extension: .XOR. as synonym for .NEQV. -constexpr struct Level5Expr { +#ifndef _MS_VER +constexpr +#endif +struct Level5Expr { using resultType = Expr; constexpr Level5Expr() {} static inline std::optional Parse(ParseState &state) { @@ -358,7 +417,12 @@ } return result; } -} level5Expr; +} +#ifndef _MS_VER +level5Expr; +#else +; constexpr Level5Expr level5Expr; +#endif // R1022 expr -> [expr defined-binary-op] level-5-expr // Defined binary operators associate leftwards. diff --git a/flang/lib/Parser/token-parsers.h b/flang/lib/Parser/token-parsers.h --- a/flang/lib/Parser/token-parsers.h +++ b/flang/lib/Parser/token-parsers.h @@ -62,7 +62,10 @@ constexpr auto digit{"0123456789"_ch}; // Skips over optional spaces. Always succeeds. -constexpr struct Space { +#ifndef _MS_VER +constexpr +#endif +struct Space { using resultType = Success; constexpr Space() {} static std::optional Parse(ParseState &state) { @@ -74,7 +77,12 @@ } return {Success{}}; } -} space; +} +#ifndef _MS_VER +space; +#else +; constexpr Space space; +#endif // Skips a space that in free form requires a warning if it precedes a // character that could begin an identifier or keyword. Always succeeds. @@ -85,7 +93,10 @@ } } -constexpr struct SpaceCheck { +#ifndef _MS_VER +constexpr +#endif +struct SpaceCheck { using resultType = Success; constexpr SpaceCheck() {} static std::optional Parse(ParseState &state) { @@ -101,7 +112,12 @@ } return {Success{}}; } -} spaceCheck; +} +#ifndef _MS_VER +spaceCheck; +#else +; constexpr SpaceCheck spaceCheck; +#endif // Matches a token string. Spaces in the token string denote where // spaces may appear in the source; they can be made mandatory for @@ -346,7 +362,10 @@ // R711 digit-string -> digit [digit]... // N.B. not a token -- no space is skipped -constexpr struct DigitString { +#ifndef _MS_VER +constexpr +#endif +struct DigitString { using resultType = CharBlock; static std::optional Parse(ParseState &state) { if (std::optional ch1{state.PeekAtNextChar()}) { @@ -363,7 +382,12 @@ } return std::nullopt; } -} digitString; +} +#ifndef _MS_VER +digitString; +#else +; constexpr DigitString digitString; +#endif struct SignedIntLiteralConstantWithoutKind { using resultType = CharBlock; @@ -380,7 +404,10 @@ } }; -constexpr struct DigitString64 { +#ifndef _MS_VER +constexpr +#endif +struct DigitString64 { using resultType = std::uint64_t; static std::optional Parse(ParseState &state) { std::optional firstDigit{digit.Parse(state)}; @@ -406,7 +433,12 @@ } return {value}; } -} digitString64; +} +#ifndef _MS_VER +digitString64; +#else +; constexpr DigitString64 digitString64; +#endif // R707 signed-int-literal-constant -> [sign] int-literal-constant // N.B. Spaces are consumed before and after the sign, since the sign @@ -537,7 +569,10 @@ } }; -constexpr struct ConsumedAllInputParser { +#ifndef _MS_VER +constexpr +#endif +struct ConsumedAllInputParser { using resultType = Success; constexpr ConsumedAllInputParser() {} static inline std::optional Parse(ParseState &state) { @@ -546,7 +581,12 @@ } return std::nullopt; } -} consumedAllInput; +} +#ifndef _MS_VER +consumedAllInput; +#else +; constexpr ConsumedAllInputParser consumedAllInput; +#endif template struct SkipPast { using resultType = Success; @@ -599,7 +639,10 @@ // the ones that specify the source form) that might appear before the // next statement. Skip over empty statements (bare semicolons) when // not in strict standard conformance mode. Always succeeds. -constexpr struct SkipStuffBeforeStatement { +#ifndef _MS_VER +constexpr +#endif +struct SkipStuffBeforeStatement { using resultType = Success; static std::optional Parse(ParseState &state) { if (UserState * ustate{state.userState()}) { @@ -637,7 +680,12 @@ } return {Success{}}; } -} skipStuffBeforeStatement; +} +#ifndef _MS_VER +skipStuffBeforeStatement; +#else +; constexpr SkipStuffBeforeStatement skipStuffBeforeStatement; +#endif // R602 underscore -> _ constexpr auto underscore{"_"_ch};