diff --git a/flang/include/flang/Evaluate/expression.h b/flang/include/flang/Evaluate/expression.h index 3ba46edba717b..2a40193e32306 100644 --- a/flang/include/flang/Evaluate/expression.h +++ b/flang/include/flang/Evaluate/expression.h @@ -342,6 +342,7 @@ template struct Extremum : public Operation, A, A, A> { : Base{x, y}, ordering{ord} {} Extremum(Ordering ord, Expr &&x, Expr &&y) : Base{std::move(x), std::move(y)}, ordering{ord} {} + bool operator==(const Extremum &) const; Ordering ordering{Ordering::Greater}; }; @@ -381,6 +382,7 @@ struct LogicalOperation : Base{x, y}, logicalOperator{opr} {} LogicalOperation(LogicalOperator opr, Expr &&x, Expr &&y) : Base{std::move(x), std::move(y)}, logicalOperator{opr} {} + bool operator==(const LogicalOperation &) const; LogicalOperator logicalOperator; }; @@ -634,6 +636,7 @@ class Relational : public Operation, LogicalResult, T, T> { : Base{a, b}, opr{r} {} Relational(RelationalOperator r, Expr &&a, Expr &&b) : Base{std::move(a), std::move(b)}, opr{r} {} + bool operator==(const Relational &) const; RelationalOperator opr; }; diff --git a/flang/include/flang/Evaluate/tools.h b/flang/include/flang/Evaluate/tools.h index 3675d9f924876..a0487e399d936 100644 --- a/flang/include/flang/Evaluate/tools.h +++ b/flang/include/flang/Evaluate/tools.h @@ -218,6 +218,22 @@ template A *UnwrapExpr(std::optional &x) { } } +template const A *UnwrapExpr(const B *x) { + if (x) { + return UnwrapExpr(*x); + } else { + return nullptr; + } +} + +template A *UnwrapExpr(B *x) { + if (x) { + return UnwrapExpr(*x); + } else { + return nullptr; + } +} + // A variant of UnwrapExpr above that also skips through (parentheses) // and conversions of kinds within a category. Useful for extracting LEN // type parameter inquiries, at least. diff --git a/flang/lib/Evaluate/expression.cpp b/flang/lib/Evaluate/expression.cpp index 5b0bc14dc3e1b..1a65d4c7362fe 100644 --- a/flang/lib/Evaluate/expression.cpp +++ b/flang/lib/Evaluate/expression.cpp @@ -125,6 +125,24 @@ template LLVM_DUMP_METHOD void ExpressionBase::dump() const { // Equality testing +template bool Extremum::operator==(const Extremum &that) const { + return ordering == that.ordering && Base::operator==(that); +} + +template +bool LogicalOperation::operator==(const LogicalOperation &that) const { + return logicalOperator == that.logicalOperator && Base::operator==(that); +} + +template +bool Relational::operator==(const Relational &that) const { + return opr == that.opr && Base::operator==(that); +} + +bool Relational::operator==(const Relational &that) const { + return u == that.u; +} + bool ImpliedDoIndex::operator==(const ImpliedDoIndex &that) const { return name == that.name; } @@ -181,10 +199,6 @@ bool StructureConstructor::operator==(const StructureConstructor &that) const { return result_ == that.result_ && values_ == that.values_; } -bool Relational::operator==(const Relational &that) const { - return u == that.u; -} - template bool Expr>::operator==( const Expr> &that) const { diff --git a/flang/lib/Evaluate/fold-implementation.h b/flang/lib/Evaluate/fold-implementation.h index 9ce0edbdcb779..1b14a305b87f4 100644 --- a/flang/lib/Evaluate/fold-implementation.h +++ b/flang/lib/Evaluate/fold-implementation.h @@ -1088,24 +1088,42 @@ Expr FoldMINorMAX( static_assert(T::category == TypeCategory::Integer || T::category == TypeCategory::Real || T::category == TypeCategory::Character); - std::vector *> constantArgs; - // Call Folding on all arguments, even if some are not constant, - // to make operand promotion explicit. - for (auto &arg : funcRef.arguments()) { - if (auto *cst{Folder{context}.Folding(arg)}) { - constantArgs.push_back(cst); + auto &args{funcRef.arguments()}; + bool ok{true}; + std::optional> result; + Folder folder{context}; + for (std::optional &arg : args) { + // Call Folding on all arguments to make operand promotion explicit. + if (!folder.Folding(arg)) { + // TODO: Lowering can't handle having every FunctionRef for max and min + // being converted into Extremum. That needs fixing. Until that + // is corrected, however, it is important that max and min references + // in module files be converted into Extremum even when not constant; + // the Extremum operations created to normalize the + // values of array bounds are formatted as max operations in the + // declarations in modules, and need to be read back in as such in + // order for expression comparison to not produce false inequalities + // when checking function results for procedure interface compatibility. + if (!context.moduleFileName()) { + ok = false; + } + } + Expr *argExpr{arg ? arg->UnwrapExpr() : nullptr}; + if (argExpr) { + *argExpr = Fold(context, std::move(*argExpr)); + } + if (Expr * tExpr{UnwrapExpr>(argExpr)}) { + if (result) { + result = FoldOperation( + context, Extremum{order, std::move(*result), Expr{*tExpr}}); + } else { + result = Expr{*tExpr}; + } + } else { + ok = false; } } - if (constantArgs.size() != funcRef.arguments().size()) { - return Expr(std::move(funcRef)); - } - CHECK(!constantArgs.empty()); - Expr result{std::move(*constantArgs[0])}; - for (std::size_t i{1}; i < constantArgs.size(); ++i) { - Extremum extremum{order, result, Expr{std::move(*constantArgs[i])}}; - result = FoldOperation(context, std::move(extremum)); - } - return result; + return ok && result ? std::move(*result) : Expr{std::move(funcRef)}; } // For AMAX0, AMIN0, AMAX1, AMIN1, DMAX1, DMIN1, MAX0, MIN0, MAX1, and MIN1 diff --git a/flang/test/Semantics/Inputs/modfile67.mod b/flang/test/Semantics/Inputs/modfile67.mod new file mode 100644 index 0000000000000..1aa0158e35089 --- /dev/null +++ b/flang/test/Semantics/Inputs/modfile67.mod @@ -0,0 +1,16 @@ +!mod$ v1 sum:37cfecee3234c8ab +module modfile67 +type::t +procedure(foo),nopass,pointer::p +end type +contains +pure function foo(n,a) result(r) +integer(4),intent(in)::n +real(4),intent(in)::a(1_8:int(n,kind=8)) +logical(4)::r(1_8:int(int(max(0_8,int(n,kind=8)),kind=4),kind=8)) +end +function fooptr(f) +procedure(foo)::f +type(t)::fooptr +end +end diff --git a/flang/test/Semantics/modfile67.f90 b/flang/test/Semantics/modfile67.f90 new file mode 100644 index 0000000000000..18cf95bd42fbf --- /dev/null +++ b/flang/test/Semantics/modfile67.f90 @@ -0,0 +1,35 @@ +!RUN: %flang_fc1 -fsyntax-only -J%S/Inputs %s + +#if 0 +!modfile67.mod was produced from this source, and must be read into this +!compilation from its module file in order to truly test this fix. +module modfile67 + type t + procedure(foo), nopass, pointer :: p + end type + contains + pure function foo(n,a) result(r) + integer, intent(in) :: n + real, intent(in), dimension(n) :: a + logical, dimension(size(a)) :: r + r = .false. + end + type(t) function fooptr(f) + procedure(foo) f + fooptr%p => f + end +end +#endif + +program test + use modfile67 + type(t) x + x = fooptr(bar) ! ensure no bogus error about procedure incompatibility + contains + pure function bar(n,a) result(r) + integer, intent(in) :: n + real, intent(in), dimension(n) :: a + logical, dimension(size(a)) :: r + r = .false. + end +end