Skip to content

[flang] Accept pointer-valued function results as ASSOCIATED() arguments #66238

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 18, 2023

Conversation

klausler
Copy link
Contributor

The POINTER= and TARGET= arguments to the intrinsic function ASSOCIATED() can be the results of references to functions that return object pointers or procedure pointers. NULL() was working well but not program-defined pointer-valued functions. Correct the validation of ASSOCIATED() and extend the infrastructure used to detect and characterize procedures and pointers.

@klausler klausler requested a review from vdonaldson September 13, 2023 16:47
@klausler klausler requested review from a team as code owners September 13, 2023 16:47
@llvmbot llvmbot added flang Flang issues not falling into any other category flang:semantics flang:fir-hlfir labels Sep 13, 2023
@llvmbot
Copy link
Member

llvmbot commented Sep 13, 2023

@llvm/pr-subscribers-flang-semantics

Changes The POINTER= and TARGET= arguments to the intrinsic function ASSOCIATED() can be the results of references to functions that return object pointers or procedure pointers. NULL() was working well but not program-defined pointer-valued functions. Correct the validation of ASSOCIATED() and extend the infrastructure used to detect and characterize procedures and pointers. --

Patch is 45.72 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/66238.diff

15 Files Affected:

  • (modified) flang/include/flang/Evaluate/characteristics.h (+2)
  • (modified) flang/include/flang/Evaluate/tools.h (+28-8)
  • (modified) flang/lib/Evaluate/characteristics.cpp (+16)
  • (modified) flang/lib/Evaluate/fold-complex.cpp (+1-1)
  • (modified) flang/lib/Evaluate/intrinsics.cpp (+3-3)
  • (modified) flang/lib/Evaluate/tools.cpp (+24-37)
  • (modified) flang/lib/Lower/ConvertCall.cpp (+3-6)
  • (modified) flang/lib/Lower/ConvertExpr.cpp (+13-20)
  • (modified) flang/lib/Lower/ConvertVariable.cpp (+1-1)
  • (modified) flang/lib/Lower/CustomIntrinsicCall.cpp (+11-17)
  • (modified) flang/lib/Semantics/check-call.cpp (+38-65)
  • (modified) flang/test/Semantics/associate01.f90 (+4-4)
  • (modified) flang/test/Semantics/associated.f90 (+39-8)
  • (modified) flang/test/Semantics/call09.f90 (+7-7)
  • (modified) flang/test/Semantics/call24.f90 (+1-1)

<pre>
diff --git a/flang/include/flang/Evaluate/characteristics.h b/flang/include/flang/Evaluate/characteristics.h
index 932f3220c2bcbbb..20750dfad8ce06e 100644
--- a/flang/include/flang/Evaluate/characteristics.h
+++ b/flang/include/flang/Evaluate/characteristics.h
@@ -349,6 +349,8 @@ struct Procedure {
const ProcedureDesignator &amp;, FoldingContext &amp;);
static std::optional&lt;Procedure&gt; Characterize(
const ProcedureRef &amp;, FoldingContext &amp;);

  • static std::optional&lt;Procedure&gt; Characterize(
  •  const Expr&amp;lt;SomeType&amp;gt; &amp;amp;, FoldingContext &amp;amp;);
    
    // Characterizes the procedure being referenced, deducing dummy argument
    // types from actual arguments in the case of an implicit interface.
    static std::optional&lt;Procedure&gt; FromActuals(
    diff --git a/flang/include/flang/Evaluate/tools.h b/flang/include/flang/Evaluate/tools.h
    index b3f8f4a67a7b5dd..6caad5db4b39b2d 100644
    --- a/flang/include/flang/Evaluate/tools.h
    +++ b/flang/include/flang/Evaluate/tools.h
    @@ -243,6 +243,29 @@ auto UnwrapConvertedExpr(B &amp;x) -&gt; common::Constify&lt;A, B&gt; * {
    return nullptr;
    }

+// UnwrapProcedureRef() returns a pointer to a ProcedureRef when the whole
+// expression is a reference to a procedure.
+template &lt;typename A&gt; inline const ProcedureRef *UnwrapProcedureRef(const A &amp;) {

  • return nullptr;
    +}

+inline const ProcedureRef *UnwrapProcedureRef(const ProcedureRef &amp;proc) {

  • // Reference to subroutine or to a function that returns
  • // an object pointer or procedure pointer
  • return &amp;proc;
    +}

+template &lt;typename T&gt;
+inline const ProcedureRef *UnwrapProcedureRef(const FunctionRef&lt;T&gt; &amp;func) {

  • return &amp;func; // reference to a function returning a non-pointer
    +}

+template &lt;typename T&gt;
+inline const ProcedureRef *UnwrapProcedureRef(const Expr&lt;T&gt; &amp;expr) {

  • return common::visit(
  •  [](const auto &amp;amp;x) { return UnwrapProcedureRef(x); }, expr.u);
    

+}
+
// When an expression is a &quot;bare&quot; LEN= derived type parameter inquiry,
// possibly wrapped in integer kind conversions &amp;/or parentheses, return
// a pointer to the Symbol with TypeParamDetails.
@@ -894,10 +917,6 @@ template &lt;typename A&gt; const Symbol *GetLastSymbol(const A &amp;x) {
}
}

