xref: /llvm-project/flang/lib/Semantics/check-purity.cpp (revision 33c27f28d1cd05fd0a739498105927c1fba04666)
164ab3302SCarolineConcatto //===-- lib/Semantics/check-purity.cpp ------------------------------------===//
264ab3302SCarolineConcatto //
364ab3302SCarolineConcatto // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
464ab3302SCarolineConcatto // See https://llvm.org/LICENSE.txt for license information.
564ab3302SCarolineConcatto // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
664ab3302SCarolineConcatto //
764ab3302SCarolineConcatto //===----------------------------------------------------------------------===//
864ab3302SCarolineConcatto 
964ab3302SCarolineConcatto #include "check-purity.h"
1064ab3302SCarolineConcatto #include "flang/Parser/parse-tree.h"
1164ab3302SCarolineConcatto #include "flang/Semantics/tools.h"
1264ab3302SCarolineConcatto 
1364ab3302SCarolineConcatto namespace Fortran::semantics {
1464ab3302SCarolineConcatto void PurityChecker::Enter(const parser::ExecutableConstruct &exec) {
1564ab3302SCarolineConcatto   if (InPureSubprogram() && IsImageControlStmt(exec)) {
1664ab3302SCarolineConcatto     context_.Say(GetImageControlStmtLocation(exec),
1764ab3302SCarolineConcatto         "An image control statement may not appear in a pure subprogram"_err_en_US);
1864ab3302SCarolineConcatto   }
1964ab3302SCarolineConcatto }
2064ab3302SCarolineConcatto void PurityChecker::Enter(const parser::SubroutineSubprogram &subr) {
2164ab3302SCarolineConcatto   const auto &stmt{std::get<parser::Statement<parser::SubroutineStmt>>(subr.t)};
2264ab3302SCarolineConcatto   Entered(
2364ab3302SCarolineConcatto       stmt.source, std::get<std::list<parser::PrefixSpec>>(stmt.statement.t));
2464ab3302SCarolineConcatto }
2564ab3302SCarolineConcatto 
2664ab3302SCarolineConcatto void PurityChecker::Leave(const parser::SubroutineSubprogram &) { Left(); }
2764ab3302SCarolineConcatto 
2864ab3302SCarolineConcatto void PurityChecker::Enter(const parser::FunctionSubprogram &func) {
2964ab3302SCarolineConcatto   const auto &stmt{std::get<parser::Statement<parser::FunctionStmt>>(func.t)};
3064ab3302SCarolineConcatto   Entered(
3164ab3302SCarolineConcatto       stmt.source, std::get<std::list<parser::PrefixSpec>>(stmt.statement.t));
3264ab3302SCarolineConcatto }
3364ab3302SCarolineConcatto 
34*33c27f28SPeter Klausler void PurityChecker::Leave(const parser::FunctionSubprogram &func) { Left(); }
3564ab3302SCarolineConcatto 
3664ab3302SCarolineConcatto bool PurityChecker::InPureSubprogram() const {
3764ab3302SCarolineConcatto   return pureDepth_ >= 0 && depth_ >= pureDepth_;
3864ab3302SCarolineConcatto }
3964ab3302SCarolineConcatto 
4064ab3302SCarolineConcatto bool PurityChecker::HasPurePrefix(
4164ab3302SCarolineConcatto     const std::list<parser::PrefixSpec> &prefixes) const {
42325d1d0bSPeter Klausler   bool result{false};
4364ab3302SCarolineConcatto   for (const parser::PrefixSpec &prefix : prefixes) {
44325d1d0bSPeter Klausler     if (std::holds_alternative<parser::PrefixSpec::Impure>(prefix.u)) {
4564ab3302SCarolineConcatto       return false;
46325d1d0bSPeter Klausler     } else if (std::holds_alternative<parser::PrefixSpec::Pure>(prefix.u) ||
47325d1d0bSPeter Klausler         std::holds_alternative<parser::PrefixSpec::Elemental>(prefix.u)) {
48325d1d0bSPeter Klausler       result = true;
49325d1d0bSPeter Klausler     }
50325d1d0bSPeter Klausler   }
51325d1d0bSPeter Klausler   return result;
5264ab3302SCarolineConcatto }
5364ab3302SCarolineConcatto 
5464ab3302SCarolineConcatto void PurityChecker::Entered(
5564ab3302SCarolineConcatto     parser::CharBlock source, const std::list<parser::PrefixSpec> &prefixes) {
5664ab3302SCarolineConcatto   if (depth_ == 2) {
5764ab3302SCarolineConcatto     context_.messages().Say(source,
5864ab3302SCarolineConcatto         "An internal subprogram may not contain an internal subprogram"_err_en_US);
5964ab3302SCarolineConcatto   }
6064ab3302SCarolineConcatto   if (HasPurePrefix(prefixes)) {
6164ab3302SCarolineConcatto     if (pureDepth_ < 0) {
6264ab3302SCarolineConcatto       pureDepth_ = depth_;
6364ab3302SCarolineConcatto     }
6464ab3302SCarolineConcatto   } else if (InPureSubprogram()) {
6564ab3302SCarolineConcatto     context_.messages().Say(source,
6664ab3302SCarolineConcatto         "An internal subprogram of a pure subprogram must also be pure"_err_en_US);
6764ab3302SCarolineConcatto   }
6864ab3302SCarolineConcatto   ++depth_;
6964ab3302SCarolineConcatto }
7064ab3302SCarolineConcatto 
7164ab3302SCarolineConcatto void PurityChecker::Left() {
7264ab3302SCarolineConcatto   if (pureDepth_ == --depth_) {
7364ab3302SCarolineConcatto     pureDepth_ = -1;
7464ab3302SCarolineConcatto   }
7564ab3302SCarolineConcatto }
7664ab3302SCarolineConcatto 
771f879005STim Keith } // namespace Fortran::semantics
78