aboutsummaryrefslogtreecommitdiff
path: root/flang/lib/Parser/expr-parsers.cpp
diff options
context:
space:
mode:
authorPeter Klausler <35819229+klausler@users.noreply.github.com>2024-06-03 11:58:18 -0700
committerGitHub <noreply@github.com>2024-06-03 11:58:18 -0700
commit68f4e46c432ea2f1f8d33c6dc9345f6e2afeec4a (patch)
tree3e1aa1b44a58c91e3829f4404cb400bac2a36113 /flang/lib/Parser/expr-parsers.cpp
parente44cea597cd835af9cbbd154f812aea3151af18b (diff)
downloadllvm-68f4e46c432ea2f1f8d33c6dc9345f6e2afeec4a.zip
llvm-68f4e46c432ea2f1f8d33c6dc9345f6e2afeec4a.tar.gz
llvm-68f4e46c432ea2f1f8d33c6dc9345f6e2afeec4a.tar.bz2
[flang] Adjust "doubled operator" expression extension (#93353)
Most Fortran compilers accept "doubled operators" as a language extension. This is the use of a unary '+' or '-' operator that is not the first unparenthesized operator in an expression, as in 'x*-y'. This compiler has implemented this extension, but in a way that's different from other compilers' behavior. I interpreted the unary '+'/'-' as a unary operator in the sense of C/C++, giving it a higher priority than any binary (dyadic) operator. All other compilers with this extension, however, give a unary '+'/'-' a lower precedence than exponentiation ('**'), a binary operator that C/C++ lacks. And this interpretation makes more sense for Fortran, anyway, where the standard conforming '-x**y' must mean '-(x**y)' already. This patch makes 'x*-y**z' parse as 'x*-(y**z)', not 'x*(-y)**z)', and adds a test to ensure that it does.
Diffstat (limited to 'flang/lib/Parser/expr-parsers.cpp')
-rw-r--r--flang/lib/Parser/expr-parsers.cpp24
1 files changed, 15 insertions, 9 deletions
diff --git a/flang/lib/Parser/expr-parsers.cpp b/flang/lib/Parser/expr-parsers.cpp
index b27366d..a47aae1 100644
--- a/flang/lib/Parser/expr-parsers.cpp
+++ b/flang/lib/Parser/expr-parsers.cpp
@@ -87,14 +87,8 @@ constexpr auto primary{instrumented("primary"_en_US,
// R1002 level-1-expr -> [defined-unary-op] primary
// TODO: Reasonable extension: permit multiple defined-unary-ops
constexpr auto level1Expr{sourced(
- first(primary, // must come before define op to resolve .TRUE._8 ambiguity
- construct<Expr>(construct<Expr::DefinedUnary>(definedOpName, primary)),
- extension<LanguageFeature::SignedPrimary>(
- "nonstandard usage: signed primary"_port_en_US,
- construct<Expr>(construct<Expr::UnaryPlus>("+" >> primary))),
- extension<LanguageFeature::SignedPrimary>(
- "nonstandard usage: signed primary"_port_en_US,
- construct<Expr>(construct<Expr::Negate>("-" >> primary)))))};
+ primary || // must come before define op to resolve .TRUE._8 ambiguity
+ construct<Expr>(construct<Expr::DefinedUnary>(definedOpName, primary)))};
// R1004 mult-operand -> level-1-expr [power-op mult-operand]
// R1007 power-op -> **
@@ -105,7 +99,19 @@ struct MultOperand {
static inline std::optional<Expr> Parse(ParseState &);
};
-static constexpr auto multOperand{sourced(MultOperand{})};
+// Extension: allow + or - before a mult-operand
+// Such a unary operand has lower precedence than exponentiation,
+// so -x**2 is -(x**2), not (-x)**2; this matches all other
+// compilers with this extension.
+static constexpr auto standardMultOperand{sourced(MultOperand{})};
+static constexpr auto multOperand{standardMultOperand ||
+ extension<LanguageFeature::SignedMultOperand>(
+ "nonstandard usage: signed mult-operand"_port_en_US,
+ construct<Expr>(
+ construct<Expr::UnaryPlus>("+" >> standardMultOperand))) ||
+ extension<LanguageFeature::SignedMultOperand>(
+ "nonstandard usage: signed mult-operand"_port_en_US,
+ construct<Expr>(construct<Expr::Negate>("-" >> standardMultOperand)))};
inline std::optional<Expr> MultOperand::Parse(ParseState &state) {
std::optional<Expr> result{level1Expr.Parse(state)};