mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-29 23:26:05 +00:00

When the result of a function never appears in a variable definition context, emit a warning. If the function has multiple result variables due to alternate ENTRY statements, any definition will suffice. The implementation of this check is tied to the general variable definability checking utility in semantics. Every variable definition context uses it to ensure that no undefinable variable is being defined. A set of defined variables is maintained in the SemanticsContext and, when the warning is enabled and no fatal error has been reported, the scope tree is traversed and all the function subprograms' results are tested for membership in that set.
78 lines
2.6 KiB
C++
78 lines
2.6 KiB
C++
//===-- lib/Semantics/check-purity.cpp ------------------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "check-purity.h"
|
|
#include "flang/Parser/parse-tree.h"
|
|
#include "flang/Semantics/tools.h"
|
|
|
|
namespace Fortran::semantics {
|
|
void PurityChecker::Enter(const parser::ExecutableConstruct &exec) {
|
|
if (InPureSubprogram() && IsImageControlStmt(exec)) {
|
|
context_.Say(GetImageControlStmtLocation(exec),
|
|
"An image control statement may not appear in a pure subprogram"_err_en_US);
|
|
}
|
|
}
|
|
void PurityChecker::Enter(const parser::SubroutineSubprogram &subr) {
|
|
const auto &stmt{std::get<parser::Statement<parser::SubroutineStmt>>(subr.t)};
|
|
Entered(
|
|
stmt.source, std::get<std::list<parser::PrefixSpec>>(stmt.statement.t));
|
|
}
|
|
|
|
void PurityChecker::Leave(const parser::SubroutineSubprogram &) { Left(); }
|
|
|
|
void PurityChecker::Enter(const parser::FunctionSubprogram &func) {
|
|
const auto &stmt{std::get<parser::Statement<parser::FunctionStmt>>(func.t)};
|
|
Entered(
|
|
stmt.source, std::get<std::list<parser::PrefixSpec>>(stmt.statement.t));
|
|
}
|
|
|
|
void PurityChecker::Leave(const parser::FunctionSubprogram &func) { Left(); }
|
|
|
|
bool PurityChecker::InPureSubprogram() const {
|
|
return pureDepth_ >= 0 && depth_ >= pureDepth_;
|
|
}
|
|
|
|
bool PurityChecker::HasPurePrefix(
|
|
const std::list<parser::PrefixSpec> &prefixes) const {
|
|
bool result{false};
|
|
for (const parser::PrefixSpec &prefix : prefixes) {
|
|
if (std::holds_alternative<parser::PrefixSpec::Impure>(prefix.u)) {
|
|
return false;
|
|
} else if (std::holds_alternative<parser::PrefixSpec::Pure>(prefix.u) ||
|
|
std::holds_alternative<parser::PrefixSpec::Elemental>(prefix.u)) {
|
|
result = true;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
void PurityChecker::Entered(
|
|
parser::CharBlock source, const std::list<parser::PrefixSpec> &prefixes) {
|
|
if (depth_ == 2) {
|
|
context_.messages().Say(source,
|
|
"An internal subprogram may not contain an internal subprogram"_err_en_US);
|
|
}
|
|
if (HasPurePrefix(prefixes)) {
|
|
if (pureDepth_ < 0) {
|
|
pureDepth_ = depth_;
|
|
}
|
|
} else if (InPureSubprogram()) {
|
|
context_.messages().Say(source,
|
|
"An internal subprogram of a pure subprogram must also be pure"_err_en_US);
|
|
}
|
|
++depth_;
|
|
}
|
|
|
|
void PurityChecker::Left() {
|
|
if (pureDepth_ == --depth_) {
|
|
pureDepth_ = -1;
|
|
}
|
|
}
|
|
|
|
} // namespace Fortran::semantics
|