diff --git a/flang/include/flang/Evaluate/tools.h b/flang/include/flang/Evaluate/tools.h --- a/flang/include/flang/Evaluate/tools.h +++ b/flang/include/flang/Evaluate/tools.h @@ -938,7 +938,7 @@ bool IsProcedure(const Expr &); bool IsFunction(const Expr &); bool IsProcedurePointerTarget(const Expr &); -bool IsBareNullPointer(const Expr *); // NULL() w/o MOLD= +bool IsBareNullPointer(const Expr *); // NULL() w/o MOLD= or type bool IsNullObjectPointer(const Expr &); bool IsNullProcedurePointer(const Expr &); bool IsNullPointer(const Expr &); diff --git a/flang/lib/Evaluate/fold.cpp b/flang/lib/Evaluate/fold.cpp --- a/flang/lib/Evaluate/fold.cpp +++ b/flang/lib/Evaluate/fold.cpp @@ -72,7 +72,11 @@ for (auto &&[symbol, value] : std::move(structure)) { auto expr{Fold(context, std::move(value.value()))}; if (IsPointer(symbol)) { - if (IsProcedure(symbol)) { + if (IsNullPointer(expr)) { + // Handle x%c when x designates a named constant of derived + // type and %c is NULL() in that constant. + expr = Expr{NullPointer{}}; + } else if (IsProcedure(symbol)) { isConstant &= IsInitialProcedureTarget(expr); } else { isConstant &= IsInitialDataTarget(expr); diff --git a/flang/lib/Evaluate/tools.cpp b/flang/lib/Evaluate/tools.cpp --- a/flang/lib/Evaluate/tools.cpp +++ b/flang/lib/Evaluate/tools.cpp @@ -784,11 +784,8 @@ } } -bool IsBareNullPointer(const Expr *expr) { - return expr && std::holds_alternative(expr->u); -} +// IsNullPointer() & variations -// IsNullObjectPointetr, IsNullProcedurePointer(), IsNullPointer() template struct IsNullPointerHelper { template bool operator()(const A &) const { return false; } bool operator()(const ProcedureRef &call) const { @@ -811,6 +808,27 @@ characteristics::Procedure::Attr::NullPointer); } } + template bool operator()(const Designator &x) const { + if (const auto *component{std::get_if(&x.u)}) { + if (const auto *baseSym{std::get_if(&component->base().u)}) { + const Symbol &base{**baseSym}; + if (const auto *object{ + base.detailsIf()}) { + // TODO: nested component and array references + if (IsNamedConstant(base) && object->init()) { + if (auto structCons{ + GetScalarConstantValue(*object->init())}) { + auto iter{structCons->values().find(component->GetLastSymbol())}; + if (iter != structCons->values().end()) { + return (*this)(iter->second.value()); + } + } + } + } + } + } + return false; + } bool operator()(const NullPointer &) const { return true; } template bool operator()(const Parentheses &x) const { return (*this)(x.left()); @@ -823,13 +841,19 @@ bool IsNullObjectPointer(const Expr &expr) { return IsNullPointerHelper{}(expr); } + bool IsNullProcedurePointer(const Expr &expr) { return IsNullPointerHelper{}(expr); } + bool IsNullPointer(const Expr &expr) { return IsNullObjectPointer(expr) || IsNullProcedurePointer(expr); } +bool IsBareNullPointer(const Expr *expr) { + return expr && std::holds_alternative(expr->u); +} + // GetSymbolVector() auto GetSymbolVectorHelper::operator()(const Symbol &x) const -> Result { if (const auto *details{x.detailsIf()}) {