Skip to content

Commit bc699ed

Browse files
committed
[flang] prevent rewrite of CMPLX with dynamically optional Y argument
CMPLX was always rewritten as a complex constructor, but the second operand of a complex constructor cannot be dynamically absent (i.e., a disassociated pointer, an unallocated allocatable or an absent OPTIONAL dummy argument), while the second argument of CMPLX can be dynamically absent. To avoid having to generate branches in complex constructor lowering when Y is a pointer, keep the distinction between CMPLX and a complex constructor when Y is a pointer, an allocatable, or an OPTIONAL entity. Differential Revision: https://reviews.llvm.org/D118784
1 parent 73f21db commit bc699ed

File tree

3 files changed

+35
-0
lines changed

3 files changed

+35
-0
lines changed

flang/include/flang/Evaluate/tools.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -889,6 +889,10 @@ template <typename A> bool IsAllocatableOrPointer(const A &x) {
889889
semantics::Attrs{semantics::Attr::POINTER, semantics::Attr::ALLOCATABLE});
890890
}
891891

892+
// Like IsAllocatableOrPointer, but accepts pointer function results as being
893+
// pointers.
894+
bool IsAllocatableOrPointerObject(const Expr<SomeType> &, FoldingContext &);
895+
892896
// Procedure and pointer detection predicates
893897
bool IsProcedure(const Expr<SomeType> &);
894898
bool IsFunction(const Expr<SomeType> &);
@@ -897,6 +901,10 @@ bool IsBareNullPointer(const Expr<SomeType> *); // NULL() w/o MOLD=
897901
bool IsNullPointer(const Expr<SomeType> &);
898902
bool IsObjectPointer(const Expr<SomeType> &, FoldingContext &);
899903

904+
// Can Expr be passed as absent to an optional dummy argument.
905+
// See 15.5.2.12 point 1 for more details.
906+
bool MayBePassedAsAbsentOptional(const Expr<SomeType> &, FoldingContext &);
907+
900908
// Extracts the chain of symbols from a designator, which has perhaps been
901909
// wrapped in an Expr<>, removing all of the (co)subscripts. The
902910
// base object will be the first symbol in the result vector.

flang/lib/Evaluate/fold-complex.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,15 @@ Expr<Type<TypeCategory::Complex, KIND>> FoldIntrinsicFunction(
4141
// CMPLX(X [, KIND]) with complex X
4242
return Fold(context, ConvertToType<T>(std::move(*x)));
4343
} else {
44+
if (args.size() >= 2 && args[1].has_value()) {
45+
// Do not fold CMPLX with an Y argument that may be absent at runtime
46+
// into a complex constructor so that lowering can deal with the
47+
// optional aspect (there is no optional aspect with the complex
48+
// constructor).
49+
if (MayBePassedAsAbsentOptional(*args[1]->UnwrapExpr(), context)) {
50+
return Expr<T>{std::move(funcRef)};
51+
}
52+
}
4453
// CMPLX(X [, Y [, KIND]]) with non-complex X
4554
Expr<SomeType> re{std::move(*args[0].value().UnwrapExpr())};
4655
Expr<SomeType> im{args.size() >= 2 && args[1].has_value()

flang/lib/Evaluate/tools.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1078,6 +1078,24 @@ std::optional<Expr<SomeType>> DataConstantConversionExtension(
10781078
return std::nullopt;
10791079
}
10801080

1081+
bool IsAllocatableOrPointerObject(
1082+
const Expr<SomeType> &expr, FoldingContext &context) {
1083+
const semantics::Symbol *sym{UnwrapWholeSymbolOrComponentDataRef(expr)};
1084+
return (sym && semantics::IsAllocatableOrPointer(*sym)) ||
1085+
evaluate::IsObjectPointer(expr, context);
1086+
}
1087+
1088+
bool MayBePassedAsAbsentOptional(
1089+
const Expr<SomeType> &expr, FoldingContext &context) {
1090+
const semantics::Symbol *sym{UnwrapWholeSymbolOrComponentDataRef(expr)};
1091+
// 15.5.2.12 1. is pretty clear that an unallocated allocatable/pointer actual
1092+
// may be passed to a non-allocatable/non-pointer optional dummy. Note that
1093+
// other compilers (like nag, nvfortran, ifort, gfortran and xlf) seems to
1094+
// ignore this point in intrinsic contexts (e.g CMPLX argument).
1095+
return (sym && semantics::IsOptional(*sym)) ||
1096+
IsAllocatableOrPointerObject(expr, context);
1097+
}
1098+
10811099
} // namespace Fortran::evaluate
10821100

10831101
namespace Fortran::semantics {

0 commit comments

Comments
 (0)