Skip to content

Commit 97e3f60

Browse files
authored
[flang] Don't allow non-standard data conversions of potentially abse… (#87391)
…nt arguments Arguments to the intrinsic functions MAX and MIN after the first two are optional. When these actual arguments might not be present at run time, emit a compilation time error if they require data conversion (a non-standard but nearly universal language extension); such a conversion would crash if the argument was absent. Other compilers either disallow data conversions entirely on MAX/MIN or crash at run time if a converted argument is absent. Fixes #87046.
1 parent aace1e1 commit 97e3f60

File tree

3 files changed

+58
-4
lines changed

3 files changed

+58
-4
lines changed

flang/docs/Extensions.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,10 @@ end
346346
* A `NAMELIST` input group may begin with either `&` or `$`.
347347
* A comma in a fixed-width numeric input field terminates the
348348
field rather than signaling an invalid character error.
349+
* Arguments to the intrinsic functions `MAX` and `MIN` are converted
350+
when necessary to the type of the result.
351+
An `OPTIONAL`, `POINTER`, or `ALLOCATABLE` argument after
352+
the first two cannot be converted, as it may not be present.
349353

350354
### Extensions supported when enabled by options
351355

flang/lib/Semantics/check-call.cpp

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1466,6 +1466,29 @@ static void CheckImage_Index(evaluate::ActualArguments &arguments,
14661466
}
14671467
}
14681468

1469+
// Ensure that any optional argument that might be absent at run time
1470+
// does not require data conversion.
1471+
static void CheckMaxMin(const characteristics::Procedure &proc,
1472+
evaluate::ActualArguments &arguments,
1473+
parser::ContextualMessages &messages) {
1474+
if (proc.functionResult) {
1475+
if (const auto *typeAndShape{proc.functionResult->GetTypeAndShape()}) {
1476+
for (std::size_t j{2}; j < arguments.size(); ++j) {
1477+
if (arguments[j]) {
1478+
if (const auto *expr{arguments[j]->UnwrapExpr()};
1479+
expr && evaluate::MayBePassedAsAbsentOptional(*expr)) {
1480+
if (auto thisType{expr->GetType()};
1481+
thisType && *thisType != typeAndShape->type()) {
1482+
messages.Say(arguments[j]->sourceLocation(),
1483+
"An actual argument to MAX/MIN requiring data conversion may not be OPTIONAL, POINTER, or ALLOCATABLE"_err_en_US);
1484+
}
1485+
}
1486+
}
1487+
}
1488+
}
1489+
}
1490+
}
1491+
14691492
// MOVE_ALLOC (F'2023 16.9.147)
14701493
static void CheckMove_Alloc(evaluate::ActualArguments &arguments,
14711494
parser::ContextualMessages &messages) {
@@ -1733,13 +1756,15 @@ static void CheckTransfer(evaluate::ActualArguments &arguments,
17331756
}
17341757
}
17351758

1736-
static void CheckSpecificIntrinsic(evaluate::ActualArguments &arguments,
1737-
SemanticsContext &context, const Scope *scope,
1738-
const evaluate::SpecificIntrinsic &intrinsic) {
1759+
static void CheckSpecificIntrinsic(const characteristics::Procedure &proc,
1760+
evaluate::ActualArguments &arguments, SemanticsContext &context,
1761+
const Scope *scope, const evaluate::SpecificIntrinsic &intrinsic) {
17391762
if (intrinsic.name == "associated") {
17401763
CheckAssociated(arguments, context, scope);
17411764
} else if (intrinsic.name == "image_index") {
17421765
CheckImage_Index(arguments, context.foldingContext().messages());
1766+
} else if (intrinsic.name == "max" || intrinsic.name == "min") {
1767+
CheckMaxMin(proc, arguments, context.foldingContext().messages());
17431768
} else if (intrinsic.name == "move_alloc") {
17441769
CheckMove_Alloc(arguments, context.foldingContext().messages());
17451770
} else if (intrinsic.name == "present") {
@@ -1790,7 +1815,7 @@ static parser::Messages CheckExplicitInterface(
17901815
CheckElementalConformance(messages, proc, actuals, foldingContext);
17911816
}
17921817
if (intrinsic) {
1793-
CheckSpecificIntrinsic(actuals, context, scope, *intrinsic);
1818+
CheckSpecificIntrinsic(proc, actuals, context, scope, *intrinsic);
17941819
}
17951820
return buffer;
17961821
}

flang/test/Semantics/intrinsics04.f90

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
! RUN: %python %S/test_errors.py %s %flang_fc1
2+
! A potentially absent actual argument cannot require data type conversion.
3+
subroutine s(o,a,p)
4+
integer(2), intent(in), optional :: o
5+
integer(2), intent(in), allocatable :: a
6+
integer(2), intent(in), pointer :: p
7+
!ERROR: An actual argument to MAX/MIN requiring data conversion may not be OPTIONAL, POINTER, or ALLOCATABLE
8+
print *, max(1, 2, o)
9+
!ERROR: An actual argument to MAX/MIN requiring data conversion may not be OPTIONAL, POINTER, or ALLOCATABLE
10+
print *, max(1, 2, a)
11+
!ERROR: An actual argument to MAX/MIN requiring data conversion may not be OPTIONAL, POINTER, or ALLOCATABLE
12+
print *, max(1, 2, p)
13+
!ERROR: An actual argument to MAX/MIN requiring data conversion may not be OPTIONAL, POINTER, or ALLOCATABLE
14+
print *, min(1, 2, o)
15+
!ERROR: An actual argument to MAX/MIN requiring data conversion may not be OPTIONAL, POINTER, or ALLOCATABLE
16+
print *, min(1, 2, a)
17+
!ERROR: An actual argument to MAX/MIN requiring data conversion may not be OPTIONAL, POINTER, or ALLOCATABLE
18+
print *, min(1, 2, p)
19+
print *, max(1_2, 2_2, o) ! ok
20+
print *, max(1_2, 2_2, a) ! ok
21+
print *, max(1_2, 2_2, p) ! ok
22+
print *, min(1_2, 2_2, o) ! ok
23+
print *, min(1_2, 2_2, a) ! ok
24+
print *, min(1_2, 2_2, p) ! ok
25+
end

0 commit comments

Comments
 (0)