Skip to content

Commit

Permalink
[flang] Error recovery in bad specific MIN/MAX calls
Browse files Browse the repository at this point in the history
When a specific MIN/MAX intrinsic function (e.g. MAX1) reference
has an actual argument error, ensure that a later attempt to fold
the call into a constant doesn't crash due to a missing argument.
Fixes #63140

Differential Revision: https://reviews.llvm.org/D153470
  • Loading branch information
klausler committed Jun 22, 2023
1 parent 4813c36 commit 553cd19
Show file tree
Hide file tree
Showing 2 changed files with 18 additions and 13 deletions.
29 changes: 16 additions & 13 deletions flang/lib/Evaluate/fold-implementation.h
Original file line number Diff line number Diff line change
Expand Up @@ -1063,26 +1063,29 @@ Expr<T> RewriteSpecificMINorMAX(
auto &intrinsic{DEREF(std::get_if<SpecificIntrinsic>(&funcRef.proc().u))};
// Rewrite MAX1(args) to INT(MAX(args)) and fold. Same logic for MIN1.
// Find result type for max/min based on the arguments.
DynamicType resultType{args[0].value().GetType().value()};
auto *resultTypeArg{&args[0]};
for (auto j{args.size() - 1}; j > 0; --j) {
DynamicType type{args[j].value().GetType().value()};
if (type.category() == resultType.category()) {
if (type.kind() > resultType.kind()) {
resultTypeArg = &args[j];
resultType = type;
}
} else if (resultType.category() == TypeCategory::Integer) {
std::optional<DynamicType> resultType;
ActualArgument *resultTypeArg{nullptr};
for (auto j{args.size()}; j-- > 0;) {
if (args[j]) {
DynamicType type{args[j]->GetType().value()};
// Handle mixed real/integer arguments: all the previous arguments were
// integers and this one is real. The type of the MAX/MIN result will
// be the one of the real argument.
resultTypeArg = &args[j];
resultType = type;
if (!resultType ||
(type.category() == resultType->category() &&
type.kind() > resultType->kind()) ||
resultType->category() == TypeCategory::Integer) {
resultType = type;
resultTypeArg = &*args[j];
}
}
}
if (!resultType) { // error recovery
return Expr<T>{std::move(funcRef)};
}
intrinsic.name =
intrinsic.name.find("max") != std::string::npos ? "max"s : "min"s;
intrinsic.characteristics.value().functionResult.value().SetType(resultType);
intrinsic.characteristics.value().functionResult.value().SetType(*resultType);
auto insertConversion{[&](const auto &x) -> Expr<T> {
using TR = ResultType<decltype(x)>;
FunctionRef<TR> maxRef{std::move(funcRef.proc()), std::move(args)};
Expand Down
2 changes: 2 additions & 0 deletions flang/test/Semantics/call23.f90
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
print *, max(a1=x,a1=1)
!ERROR: Keyword argument 'a1=' has already been specified positionally (#1) in this procedure reference
print *, max(x,a1=1)
!ERROR: Keyword argument 'a1=' has already been specified positionally (#1) in this procedure reference
print *, min1(1.,a1=2.,a2=3.)
print *, max(a1=x,a2=0,a4=0) ! ok
print *, max(x,0,a99=0) ! ok
!ERROR: Argument keyword 'a06=' is not known in call to 'max'
Expand Down

0 comments on commit 553cd19

Please sign in to comment.