From b8641bfc4c2d488c7a09a556728f10340d5c8819 Mon Sep 17 00:00:00 2001 From: Peter Klausler Date: Wed, 3 Aug 2022 12:21:17 -0700 Subject: [PATCH] [flang] Don't compute pointer component procedure characteristics when not needed When a procedure pointer component has an interface that is a forward reference to a procedure, syntax errors can be emitted if there is a structure constructor that tries to initialize that component, since its characteristics are not yet known; however, when the initializer is a bare NULL(with no mold), those characteristics don't matter. Make the characterization of the procedure pointer component take place only when needed. Differential Revision: https://reviews.llvm.org/D131100 --- flang/lib/Semantics/pointer-assignment.cpp | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/flang/lib/Semantics/pointer-assignment.cpp b/flang/lib/Semantics/pointer-assignment.cpp index 71b7387..69e80e5 100644 --- a/flang/lib/Semantics/pointer-assignment.cpp +++ b/flang/lib/Semantics/pointer-assignment.cpp @@ -48,9 +48,6 @@ public: set_lhsType(TypeAndShape::Characterize(lhs, context)); set_isContiguous(lhs.attrs().test(Attr::CONTIGUOUS)); set_isVolatile(lhs.attrs().test(Attr::VOLATILE)); - if (IsProcedure(lhs)) { - procedure_ = Procedure::Characterize(lhs, context); - } } PointerAssignmentChecker &set_lhsType(std::optional &&); PointerAssignmentChecker &set_isContiguous(bool); @@ -59,6 +56,7 @@ public: bool Check(const SomeExpr &); private: + bool CharacterizeProcedure(); template bool Check(const T &); template bool Check(const evaluate::Expr &); template bool Check(const evaluate::FunctionRef &); @@ -79,6 +77,7 @@ private: const Symbol *lhs_{nullptr}; std::optional lhsType_; std::optional procedure_; + bool characterizedProcedure_{false}; bool isContiguous_{false}; bool isVolatile_{false}; bool isBoundsRemapping_{false}; @@ -108,6 +107,16 @@ PointerAssignmentChecker &PointerAssignmentChecker::set_isBoundsRemapping( return *this; } +bool PointerAssignmentChecker::CharacterizeProcedure() { + if (!characterizedProcedure_) { + characterizedProcedure_ = true; + if (lhs_ && IsProcedure(*lhs_)) { + procedure_ = Procedure::Characterize(*lhs_, context_); + } + } + return procedure_.has_value(); +} + template bool PointerAssignmentChecker::Check(const T &) { // Catch-all case for really bad target expression Say("Target associated with %s must be a designator or a call to a" @@ -155,7 +164,7 @@ bool PointerAssignmentChecker::Check(const evaluate::FunctionRef &f) { if (!funcResult) { msg = "%s is associated with the non-existent result of reference to" " procedure"_err_en_US; - } else if (procedure_) { + } else if (CharacterizeProcedure()) { // Shouldn't be here in this function unless lhs is an object pointer. msg = "Procedure %s is associated with the result of a reference to" " function '%s' that does not return a procedure pointer"_err_en_US; @@ -197,7 +206,7 @@ bool PointerAssignmentChecker::Check(const evaluate::Designator &d) { return false; } std::optional> msg; - if (procedure_) { + if (CharacterizeProcedure()) { // Shouldn't be here in this function unless lhs is an object pointer. msg = "In assignment to procedure %s, the target is not a procedure or" " procedure pointer"_err_en_US; @@ -260,6 +269,7 @@ bool PointerAssignmentChecker::Check(parser::CharBlock rhsName, bool isCall, const Procedure *rhsProcedure, const evaluate::SpecificIntrinsic *specific) { std::string whyNot; + CharacterizeProcedure(); if (std::optional msg{evaluate::CheckProcCompatibility( isCall, procedure_, rhsProcedure, specific, whyNot)}) { Say(std::move(*msg), description_, rhsName, whyNot); -- 2.7.4