diff --git a/flang/lib/Semantics/check-call.cpp b/flang/lib/Semantics/check-call.cpp --- a/flang/lib/Semantics/check-call.cpp +++ b/flang/lib/Semantics/check-call.cpp @@ -9,15 +9,20 @@ #include "check-call.h" #include "definable.h" #include "pointer-assignment.h" +#include "flang/Evaluate/call.h" #include "flang/Evaluate/characteristics.h" #include "flang/Evaluate/check-expression.h" +#include "flang/Evaluate/constant.h" +#include "flang/Evaluate/expression.h" #include "flang/Evaluate/fold-designator.h" #include "flang/Evaluate/shape.h" #include "flang/Evaluate/tools.h" +#include "flang/Evaluate/type.h" #include "flang/Parser/characters.h" #include "flang/Parser/message.h" #include "flang/Semantics/scope.h" #include "flang/Semantics/tools.h" +#include "flang/Semantics/type.h" #include #include @@ -26,6 +31,35 @@ namespace Fortran::semantics { +// Automatic conversion of different-kind LOGICAL scalar actual argument +// expressions that are constants or results of relational operators to LOGICAL +// scalar dummies when the dummy is of default logical kind or is implicit. This +// allows these expressions in dummy arguments to work when the default logical +// kind is not the one used in LogicalResult. This will always be safe even when +// downconverting so no warning is needed. +static void ConvertLogicalResult(evaluate::Expr &actual, + characteristics::TypeAndShape &actualType, + evaluate::FoldingContext &context) { + auto defaultLogicalKind{ + context.defaults().GetDefaultKind(TypeCategory::Logical)}; + auto argChars{characteristics::DummyArgument::FromActual( + "actual argument", actual, context)}; + if (actualType.type().category() == TypeCategory::Logical && + actualType.type().kind() != defaultLogicalKind && + (evaluate::UnwrapExpr>(actual) || + evaluate::UnwrapExpr>( + actual)) && + !evaluate::IsVariable(actual)) { + evaluate::DynamicType defaultLogicalType{ + TypeCategory::Logical, defaultLogicalKind}; + auto converted{ + evaluate::ConvertToType(defaultLogicalType, std::move(actual))}; + CHECK(converted); + actual = std::move(*converted); + actualType.set_type(defaultLogicalType); + } +} + static void CheckImplicitInterfaceArg(evaluate::ActualArgument &arg, parser::ContextualMessages &messages, evaluate::FoldingContext &context) { auto restorer{ @@ -49,7 +83,11 @@ } } } - if (const auto *expr{arg.UnwrapExpr()}) { + if (auto *expr{arg.UnwrapExpr()}) { + if (auto type{ + characteristics::TypeAndShape::Characterize(*expr, context)}) { + ConvertLogicalResult(*expr, *type, context); + } if (IsBOZLiteral(*expr)) { messages.Say("BOZ argument requires an explicit interface"_err_en_US); } else if (evaluate::IsNullPointer(*expr)) { @@ -294,6 +332,8 @@ if (allowActualArgumentConversions) { ConvertIntegerActual(actual, dummy.type, actualType, messages); } + // ConvertLogicalActual(actual, dummy.type, actualType); + ConvertLogicalResult(actual, actualType, foldingContext); bool typesCompatible{typesCompatibleWithIgnoreTKR || dummy.type.type().IsTkCompatibleWith(actualType.type())}; int dummyRank{dummy.type.Rank()}; diff --git a/flang/test/Evaluate/logical-args.f90 b/flang/test/Evaluate/logical-args.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Evaluate/logical-args.f90 @@ -0,0 +1,33 @@ +! Test that actual logical arguments convert to the right kind when it is non-default +! RUN: %flang_fc1 -fdebug-unparse %s 2>&1 | FileCheck %s +! RUN: %flang_fc1 -fdebug-unparse -fdefault-integer-8 %s 2>&1 | FileCheck %s --check-prefixes CHECK-8 + +program main + integer :: x(10), y + logical(kind=1) :: l(2) + ! CHECK: CALL foo(.true._4) + ! CHECK-8: CALL foo(logical(.true._4,kind=8)) + call foo(1 < 2) + ! CHECK: CALL fooa(x>y) + ! CHECK-8: CALL fooa(logical(x>y,kind=8)) + call fooa(x > y) + + ! CHECK: CALL bar(.true._4) + ! CHECK-8: CALL bar(logical(.true._4,kind=8)) + call bar(1 < 2) + + ! Make sure we don't try to convert when the argument comes from an intrinsic + ! call with a non-default kind logical result + ! CHECK: CALL baz(any(l)) + ! CHECK-8: CALL baz(any(l)) + call baz(any(l)) + + contains + subroutine foo(l) + logical :: l + end subroutine foo + + subroutine fooa(l) + logical :: l(10) + end subroutine fooa +end program main