From afbaba0417d9cab55d0771873d9a942316f0b778 Mon Sep 17 00:00:00 2001 From: Carlos Seo Date: Wed, 8 Oct 2025 18:14:58 -0300 Subject: [PATCH] [Flang] RFC: Allow extended argument types in min0/max0 intrinsics Change the behavior of min0/max0 when they are called with non-default integer kinds by preserving the argument kinds instead of converting to default integer. Fixes #132646 --- flang/docs/Extensions.md | 3 +++ flang/lib/Evaluate/intrinsics.cpp | 6 ++++++ flang/test/Evaluate/folding04.f90 | 13 +++++++------ 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/flang/docs/Extensions.md b/flang/docs/Extensions.md index 420b7517922b7..3fef0ab742287 100644 --- a/flang/docs/Extensions.md +++ b/flang/docs/Extensions.md @@ -287,6 +287,9 @@ end * Specific intrinsics AMAX0, AMAX1, AMIN0, AMIN1, DMAX1, DMIN1, MAX0, MAX1, MIN0, and MIN1 accept more argument types than specified. They are replaced by the related generics followed by conversions to the specified result types. + For MAX0 and MIN0, the result type matches the argument types rather than + being converted to default INTEGER, preserving the kind of the arguments. + For example, `MAX0(1_8, 2_8)` returns `INTEGER(8)`, not `INTEGER(4)`. * When a scalar CHARACTER actual argument of the same kind is known to have a length shorter than the associated dummy argument, it is extended on the right with blanks, similar to assignment. diff --git a/flang/lib/Evaluate/intrinsics.cpp b/flang/lib/Evaluate/intrinsics.cpp index fe679da4ff98b..46375ed0e08f6 100644 --- a/flang/lib/Evaluate/intrinsics.cpp +++ b/flang/lib/Evaluate/intrinsics.cpp @@ -3654,6 +3654,12 @@ std::optional IntrinsicProcTable::Implementation::Probe( .GetTypeAndShape()) .type()}; DynamicType newType{GetReturnType(*specIter->second, defaults_)}; + // For MAX0/MIN0, preserve the generic type rather than forcing + // to default integer. This allows, for example, MAX0(1_8,2_8) to + // return INTEGER(8) instead of INTEGER(4). + if (genericType.category() == newType.category()) { + newType = genericType; + } if (genericType.category() == newType.category() || ((genericType.category() == TypeCategory::Integer || genericType.category() == TypeCategory::Real) && diff --git a/flang/test/Evaluate/folding04.f90 b/flang/test/Evaluate/folding04.f90 index 027db20f608b2..390197eb9cfdd 100644 --- a/flang/test/Evaluate/folding04.f90 +++ b/flang/test/Evaluate/folding04.f90 @@ -79,15 +79,16 @@ module parentheses module specific_extremums ! f18 accepts all type kinds for the arguments of specific extremum intrinsics ! instead of of only default kind (or double precision for DMAX1 and DMIN1). - ! This extensions is implemented by using the related generic intrinsic and - ! converting the result. + ! This extension is implemented by using the related generic intrinsic. + ! For MAX0/MIN0, the result type matches the argument types (preserving kind). + ! For AMAX0/AMIN0/MAX1/MIN1, the result is converted to the specified type. ! The tests below are cases where an implementation that converts the arguments to the ! standard required types instead would give different results than the implementation - ! specified for f18 (converting the result). + ! specified for f18. integer(8), parameter :: max_i32_8 = 2_8**31-1 - integer, parameter :: expected_min0 = int(min(max_i32_8, 2_8*max_i32_8), 4) - !WARN: portability: Argument types do not match specific intrinsic 'min0' requirements; using 'min' generic instead and converting the result to INTEGER(4) if needed [-Wuse-generic-intrinsic-when-specific-doesnt-match] - integer, parameter :: result_min0 = min0(max_i32_8, 2_8*max_i32_8) + integer(8), parameter :: expected_min0 = min(max_i32_8, 2_8*max_i32_8) + !WARN: portability: Argument types do not match specific intrinsic 'min0' requirements; using 'min' generic instead and converting the result to INTEGER(8) if needed [-Wuse-generic-intrinsic-when-specific-doesnt-match] + integer(8), parameter :: result_min0 = min0(max_i32_8, 2_8*max_i32_8) ! result_min0 would be -2 if arguments were converted to default integer. logical, parameter :: test_min0 = expected_min0 .EQ. result_min0