bool operator==(const Procedure &) const;
bool operator!=(const Procedure &that) const { return !(*this == that); }
- // Characterizes the procedure represented by a symbol, which may be an
+ // Characterizes a procedure. If a Symbol, it may be an
// "unrestricted specific intrinsic function".
+ // Error messages are produced when a procedure cannot be characterized.
static std::optional<Procedure> Characterize(
const semantics::Symbol &, FoldingContext &);
- // This function is the initial point of entry for characterizing procedure
static std::optional<Procedure> Characterize(
const ProcedureDesignator &, FoldingContext &);
static std::optional<Procedure> Characterize(
[&](const semantics::HostAssocDetails &assoc) {
return CharacterizeProcedure(assoc.symbol(), context, seenProcs);
},
- [](const auto &) { return std::optional<Procedure>{}; },
+ [&](const semantics::EntityDetails &) {
+ context.messages().Say(
+ "Procedure '%s' is referenced before being sufficiently defined in a context where it must be so"_err_en_US,
+ symbol.name());
+ return std::optional<Procedure>{};
+ },
+ [&](const semantics::SubprogramNameDetails &) {
+ context.messages().Say(
+ "Procedure '%s' is referenced before being sufficiently defined in a context where it must be so"_err_en_US,
+ symbol.name());
+ return std::optional<Procedure>{};
+ },
+ [&](const auto &) {
+ context.messages().Say(
+ "'%s' is not a procedure"_err_en_US, symbol.name());
+ return std::optional<Procedure>{};
+ },
},
symbol.details());
}
// MOLD= procedure pointer
const Symbol *last{GetLastSymbol(*mold)};
CHECK(last);
- auto procPointer{
- characteristics::Procedure::Characterize(*last, context)};
+ auto procPointer{IsProcedure(*last)
+ ? characteristics::Procedure::Characterize(*last, context)
+ : std::nullopt};
// procPointer is null if there was an error with the analysis
// associated with the procedure pointer
if (procPointer) {
"POINTER"_err_en_US),
*pointerSymbol);
} else {
- const auto pointerProc{characteristics::Procedure::Characterize(
- *pointerSymbol, context)};
if (const auto &targetArg{call.arguments[1]}) {
if (const auto *targetExpr{targetArg->UnwrapExpr()}) {
- std::optional<characteristics::Procedure> targetProc{
- std::nullopt};
+ std::optional<characteristics::Procedure> pointerProc, targetProc;
const Symbol *targetSymbol{GetLastSymbol(*targetExpr)};
bool isCall{false};
std::string targetName;
targetName = targetProcRef->proc().GetName() + "()";
isCall = true;
}
- } else if (targetSymbol && !targetProc) {
+ } else if (targetSymbol) {
// proc that's not a call
- targetProc = characteristics::Procedure::Characterize(
- *targetSymbol, context);
+ if (IsProcedure(*targetSymbol)) {
+ targetProc = characteristics::Procedure::Characterize(
+ *targetSymbol, context);
+ }
targetName = targetSymbol->name().ToString();
}
-
+ if (IsProcedure(*pointerSymbol)) {
+ pointerProc = characteristics::Procedure::Characterize(
+ *pointerSymbol, context);
+ }
if (pointerProc) {
if (targetProc) {
// procedure pointer and procedure target
} else if (FindSeparateModuleSubprogramInterface(subprogram)) {
error = "ENTRY may not appear in a separate module procedure"_err_en_US;
} else if (subprogramDetails && details.isFunction() &&
- subprogramDetails->isFunction()) {
+ subprogramDetails->isFunction() &&
+ !context_.HasError(details.result()) &&
+ !context_.HasError(subprogramDetails->result())) {
auto result{FunctionResult::Characterize(
details.result(), context_.foldingContext())};
auto subpResult{FunctionResult::Characterize(
Say(sc.component.source, "'%s' is not a procedure"_err_en_US,
sc.component.source),
*sym);
+ return std::nullopt;
}
if (auto *dtExpr{UnwrapExpr<Expr<SomeDerived>>(*base)}) {
if (sym->has<semantics::GenericDetails>()) {
: context_{context}, source_{source}, description_{description} {}
PointerAssignmentChecker(evaluate::FoldingContext &context, const Symbol &lhs)
: context_{context}, source_{lhs.name()},
- description_{"pointer '"s + lhs.name().ToString() + '\''}, lhs_{&lhs},
- procedure_{Procedure::Characterize(lhs, context)} {
+ description_{"pointer '"s + lhs.name().ToString() + '\''}, lhs_{&lhs} {
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<TypeAndShape> &&);
PointerAssignmentChecker &set_isContiguous(bool);
Say2(effectiveResultName.source,
"'%s' was previously declared as an item that may not be used as a function result"_err_en_US,
resultSymbol->name(), "Previous declaration of '%s'"_en_US);
+ context().SetError(*resultSymbol);
}},
resultSymbol->details());
} else if (inExecutionPart_) {
call p2
call p3
end program
+
+module mutualSpecExprs
+contains
+ pure integer function f(n)
+ integer, intent(in) :: n
+ real arr(g(n))
+ f = size(arr)
+ end function
+ pure integer function g(n)
+ integer, intent(in) :: n
+ !ERROR: Procedure 'f' is referenced before being sufficiently defined in a context where it must be so
+ real arr(f(n))
+ g = size(arr)
+ end function
+end