diff --git a/flang/lib/Evaluate/fold-implementation.h b/flang/lib/Evaluate/fold-implementation.h --- a/flang/lib/Evaluate/fold-implementation.h +++ b/flang/lib/Evaluate/fold-implementation.h @@ -1105,12 +1105,13 @@ // This variable is a workaround for msvc which emits an error when // using the FROMCAT template parameter below. TypeCategory constexpr FromCat{FROMCAT}; + static_assert(FromCat == Operand::category); auto &convert{msvcWorkaround.convert}; char buffer[64]; if (auto value{GetScalarConstantValue(kindExpr)}) { FoldingContext &ctx{msvcWorkaround.context}; if constexpr (TO::category == TypeCategory::Integer) { - if constexpr (Operand::category == TypeCategory::Integer) { + if constexpr (FromCat == TypeCategory::Integer) { auto converted{Scalar::ConvertSigned(*value)}; if (converted.overflow) { ctx.messages().Say( @@ -1118,7 +1119,7 @@ Operand::kind, TO::kind); } return ScalarConstantToExpr(std::move(converted.value)); - } else if constexpr (Operand::category == TypeCategory::Real) { + } else if constexpr (FromCat == TypeCategory::Real) { auto converted{value->template ToInteger>()}; if (converted.flags.test(RealFlag::InvalidArgument)) { ctx.messages().Say( @@ -1132,7 +1133,7 @@ return ScalarConstantToExpr(std::move(converted.value)); } } else if constexpr (TO::category == TypeCategory::Real) { - if constexpr (Operand::category == TypeCategory::Integer) { + if constexpr (FromCat == TypeCategory::Integer) { auto converted{Scalar::FromInteger(*value)}; if (!converted.flags.empty()) { std::snprintf(buffer, sizeof buffer, @@ -1141,7 +1142,7 @@ RealFlagWarnings(ctx, converted.flags, buffer); } return ScalarConstantToExpr(std::move(converted.value)); - } else if constexpr (Operand::category == TypeCategory::Real) { + } else if constexpr (FromCat == TypeCategory::Real) { auto converted{Scalar::Convert(*value)}; if (!converted.flags.empty()) { std::snprintf(buffer, sizeof buffer, @@ -1154,7 +1155,7 @@ return ScalarConstantToExpr(std::move(converted.value)); } } else if constexpr (TO::category == TypeCategory::Complex) { - if constexpr (Operand::category == TypeCategory::Complex) { + if constexpr (FromCat == TypeCategory::Complex) { return FoldOperation(ctx, ComplexConstructor{ AsExpr(Convert{AsCategoryExpr( @@ -1163,17 +1164,31 @@ Constant{value->AIMAG()})})}); } } else if constexpr (TO::category == TypeCategory::Character && - Operand::category == TypeCategory::Character) { + FromCat == TypeCategory::Character) { if (auto converted{ConvertString>(std::move(*value))}) { return ScalarConstantToExpr(std::move(*converted)); } } else if constexpr (TO::category == TypeCategory::Logical && - Operand::category == TypeCategory::Logical) { + FromCat == TypeCategory::Logical) { return Expr{value->IsTrue()}; } - } else if constexpr (std::is_same_v && + } else if constexpr (TO::category == FromCat && FromCat != TypeCategory::Character) { - return std::move(kindExpr); // remove needless conversion + // Conversion of non-constant in same type category + if constexpr (std::is_same_v) { + return std::move(kindExpr); // remove needless conversion + } else if constexpr (std::is_same_v) { + if (auto *innerConv{ + std::get_if>( + &kindExpr.u)}) { + if (auto *x{std::get_if>(&innerConv->left().u)}) { + if (std::holds_alternative(x->u)) { + // int(int(size(...),kind=k),kind=8) -> size(...) + return std::move(*x); + } + } + } + } } return Expr{std::move(convert)}; }, @@ -1201,7 +1216,9 @@ return *array; } auto &operand{x.left()}; - if (auto value{GetScalarConstantValue(operand)}) { + if (auto *nn{std::get_if>(&x.left().u)}) { + return std::move(nn->left()); // -(-x) -> x + } else if (auto value{GetScalarConstantValue(operand)}) { if constexpr (T::category == TypeCategory::Integer) { auto negated{value->Negate()}; if (negated.overflow) { @@ -1308,6 +1325,20 @@ } return Expr{Constant{product.value}}; } + } else if constexpr (T::category == TypeCategory::Integer) { + if (auto c{GetScalarConstantValue(x.right())}) { + x.right() = std::move(x.left()); + x.left() = Expr{std::move(*c)}; + } + if (auto c{GetScalarConstantValue(x.left())}) { + if (c->IsZero()) { + return std::move(x.left()); + } else if (c->CompareSigned(Scalar{1}) == Ordering::Equal) { + return std::move(x.right()); + } else if (c->CompareSigned(Scalar{-1}) == Ordering::Equal) { + return Expr{Negate{std::move(x.right())}}; + } + } } return Expr{std::move(x)}; } diff --git a/flang/test/Semantics/modfile17.f90 b/flang/test/Semantics/modfile17.f90 --- a/flang/test/Semantics/modfile17.f90 +++ b/flang/test/Semantics/modfile17.f90 @@ -98,7 +98,7 @@ !end type !type::defaulted(n1,n2,n4,n8) !integer(1),kind::n1=1_1 -!integer(2),kind::n2=int(int(int(n1,kind=1),kind=4)*2_4,kind=2) +!integer(2),kind::n2=int(2_4*int(int(n1,kind=1),kind=4),kind=2) !integer(4),kind::n4=2_4*int(int(n2,kind=2),kind=4) !integer(8),kind::n8=int(12_4-int(n4,kind=4),kind=8) !type(capture(k1=int(n1,kind=1),k2=int(n2,kind=2),k4=int(n4,kind=4),k8=n8))::cap diff --git a/flang/test/Semantics/modfile30.f90 b/flang/test/Semantics/modfile30.f90 --- a/flang/test/Semantics/modfile30.f90 +++ b/flang/test/Semantics/modfile30.f90 @@ -19,11 +19,11 @@ !contains ! function f1(x) result(y) ! integer(4)::x(:) -! integer(4)::y(1_8:int(int(1_8*size(x,dim=1),kind=4),kind=8)) +! integer(4)::y(1_8:size(x,dim=1)) ! end ! function f2(x) ! integer(4)::x(:) -! integer(4)::f2(1_8:int(int(1_8*size(x,dim=1),kind=4),kind=8)) +! integer(4)::f2(1_8:size(x,dim=1)) ! end !end