-// If a function reference constitutes an entire expression, return a pointer
-// to its PrcedureRef.
-const ProcedureRef *GetProcedureRef(const Expr&lt;SomeType&gt; &amp;);

// For everyday variables: if GetLastSymbol() succeeds on the argument, return
// its set of attributes, otherwise the empty set. Also works on variables that
// are pointer results of functions.
@@ -912,7 +931,7 @@ template &lt;typename A&gt; semantics::Attrs GetAttrs(const A &amp;x) {
template &lt;&gt;
inline semantics::Attrs GetAttrs&lt;Expr&lt;SomeType&gt;&gt;(const Expr&lt;SomeType&gt; &amp;x) {
if (IsVariable(x)) {

  • if (const auto *procRef{GetProcedureRef(x)}) {
  • if (const auto *procRef{UnwrapProcedureRef(x)}) {
    if (const Symbol * interface{procRef-&gt;proc().GetInterfaceSymbol()}) {
    if (const auto *details{
    interface-&gt;detailsIf&lt;semantics::SubprogramDetails&gt;()}) {
    @@ -963,24 +982,25 @@ std::optional&lt;BaseObject&gt; GetBaseObject(const std::optional&lt;A&gt; &amp;x) {

// Like IsAllocatableOrPointer, but accepts pointer function results as being
// pointers too.
-bool IsAllocatableOrPointerObject(const Expr&lt;SomeType&gt; &amp;, FoldingContext &amp;);
+bool IsAllocatableOrPointerObject(const Expr&lt;SomeType&gt; &amp;);

bool IsAllocatableDesignator(const Expr&lt;SomeType&gt; &amp;);

// Procedure and pointer detection predicates
bool IsProcedure(const Expr&lt;SomeType&gt; &amp;);
bool IsFunction(const Expr&lt;SomeType&gt; &amp;);
+bool IsPointer(const Expr&lt;SomeType&gt; &amp;);
bool IsProcedurePointer(const Expr&lt;SomeType&gt; &amp;);
bool IsProcedurePointerTarget(const Expr&lt;SomeType&gt; &amp;);
bool IsBareNullPointer(const Expr&lt;SomeType&gt; *); // NULL() w/o MOLD= or type
bool IsNullObjectPointer(const Expr&lt;SomeType&gt; &amp;);
bool IsNullProcedurePointer(const Expr&lt;SomeType&gt; &amp;);
bool IsNullPointer(const Expr&lt;SomeType&gt; &amp;);
-bool IsObjectPointer(const Expr&lt;SomeType&gt; &amp;, FoldingContext &amp;);
+bool IsObjectPointer(const Expr&lt;SomeType&gt; &amp;);

// Can Expr be passed as absent to an optional dummy argument.
// See 15.5.2.12 point 1 for more details.
-bool MayBePassedAsAbsentOptional(const Expr&lt;SomeType&gt; &amp;, FoldingContext &amp;);
+bool MayBePassedAsAbsentOptional(const Expr&lt;SomeType&gt; &amp;);

// Extracts the chain of symbols from a designator, which has perhaps been
// wrapped in an Expr&lt;&gt;, removing all of the (co)subscripts. The
diff --git a/flang/lib/Evaluate/characteristics.cpp b/flang/lib/Evaluate/characteristics.cpp
index 8d52eabc16d502b..6daa113abe64255 100644
--- a/flang/lib/Evaluate/characteristics.cpp
+++ b/flang/lib/Evaluate/characteristics.cpp
@@ -1268,6 +1268,22 @@ std::optional&lt;Procedure&gt; Procedure::Characterize(
return std::nullopt;
}

+std::optional&lt;Procedure&gt; Procedure::Characterize(

  • const Expr&lt;SomeType&gt; &amp;expr, FoldingContext &amp;context) {
  • if (const auto *procRef{UnwrapProcedureRef(expr)}) {
  • return Characterize(*procRef, context);
  • } else if (const auto *procDesignator{
  •             std::get_if&amp;lt;ProcedureDesignator&amp;gt;(&amp;amp;expr.u)}) {
    
  • return Characterize(*procDesignator, context);
  • } else if (const Symbol * symbol{UnwrapWholeSymbolOrComponentDataRef(expr)}) {
  • return Characterize(*symbol, context);
  • } else {
  • context.messages().Say(
  •    &amp;quot;Expression &amp;#x27;%s&amp;#x27; is not a procedure&amp;quot;_err_en_US, expr.AsFortran());
    
  • return std::nullopt;
  • }
    +}

std::optional&lt;Procedure&gt; Procedure::FromActuals(const ProcedureDesignator &amp;proc,
const ActualArguments &amp;args, FoldingContext &amp;context) {
auto callee{Characterize(proc, context)};
diff --git a/flang/lib/Evaluate/fold-complex.cpp b/flang/lib/Evaluate/fold-complex.cpp
index 520121ad254de77..e40e3a37df14948 100644
--- a/flang/lib/Evaluate/fold-complex.cpp
+++ b/flang/lib/Evaluate/fold-complex.cpp
@@ -47,7 +47,7 @@ Expr&lt;Type&lt;TypeCategory::Complex, KIND&gt;&gt; FoldIntrinsicFunction(
// into a complex constructor so that lowering can deal with the
// optional aspect (there is no optional aspect with the complex
// constructor).

  •      if (MayBePassedAsAbsentOptional(*args[1]-&amp;gt;UnwrapExpr(), context)) {
    
  •      if (MayBePassedAsAbsentOptional(*args[1]-&amp;gt;UnwrapExpr())) {
           return Expr&amp;lt;T&amp;gt;{std::move(funcRef)};
         }
       }
    

diff --git a/flang/lib/Evaluate/intrinsics.cpp b/flang/lib/Evaluate/intrinsics.cpp
index 030e5b2fd2c6d9d..448e9aae6d5403e 100644
--- a/flang/lib/Evaluate/intrinsics.cpp
+++ b/flang/lib/Evaluate/intrinsics.cpp
@@ -2577,7 +2577,7 @@ SpecificCall IntrinsicProcTable::Implementation::HandleNull(
arguments[0]) {
if (Expr&lt;SomeType&gt; * mold{arguments[0]-&gt;UnwrapExpr()}) {
bool isProcPtrTarget{IsProcedurePointerTarget(*mold)};

  •  if (isProcPtrTarget || IsAllocatableOrPointerObject(*mold, context)) {
    
  •  if (isProcPtrTarget || IsAllocatableOrPointerObject(*mold)) {
       characteristics::DummyArguments args;
       std::optional&amp;lt;characteristics::FunctionResult&amp;gt; fResult;
       if (isProcPtrTarget) {
    

@@ -2747,7 +2747,7 @@ std::optional&lt;SpecificCall&gt; IntrinsicProcTable::Implementation::HandleC_Loc(
CheckForCoindexedObject(context, arguments[0], &quot;c_loc&quot;, &quot;x&quot;);
const auto *expr{arguments[0].value().UnwrapExpr()};
if (expr &amp;&amp;

  •    !(IsObjectPointer(*expr, context) ||
    
  •    !(IsObjectPointer(*expr) ||
           (IsVariable(*expr) &amp;amp;&amp;amp; GetLastTarget(GetSymbolVector(*expr))))) {
     context.messages().Say(arguments[0]-&amp;gt;sourceLocation(),
         &amp;quot;C_LOC() argument must be a data pointer or target&amp;quot;_err_en_US);
    

@@ -3094,7 +3094,7 @@ std::optional&lt;SpecificCall&gt; IntrinsicProcTable::Implementation::Probe(
for (const auto &amp;arg : arguments) {
if (const auto *expr{arg-&gt;UnwrapExpr()}) {
optionalCount +=

  •          Fortran::evaluate::MayBePassedAsAbsentOptional(*expr, context);
    
  •          Fortran::evaluate::MayBePassedAsAbsentOptional(*expr);
       }
     }
     if (arguments.size() - optionalCount &amp;gt; 1) {
    

diff --git a/flang/lib/Evaluate/tools.cpp b/flang/lib/Evaluate/tools.cpp
index d2fa5c9b5f36be6..0392adc60adb4e6 100644
--- a/flang/lib/Evaluate/tools.cpp
+++ b/flang/lib/Evaluate/tools.cpp
@@ -740,16 +740,25 @@ bool IsFunction(const Expr&lt;SomeType&gt; &amp;expr) {
return designator &amp;&amp; designator-&gt;GetType().has_value();
}

+bool IsPointer(const Expr&lt;SomeType&gt; &amp;expr) {

  • return IsObjectPointer(expr) || IsProcedurePointer(expr);
    +}

bool IsProcedurePointer(const Expr&lt;SomeType&gt; &amp;expr) {

  • return common::visit(common::visitors{
  •                       [](const NullPointer &amp;amp;) { return true; },
    
  •                       [](const ProcedureRef &amp;amp;) { return false; },
    
  •                       [&amp;amp;](const auto &amp;amp;) {
    
  •                         const Symbol *last{GetLastSymbol(expr)};
    
  •                         return last &amp;amp;&amp;amp; IsProcedurePointer(*last);
    
  •                       },
    
  •                   },
    
  •  expr.u);
    
  • if (IsNullProcedurePointer(expr)) {
  • return true;
  • } else if (const auto *funcRef{UnwrapProcedureRef(expr)}) {
  • if (const Symbol * proc{funcRef-&gt;proc().GetSymbol()}) {
  •  const Symbol *result{FindFunctionResult(*proc)};
    
  •  return result &amp;amp;&amp;amp; IsProcedurePointer(*result);
    
  • } else {
  •  return false;
    
  • }
  • } else if (const auto *proc{std::get_if&lt;ProcedureDesignator&gt;(&amp;expr.u)}) {
  • return IsProcedurePointer(proc-&gt;GetSymbol());
  • } else {
  • return false;
  • }
    }

bool IsProcedurePointerTarget(const Expr&lt;SomeType&gt; &amp;expr) {
@@ -765,23 +774,7 @@ bool IsProcedurePointerTarget(const Expr&lt;SomeType&gt; &amp;expr) {
expr.u);
}

-template &lt;typename A&gt; inline const ProcedureRef *UnwrapProcedureRef(const A &amp;) {

  • return nullptr;
    -}

-template &lt;typename T&gt;
-inline const ProcedureRef *UnwrapProcedureRef(const FunctionRef&lt;T&gt; &amp;func) {

  • return &amp;func;
    -}

-template &lt;typename T&gt;
-inline const ProcedureRef *UnwrapProcedureRef(const Expr&lt;T&gt; &amp;expr) {

  • return common::visit(
  •  [](const auto &amp;amp;x) { return UnwrapProcedureRef(x); }, expr.u);
    

-}

-// IsObjectPointer()
-bool IsObjectPointer(const Expr&lt;SomeType&gt; &amp;expr, FoldingContext &amp;context) {
+bool IsObjectPointer(const Expr&lt;SomeType&gt; &amp;expr) {
if (IsNullObjectPointer(expr)) {
return true;
} else if (IsProcedurePointerTarget(expr)) {
@@ -795,10 +788,6 @@ bool IsObjectPointer(const Expr&lt;SomeType&gt; &amp;expr, FoldingContext &amp;context) {
}
}

-const ProcedureRef *GetProcedureRef(const Expr&lt;SomeType&gt; &amp;expr) {

  • return UnwrapProcedureRef(expr);
    -}

// IsNullPointer() &amp; variations

template &lt;bool IS_PROC_PTR&gt; struct IsNullPointerHelper {
@@ -872,7 +861,7 @@ bool IsBareNullPointer(const Expr&lt;SomeType&gt; *expr) {
// GetSymbolVector()
auto GetSymbolVectorHelper::operator()(const Symbol &amp;x) const -&gt; Result {
if (const auto *details{x.detailsIf&lt;semantics::AssocEntityDetails&gt;()}) {

  • if (IsVariable(details-&gt;expr()) &amp;&amp; !GetProcedureRef(*details-&gt;expr())) {
  • if (IsVariable(details-&gt;expr()) &amp;&amp; !UnwrapProcedureRef(*details-&gt;expr())) {
    // associate(x =&gt; variable that is not a pointer returned by a function)
    return (*this)(details-&gt;expr());
    }
    @@ -1155,12 +1144,11 @@ std::optional&lt;Expr&lt;SomeType&gt;&gt; DataConstantConversionExtension(
    return std::nullopt;
    }

-bool IsAllocatableOrPointerObject(

  • const Expr&lt;SomeType&gt; &amp;expr, FoldingContext &amp;context) {
    +bool IsAllocatableOrPointerObject(const Expr&lt;SomeType&gt; &amp;expr) {
    const semantics::Symbol *sym{UnwrapWholeSymbolOrComponentDataRef(expr)};
    return (sym &amp;&amp;
    semantics::IsAllocatableOrObjectPointer(&amp;sym-&gt;GetUltimate())) ||
  •  evaluate::IsObjectPointer(expr, context);
    
  •  evaluate::IsObjectPointer(expr);
    

}

bool IsAllocatableDesignator(const Expr&lt;SomeType&gt; &amp;expr) {
@@ -1172,15 +1160,14 @@ bool IsAllocatableDesignator(const Expr&lt;SomeType&gt; &amp;expr) {
return false;
}

-bool MayBePassedAsAbsentOptional(

  • const Expr&lt;SomeType&gt; &amp;expr, FoldingContext &amp;context) {
    +bool MayBePassedAsAbsentOptional(const Expr&lt;SomeType&gt; &amp;expr) {
    const semantics::Symbol *sym{UnwrapWholeSymbolOrComponentDataRef(expr)};
    // 15.5.2.12 1. is pretty clear that an unallocated allocatable/pointer actual
    // may be passed to a non-allocatable/non-pointer optional dummy. Note that
    // other compilers (like nag, nvfortran, ifort, gfortran and xlf) seems to
    // ignore this point in intrinsic contexts (e.g CMPLX argument).
    return (sym &amp;&amp; semantics::IsOptional(*sym)) ||
  •  IsAllocatableOrPointerObject(expr, context);
    
  •  IsAllocatableOrPointerObject(expr);
    

}

std::optional&lt;Expr&lt;SomeType&gt;&gt; HollerithToBOZ(FoldingContext &amp;context,
diff --git a/flang/lib/Lower/ConvertCall.cpp b/flang/lib/Lower/ConvertCall.cpp
index 15915b02aebaa70..fbf8eac642af2a7 100644
--- a/flang/lib/Lower/ConvertCall.cpp
+++ b/flang/lib/Lower/ConvertCall.cpp
@@ -1165,8 +1165,7 @@ genUserCall(Fortran::lower::PreparedActualArguments &amp;loweredActuals,
continue;
}
if (fir::isPointerType(argTy) &amp;&amp;

  •      !Fortran::evaluate::IsObjectPointer(
    
  •          *expr, callContext.converter.getFoldingContext())) {
    
  •      !Fortran::evaluate::IsObjectPointer(*expr)) {
       // Passing a non POINTER actual argument to a POINTER dummy argument.
       // Create a pointer of the dummy argument type and assign the actual
       // argument to it.
    

@@ -1814,13 +1813,11 @@ genIsPresentIfArgMaybeAbsent(mlir::Location loc, hlfir::Entity actual,
const Fortran::lower::SomeExpr &amp;expr,
CallContext &amp;callContext,
bool passAsAllocatableOrPointer) {

  • if (!Fortran::evaluate::MayBePassedAsAbsentOptional(
  •      expr, callContext.converter.getFoldingContext()))
    
  • if (!Fortran::evaluate::MayBePassedAsAbsentOptional(expr))
    return std::nullopt;
    fir::FirOpBuilder &amp;builder = callContext.getBuilder();
    if (!passAsAllocatableOrPointer &amp;&amp;
  •  Fortran::evaluate::IsAllocatableOrPointerObject(
    
  •      expr, callContext.converter.getFoldingContext())) {
    
  •  Fortran::evaluate::IsAllocatableOrPointerObject(expr)) {
    
    // Passing Allocatable/Pointer to non-pointer/non-allocatable OPTIONAL.
    // Fortran 2018 15.5.2.12 point 1: If unallocated/disassociated, it is
    // as if the argument was absent. The main care here is to not do a
    diff --git a/flang/lib/Lower/ConvertExpr.cpp b/flang/lib/Lower/ConvertExpr.cpp
    index a9298be5532d905..26519d204460c67 100644
    --- a/flang/lib/Lower/ConvertExpr.cpp
    +++ b/flang/lib/Lower/ConvertExpr.cpp
    @@ -1782,8 +1782,7 @@ class ScalarExprLowering {
    /// Helper to lower intrinsic arguments for inquiry intrinsic.
    ExtValue
    lowerIntrinsicArgumentAsInquired(const Fortran::lower::SomeExpr &amp;expr) {
  • if (Fortran::evaluate::IsAllocatableOrPointerObject(
  •        expr, converter.getFoldingContext()))
    
  • if (Fortran::evaluate::IsAllocatableOrPointerObject(expr))
    return genMutableBoxValue(expr);
    /// Do not create temps for array sections whose properties only need to be
    /// inquired: create a descriptor that will be inquired.
    @@ -1918,8 +1917,7 @@ class ScalarExprLowering {
    fir::ArgLoweringRule argRules =
    fir::lowerIntrinsicArgumentAs(*argLowering, arg.index());
    if (argRules.handleDynamicOptional &amp;&amp;
  •      Fortran::evaluate::MayBePassedAsAbsentOptional(
    
  •          *expr, converter.getFoldingContext())) {
    
  •      Fortran::evaluate::MayBePassedAsAbsentOptional(*expr)) {
       ExtValue optional = lowerIntrinsicArgumentAsInquired(*expr);
       mlir::Value isPresent = genActualIsPresentTest(builder, loc, optional);
       switch (argRules.lowerAs) {
    

@@ -2392,8 +2390,7 @@ class ScalarExprLowering {
std::pair&lt;ExtValue, mlir::Value&gt;
prepareActualThatMayBeAbsent(const Fortran::lower::SomeExpr &amp;expr) {
mlir::Location loc = getLoc();

  • if (Fortran::evaluate::IsAllocatableOrPointerObject(
  •        expr, converter.getFoldingContext())) {
    
  • if (Fortran::evaluate::IsAllocatableOrPointerObject(expr)) {
    // Fortran 2018 15.5.2.12 point 1: If unallocated/disassociated,
    // it is as if the argument was absent. The main care here is to
    // not do a copy-in/copy-out because the temp address, even though
    @@ -2496,8 +2493,8 @@ class ScalarExprLowering {
    // not passed.
    return {genTempExtAddr(expr), std::nullopt};
    ExtValue baseAddr;
  •  if (arg.isOptional() &amp;amp;&amp;amp; Fortran::evaluate::MayBePassedAsAbsentOptional(
    
  •                              expr, converter.getFoldingContext())) {
    
  •  if (arg.isOptional() &amp;amp;&amp;amp;
    
  •      Fortran::evaluate::MayBePassedAsAbsentOptional(expr)) {
       auto [actualArgBind, isPresent] = prepareActualThatMayBeAbsent(expr);
       const ExtValue &amp;amp;actualArg = actualArgBind;
       if (!needsCopy)
    

@@ -2631,8 +2628,7 @@ class ScalarExprLowering {
continue;
}
if (fir::isPointerType(argTy) &amp;&amp;

  •        !Fortran::evaluate::IsObjectPointer(
    
  •            *expr, converter.getFoldingContext())) {
    
  •        !Fortran::evaluate::IsObjectPointer(*expr)) {
         // Passing a non POINTER actual argument to a POINTER dummy argument.
         // Create a pointer of the dummy argument type and assign the actual
         // argument to it.
    

@@ -2759,8 +2755,7 @@ class ScalarExprLowering {
}

     } else if (arg.isOptional() &amp;amp;&amp;amp;
  •               Fortran::evaluate::IsAllocatableOrPointerObject(
    
  •                   *expr, converter.getFoldingContext())) {
    
  •               Fortran::evaluate::IsAllocatableOrPointerObject(*expr)) {
         // Before lowering to an address, handle the allocatable/pointer
         // actual argument to optional fir.box dummy. It is legal to pass
         // unallocated/disassociated entity to an optional. In this case, an
    

@@ -3355,8 +3350,7 @@ class ArrayExprLowering {
setPointerAssignmentBounds(lbounds, ubounds);
if (rhs.Rank() == 0 ||
(Fortran::evaluate::UnwrapWholeSymbolOrComponentDataRef(rhs) &amp;&amp;

  •     Fortran::evaluate::IsAllocatableOrPointerObject(
    
  •         rhs, converter.getFoldingContext()))) {
    
  •     Fortran::evaluate::IsAllocatableOrPointerObject(rhs))) {
     lowerScalarAssignment(lhs, rhs);
     return;
    
    }
    @@ -4684,8 +4678,7 @@ class ArrayExprLowering {
    fir::ArgLoweringRule argRules =
    fir::lowerIntrinsicArgumentAs(*argLowering, arg.index());
    if (argRules.handleDynamicOptional &amp;&amp;
  •        Fortran::evaluate::MayBePassedAsAbsentOptional(
    
  •            *e...
    

The POINTER= and TARGET= arguments to the intrinsic function
ASSOCIATED() can be the results of references to functions that
return object pointers or procedure pointers.  NULL() was working
well but not program-defined pointer-valued functions.  Correct the
validation of ASSOCIATED() and extend the infrastructure used to
detect and characterize procedures and pointers.

Pull request: llvm#66238
@klausler klausler merged commit f025e41 into llvm:main Sep 18, 2023
@klausler klausler deleted the u7 branch September 18, 2023 15:39
ZijunZhaoCCK pushed a commit to ZijunZhaoCCK/llvm-project that referenced this pull request Sep 19, 2023
…nts (llvm#66238)

The POINTER= and TARGET= arguments to the intrinsic function
ASSOCIATED() can be the results of references to functions that return
object pointers or procedure pointers. NULL() was working well but not
program-defined pointer-valued functions. Correct the validation of
ASSOCIATED() and extend the infrastructure used to detect and
characterize procedures and pointers.
zahiraam pushed a commit to tahonermann/llvm-project that referenced this pull request Oct 24, 2023
…nts (llvm#66238)

The POINTER= and TARGET= arguments to the intrinsic function
ASSOCIATED() can be the results of references to functions that return
object pointers or procedure pointers. NULL() was working well but not
program-defined pointer-valued functions. Correct the validation of
ASSOCIATED() and extend the infrastructure used to detect and
characterize procedures and pointers.
zahiraam pushed a commit to tahonermann/llvm-project that referenced this pull request Oct 24, 2023
…nts (llvm#66238)

The POINTER= and TARGET= arguments to the intrinsic function
ASSOCIATED() can be the results of references to functions that return
object pointers or procedure pointers. NULL() was working well but not
program-defined pointer-valued functions. Correct the validation of
ASSOCIATED() and extend the infrastructure used to detect and
characterize procedures and pointers.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
flang:fir-hlfir flang Flang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants