mirror of
https://github.com/intel/llvm.git
synced 2026-01-21 04:14:03 +08:00
[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.
This commit is contained in:
@@ -356,6 +356,8 @@ end
|
||||
* A derived type that meets (most of) the requirements of an interoperable
|
||||
derived type can be used as such where an interoperable type is
|
||||
required, with warnings, even if it lacks the BIND(C) attribute.
|
||||
* A "mult-operand" in an expression can be preceded by a unary
|
||||
`+` or `-` operator.
|
||||
|
||||
### Extensions supported when enabled by options
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ ENUM_CLASS(LanguageFeature, BackslashEscapes, OldDebugLines,
|
||||
DoubleComplex, Byte, StarKind, ExponentMatchingKindParam, QuadPrecision,
|
||||
SlashInitialization, TripletInArrayConstructor, MissingColons,
|
||||
SignedComplexLiteral, OldStyleParameter, ComplexConstructor, PercentLOC,
|
||||
SignedPrimary, FileName, Carriagecontrol, Convert, Dispose,
|
||||
SignedMultOperand, FileName, Carriagecontrol, Convert, Dispose,
|
||||
IOListLeadingComma, AbbreviatedEditDescriptor, ProgramParentheses,
|
||||
PercentRefAndVal, OmitFunctionDummies, CrayPointer, Hollerith, ArithmeticIF,
|
||||
Assign, AssignedGOTO, Pause, OpenACC, OpenMP, CUDA, CruftAfterAmpersand,
|
||||
|
||||
@@ -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)};
|
||||
|
||||
12
flang/test/Evaluate/signed-mult-opd.f90
Normal file
12
flang/test/Evaluate/signed-mult-opd.f90
Normal file
@@ -0,0 +1,12 @@
|
||||
! RUN: %python %S/test_folding.py %s %flang_fc1
|
||||
module m
|
||||
integer, parameter :: j = 2
|
||||
! standard cases
|
||||
logical, parameter :: test_1 = -j**2 == -4
|
||||
logical, parameter :: test_2 = 4-j**2 == 0
|
||||
! extension cases
|
||||
logical, parameter :: test_3 = 4+-j**2 == 0 ! not 8
|
||||
logical, parameter :: test_4 = 2*-j**2 == -8 ! not 8
|
||||
logical, parameter :: test_5 = -j**2+-j**2 == -8 ! not 8
|
||||
logical, parameter :: test_6 = j**2*-j**2 == -16 ! not 16
|
||||
end
|
||||
Reference in New Issue
Block a user