diff --git a/flang/include/flang/Evaluate/expression.h b/flang/include/flang/Evaluate/expression.h --- a/flang/include/flang/Evaluate/expression.h +++ b/flang/include/flang/Evaluate/expression.h @@ -116,8 +116,10 @@ public: using Derived = DERIVED; using Result = RESULT; - static_assert(IsSpecificIntrinsicType); static constexpr std::size_t operands{sizeof...(OPERANDS)}; + // Allow specific intrinsic types and Parentheses + static_assert(IsSpecificIntrinsicType || + (operands == 1 && std::is_same_v)); template using Operand = std::tuple_element_t; // Unary operations wrap a single Expr with a CopyableIndirection. @@ -172,7 +174,9 @@ } } - static constexpr std::optional GetType() { + static constexpr std::conditional_t, void> + GetType() { return Result::GetType(); } int Rank() const { @@ -222,6 +226,17 @@ using Base::Base; }; +template <> +struct Parentheses + : public Operation, SomeDerived, SomeDerived> { +public: + using Result = SomeDerived; + using Operand = SomeDerived; + using Base = Operation; + using Base::Base; + DynamicType GetType() const; +}; + template struct Negate : public Operation, A, A> { using Result = A; using Operand = A; @@ -730,7 +745,7 @@ using Result = SomeDerived; EVALUATE_UNION_CLASS_BOILERPLATE(Expr) std::variant, ArrayConstructor, StructureConstructor, - Designator, FunctionRef> + Designator, FunctionRef, Parentheses> u; }; diff --git a/flang/lib/Evaluate/expression.cpp b/flang/lib/Evaluate/expression.cpp --- a/flang/lib/Evaluate/expression.cpp +++ b/flang/lib/Evaluate/expression.cpp @@ -107,6 +107,10 @@ derived().u); } +DynamicType Parentheses::GetType() const { + return left().GetType().value(); +} + // Equality testing bool ImpliedDoIndex::operator==(const ImpliedDoIndex &that) const { diff --git a/flang/lib/Evaluate/tools.cpp b/flang/lib/Evaluate/tools.cpp --- a/flang/lib/Evaluate/tools.cpp +++ b/flang/lib/Evaluate/tools.cpp @@ -35,9 +35,10 @@ return std::visit( [&](auto &&x) { using T = std::decay_t; - if constexpr (common::HasMember || - std::is_same_v>) { - return expr; // no parentheses around typeless or derived type + if constexpr (common::HasMember) { + return expr; // no parentheses around typeless + } else if constexpr (std::is_same_v>) { + return AsGenericExpr(Parentheses{std::move(x)}); } else { return std::visit( [](auto &&y) { diff --git a/flang/test/Evaluate/expr01.f90 b/flang/test/Evaluate/expr01.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Evaluate/expr01.f90 @@ -0,0 +1,34 @@ +! RUN: %flang_fc1 -fdebug-unparse %s 2>&1 | FileCheck %s +! Ensures that parentheses are preserved with derived types +module m + type :: t + integer :: n + end type + contains + subroutine sub(x) + type(t), intent(in) :: x + end subroutine + function f(m) + type(t), pointer :: f + integer, intent(in) :: m + type(t), save, target :: res + res%n = m + f => res + end function + subroutine test + type(t) :: x + x = t(1) + !CHECK: CALL sub(t(n=1_4)) + call sub(t(1)) + !CHECK: CALL sub((t(n=1_4))) + call sub((t(1))) + !CHECK: CALL sub(x) + call sub(x) + !CHECK: CALL sub((x)) + call sub((x)) + !CHECK: CALL sub(f(2_4)) + call sub(f(2)) + !CHECK: CALL sub((f(2_4))) + call sub((f(2))) + end subroutine +end module