forked from OSchip/llvm-project
[flang] Represent (parentheses around derived types)
The strongly typed expression representation classes supported a representation of parentheses only around intrinsic types with specific kinds. Parentheses around derived type variables must also be preserved so that expressions may be distinguished from variables; this distinction matters for actual arguments & construct associations. Differential Revision: https://reviews.llvm.org/D110355
This commit is contained in:
parent
fbaf367217
commit
f6ecea1a35
|
@ -116,8 +116,10 @@ class Operation {
|
||||||
public:
|
public:
|
||||||
using Derived = DERIVED;
|
using Derived = DERIVED;
|
||||||
using Result = RESULT;
|
using Result = RESULT;
|
||||||
static_assert(IsSpecificIntrinsicType<Result>);
|
|
||||||
static constexpr std::size_t operands{sizeof...(OPERANDS)};
|
static constexpr std::size_t operands{sizeof...(OPERANDS)};
|
||||||
|
// Allow specific intrinsic types and Parentheses<SomeDerived>
|
||||||
|
static_assert(IsSpecificIntrinsicType<Result> ||
|
||||||
|
(operands == 1 && std::is_same_v<Result, SomeDerived>));
|
||||||
template <int J> using Operand = std::tuple_element_t<J, OperandTypes>;
|
template <int J> using Operand = std::tuple_element_t<J, OperandTypes>;
|
||||||
|
|
||||||
// Unary operations wrap a single Expr with a CopyableIndirection.
|
// Unary operations wrap a single Expr with a CopyableIndirection.
|
||||||
|
@ -172,7 +174,9 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr std::optional<DynamicType> GetType() {
|
static constexpr std::conditional_t<Result::category != TypeCategory::Derived,
|
||||||
|
std::optional<DynamicType>, void>
|
||||||
|
GetType() {
|
||||||
return Result::GetType();
|
return Result::GetType();
|
||||||
}
|
}
|
||||||
int Rank() const {
|
int Rank() const {
|
||||||
|
@ -222,6 +226,17 @@ struct Parentheses : public Operation<Parentheses<A>, A, A> {
|
||||||
using Base::Base;
|
using Base::Base;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct Parentheses<SomeDerived>
|
||||||
|
: public Operation<Parentheses<SomeDerived>, SomeDerived, SomeDerived> {
|
||||||
|
public:
|
||||||
|
using Result = SomeDerived;
|
||||||
|
using Operand = SomeDerived;
|
||||||
|
using Base = Operation<Parentheses, SomeDerived, SomeDerived>;
|
||||||
|
using Base::Base;
|
||||||
|
DynamicType GetType() const;
|
||||||
|
};
|
||||||
|
|
||||||
template <typename A> struct Negate : public Operation<Negate<A>, A, A> {
|
template <typename A> struct Negate : public Operation<Negate<A>, A, A> {
|
||||||
using Result = A;
|
using Result = A;
|
||||||
using Operand = A;
|
using Operand = A;
|
||||||
|
@ -730,7 +745,7 @@ public:
|
||||||
using Result = SomeDerived;
|
using Result = SomeDerived;
|
||||||
EVALUATE_UNION_CLASS_BOILERPLATE(Expr)
|
EVALUATE_UNION_CLASS_BOILERPLATE(Expr)
|
||||||
std::variant<Constant<Result>, ArrayConstructor<Result>, StructureConstructor,
|
std::variant<Constant<Result>, ArrayConstructor<Result>, StructureConstructor,
|
||||||
Designator<Result>, FunctionRef<Result>>
|
Designator<Result>, FunctionRef<Result>, Parentheses<Result>>
|
||||||
u;
|
u;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -107,6 +107,10 @@ template <typename A> int ExpressionBase<A>::Rank() const {
|
||||||
derived().u);
|
derived().u);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DynamicType Parentheses<SomeDerived>::GetType() const {
|
||||||
|
return left().GetType().value();
|
||||||
|
}
|
||||||
|
|
||||||
// Equality testing
|
// Equality testing
|
||||||
|
|
||||||
bool ImpliedDoIndex::operator==(const ImpliedDoIndex &that) const {
|
bool ImpliedDoIndex::operator==(const ImpliedDoIndex &that) const {
|
||||||
|
|
|
@ -35,9 +35,10 @@ Expr<SomeType> Parenthesize(Expr<SomeType> &&expr) {
|
||||||
return std::visit(
|
return std::visit(
|
||||||
[&](auto &&x) {
|
[&](auto &&x) {
|
||||||
using T = std::decay_t<decltype(x)>;
|
using T = std::decay_t<decltype(x)>;
|
||||||
if constexpr (common::HasMember<T, TypelessExpression> ||
|
if constexpr (common::HasMember<T, TypelessExpression>) {
|
||||||
std::is_same_v<T, Expr<SomeDerived>>) {
|
return expr; // no parentheses around typeless
|
||||||
return expr; // no parentheses around typeless or derived type
|
} else if constexpr (std::is_same_v<T, Expr<SomeDerived>>) {
|
||||||
|
return AsGenericExpr(Parentheses<SomeDerived>{std::move(x)});
|
||||||
} else {
|
} else {
|
||||||
return std::visit(
|
return std::visit(
|
||||||
[](auto &&y) {
|
[](auto &&y) {
|
||||||
|
|
|
@ -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
|
Loading…
Reference in New Issue