// See the License for the specific language governing permissions and
// limitations under the License.
-#include "attr.h"
#include "check-arithmeticif.h"
+#include "attr.h"
#include "scope.h"
#include "semantics.h"
#include "symbol.h"
namespace Fortran::semantics {
-class ArithmeticIfStmtContext {
-public:
- ArithmeticIfStmtContext(SemanticsContext &context)
- : messages_{context.messages()} {}
-
- bool operator==(const ArithmeticIfStmtContext &x) const { return this == &x; }
- bool operator!=(const ArithmeticIfStmtContext &x) const { return this != &x; }
-
- // Arithmetic IF statements have been removed from Fortran 2018.
- // The constraints and requirements here refer to the 2008 spec.
- void Check(const parser::ArithmeticIfStmt &arithmeticIfStmt) {
- // R853 Check for a scalar-numeric-expr
- // C849 that shall not be of type complex.
- auto &expr{std::get<parser::Expr>(arithmeticIfStmt.t)};
- if (expr.typedExpr->v.Rank() > 0) {
- messages_.Say(expr.source,
- "ARITHMETIC IF statement must have a scalar numeric expression"_err_en_US);
- } else if (ExprHasTypeCategory(
- *expr.typedExpr, common::TypeCategory::Complex)) {
- messages_.Say(expr.source,
- "ARITHMETIC IF statement must not have a COMPLEX expression"_err_en_US);
- } else if (!IsNumericExpr(*expr.typedExpr)) {
- messages_.Say(expr.source,
- "ARITHMETIC IF statement must have a numeric expression"_err_en_US);
- }
- // The labels have already been checked in resolve-labels.
- // TODO: Really? Check that they are really branch target
- // statements and in the same inclusive scope.
- }
-
-private:
- bool IsNumericExpr(const evaluate::GenericExprWrapper &expr) {
- auto dynamicType{expr.v.GetType()};
- return dynamicType.has_value() &&
- common::IsNumericTypeCategory(dynamicType->category);
- }
- parser::Messages &messages_;
- parser::CharBlock currentStatementSourcePosition_;
-};
-
-} // namespace Fortran::semantics
-
-namespace Fortran::semantics {
+bool IsNumericExpr(const evaluate::GenericExprWrapper &expr) {
+ auto dynamicType{expr.v.GetType()};
+ return dynamicType.has_value() &&
+ common::IsNumericTypeCategory(dynamicType->category);
+}
ArithmeticIfStmtChecker::ArithmeticIfStmtChecker(SemanticsContext &context)
- : context_{new ArithmeticIfStmtContext{context}} {}
+ : context_(context) {}
ArithmeticIfStmtChecker::~ArithmeticIfStmtChecker() = default;
-void ArithmeticIfStmtChecker::Leave(const parser::ArithmeticIfStmt &x) {
- context_.value().Check(x);
+void ArithmeticIfStmtChecker::Leave(
+ const parser::ArithmeticIfStmt &arithmeticIfStmt) {
+ // Arithmetic IF statements have been removed from Fortran 2018.
+ // The constraints and requirements here refer to the 2008 spec.
+ // R853 Check for a scalar-numeric-expr
+ // C849 that shall not be of type complex.
+ auto &expr{std::get<parser::Expr>(arithmeticIfStmt.t)};
+ if (expr.typedExpr->v.Rank() > 0) {
+ context_.messages().Say(expr.source,
+ "ARITHMETIC IF expression must be a scalar expression"_err_en_US);
+ } else if (ExprHasTypeCategory(
+ *expr.typedExpr, common::TypeCategory::Complex)) {
+ context_.messages().Say(expr.source,
+ "ARITHMETIC IF expression must not be a COMPLEX expression"_err_en_US);
+ } else if (!IsNumericExpr(*expr.typedExpr)) {
+ context_.messages().Say(expr.source,
+ "ARITHMETIC IF expression must be a numeric expression"_err_en_US);
+ }
+ // The labels have already been checked in resolve-labels.
+ // TODO: Really? Check that they are really branch target
+ // statements and in the same inclusive scope.
}
} // namespace Fortran::semantics
-
-template class Fortran::common::Indirection<
- Fortran::semantics::ArithmeticIfStmtContext>;
#define FORTRAN_SEMANTICS_CHECK_ARITHMETICIF_STMT_H_
#include "semantics.h"
-#include "../common/indirection.h"
namespace Fortran::parser {
struct ArithmeticIfStmt;
}
-namespace Fortran::semantics {
-class ArithmeticIfStmtContext;
-}
-extern template class Fortran::common::Indirection<
- Fortran::semantics::ArithmeticIfStmtContext>;
namespace Fortran::semantics {
class ArithmeticIfStmtChecker : public virtual BaseChecker {
void Leave(const parser::ArithmeticIfStmt &);
private:
- common::Indirection<ArithmeticIfStmtContext> context_;
+ SemanticsContext &context_;
};
}
#endif // FORTRAN_SEMANTICS_CHECK_ARITHMETICIF_STMT_H_
// See the License for the specific language governing permissions and
// limitations under the License.
-#include "attr.h"
#include "check-do-concurrent.h"
+#include "attr.h"
#include "scope.h"
#include "semantics.h"
#include "symbol.h"
parser::CharBlock currentStatementSourcePosition_;
};
-} // namespace Fortran::semantics
-
-namespace Fortran::semantics {
-
DoConcurrentChecker::DoConcurrentChecker(SemanticsContext &context)
: context_{new DoConcurrentContext{context}} {}
private:
common::Indirection<DoConcurrentContext> context_;
};
-
}
#endif // FORTRAN_SEMANTICS_CHECK_DO_CONCURRENT_H_
// See the License for the specific language governing permissions and
// limitations under the License.
-#include "attr.h"
#include "check-if-construct.h"
+#include "attr.h"
#include "scope.h"
#include "semantics.h"
#include "symbol.h"
namespace Fortran::semantics {
-class IfConstructContext {
-public:
- IfConstructContext(SemanticsContext &context)
- : messages_{context.messages()} {}
-
- bool operator==(const IfConstructContext &x) const { return this == &x; }
- bool operator!=(const IfConstructContext &x) const { return this != &x; }
-
- void Check(const parser::IfConstruct &ifConstruct) {
- auto &ifThenStmt{
- std::get<parser::Statement<parser::IfThenStmt>>(ifConstruct.t)
- .statement};
- auto &ifThenExpr{
- std::get<parser::ScalarLogicalExpr>(ifThenStmt.t).thing.thing.value()};
- CheckScalarLogicalExpr(ifThenExpr, messages_);
- for (const auto &elseIfBlock :
- std::get<std::list<parser::IfConstruct::ElseIfBlock>>(ifConstruct.t)) {
- auto &elseIfStmt{
- std::get<parser::Statement<parser::ElseIfStmt>>(elseIfBlock.t)
- .statement};
- auto &elseIfExpr{std::get<parser::ScalarLogicalExpr>(elseIfStmt.t)
- .thing.thing.value()};
- CheckScalarLogicalExpr(elseIfExpr, messages_);
- }
- // The (optional) ELSE does not have an expression to check; ignore it.
- }
-
-private:
- parser::Messages &messages_;
- parser::CharBlock currentStatementSourcePosition_;
-};
-
-} // namespace Fortran::semantics
-
-namespace Fortran::semantics {
-
IfConstructChecker::IfConstructChecker(SemanticsContext &context)
- : context_{new IfConstructContext{context}} {}
+ : context_{context} {}
IfConstructChecker::~IfConstructChecker() = default;
-void IfConstructChecker::Leave(const parser::IfConstruct &x) {
- context_.value().Check(x);
+void IfConstructChecker::Leave(const parser::IfConstruct &ifConstruct) {
+ auto &ifThenStmt{
+ std::get<parser::Statement<parser::IfThenStmt>>(ifConstruct.t).statement};
+ auto &ifThenExpr{
+ std::get<parser::ScalarLogicalExpr>(ifThenStmt.t).thing.thing.value()};
+ // R1135 - IF scalar logical expr
+ CheckScalarLogicalExpr(ifThenExpr, context_.messages());
+ for (const auto &elseIfBlock :
+ std::get<std::list<parser::IfConstruct::ElseIfBlock>>(ifConstruct.t)) {
+ auto &elseIfStmt{
+ std::get<parser::Statement<parser::ElseIfStmt>>(elseIfBlock.t)
+ .statement};
+ auto &elseIfExpr{
+ std::get<parser::ScalarLogicalExpr>(elseIfStmt.t).thing.thing.value()};
+ // R1136 - ELSE IF scalar logical expr
+ CheckScalarLogicalExpr(elseIfExpr, context_.messages());
+ }
+ // R1137 The (optional) ELSE does not have an expression to check; ignore it.
}
} // namespace Fortran::semantics
-
-template class Fortran::common::Indirection<
- Fortran::semantics::IfConstructContext>;
#define FORTRAN_SEMANTICS_CHECK_IF_CONSTRUCT_H_
#include "semantics.h"
-#include "../common/indirection.h"
namespace Fortran::parser {
struct IfConstruct;
}
-namespace Fortran::semantics {
-class IfConstructContext;
-}
-extern template class Fortran::common::Indirection<
- Fortran::semantics::IfConstructContext>;
namespace Fortran::semantics {
class IfConstructChecker : public virtual BaseChecker {
void Leave(const parser::IfConstruct &);
private:
- common::Indirection<IfConstructContext> context_;
+ SemanticsContext &context_;
};
}
#endif // FORTRAN_SEMANTICS_CHECK_IF_CONSTRUCT_H_
// See the License for the specific language governing permissions and
// limitations under the License.
-#include "attr.h"
#include "check-if-stmt.h"
+#include "attr.h"
#include "scope.h"
#include "semantics.h"
#include "symbol.h"
#include "../parser/parse-tree.h"
namespace Fortran::semantics {
-
-class IfStmtContext {
-public:
- IfStmtContext(SemanticsContext &context) : messages_{context.messages()} {}
-
- bool operator==(const IfStmtContext &x) const { return this == &x; }
- bool operator!=(const IfStmtContext &x) const { return this != &x; }
-
- // TODO: remove after fixing the issues that gives rise to the warning
- template<class T> void suppress_unused_variable_warning(const T &) {}
-
- void Check(const parser::IfStmt &ifStmt) {
- // R1139 Check for a scalar logical expression
- auto &expr{
- std::get<parser::ScalarLogicalExpr>(ifStmt.t).thing.thing.value()};
- CheckScalarLogicalExpr(expr, messages_);
- // C1143 Check that the action stmt is not an if stmt
- auto &actionStmt{std::get<parser::ActionStmt>(ifStmt.t)};
- if (auto *actionIfStmt{
- std::get_if<common::Indirection<parser::IfStmt>>(&actionStmt.u)}) {
- // TODO: get the source position from the action stmt
- suppress_unused_variable_warning(actionIfStmt);
- messages_.Say(expr.source,
- "IF statement is not allowed"_err_en_US);
- }
- }
-
-private:
- parser::Messages &messages_;
- parser::CharBlock currentStatementSourcePosition_;
-};
-
-} // namespace Fortran::semantics
-
-namespace Fortran::semantics {
-
-IfStmtChecker::IfStmtChecker(SemanticsContext &context)
- : context_{new IfStmtContext{context}} {}
+IfStmtChecker::IfStmtChecker(SemanticsContext &context) : context_{context} {}
IfStmtChecker::~IfStmtChecker() = default;
-void IfStmtChecker::Leave(const parser::IfStmt &x) {
- context_.value().Check(x);
+template<class T> void suppress_unused_variable_warning(const T &) {}
+
+void IfStmtChecker::Leave(const parser::IfStmt &ifStmt) {
+ // R1139 Check for a scalar logical expression
+ auto &expr{std::get<parser::ScalarLogicalExpr>(ifStmt.t).thing.thing.value()};
+ CheckScalarLogicalExpr(expr, context_.messages());
+ // C1143 Check that the action stmt is not an if stmt
+ auto &actionStmt{std::get<parser::ActionStmt>(ifStmt.t)};
+ if (auto *actionIfStmt{
+ std::get_if<common::Indirection<parser::IfStmt>>(&actionStmt.u)}) {
+ // TODO: get the source position from the action stmt
+ suppress_unused_variable_warning(actionIfStmt);
+ context_.messages().Say(
+ expr.source, "IF statement is not allowed in IF statement"_err_en_US);
+ }
}
} // namespace Fortran::semantics
-
-template class Fortran::common::Indirection<Fortran::semantics::IfStmtContext>;
#define FORTRAN_SEMANTICS_CHECK_IF_STMT_H_
#include "semantics.h"
-#include "../common/indirection.h"
namespace Fortran::parser {
struct IfStmt;
}
-namespace Fortran::semantics {
-class IfStmtContext;
-}
extern template class Fortran::common::Indirection<
- Fortran::semantics::IfStmtContext>;
+ Fortran::semantics::SemanticsContext>;
namespace Fortran::semantics {
class IfStmtChecker : public virtual BaseChecker {
void Leave(const parser::IfStmt &);
private:
- common::Indirection<IfStmtContext> context_;
+ SemanticsContext &context_;
};
}
#endif // FORTRAN_SEMANTICS_CHECK_IF_STMT_H_
// See the License for the specific language governing permissions and
// limitations under the License.
+#include "semantics.h"
#include "assignment.h"
#include "canonicalize-do.h"
#include "check-arithmeticif.h"
#include "resolve-names.h"
#include "rewrite-parse-tree.h"
#include "scope.h"
-#include "semantics.h"
#include "symbol.h"
#include "../common/default-kinds.h"
#include "../parser/parse-tree-visitor.h"
#include "scope.h"
#include "../evaluate/common.h"
#include "../evaluate/intrinsics.h"
-#include "../parser/message.h"
#include "../parser/features.h"
+#include "../parser/message.h"
#include <iosfwd>
#include <string>
#include <vector>
template<typename N> void Enter(const N &) {}
template<typename N> void Leave(const N &) {}
};
-
}
#endif
// See the License for the specific language governing permissions and
// limitations under the License.
-#include "scope.h"
#include "tools.h"
+#include "scope.h"
#include "../evaluate/variable.h"
#include <algorithm>
#include <set>
if (expr.typedExpr == nullptr) {
return;
}
- // TODO: Whence IsArray()?
if (expr.typedExpr->v.Rank() > 0) {
messages.Say(expr.source, "Expected a scalar LOGICAL expression"_err_en_US);
} else if (!ExprHasTypeCategory(
200 CONTINUE
300 CONTINUE
-!ERROR: ARITHMETIC IF statement must not have a COMPLEX expression
+!ERROR: ARITHMETIC IF expression must not be a COMPLEX expression
if ( Z ) 101, 201, 301
101 CONTINUE
201 CONTINUE
301 CONTINUE
-!ERROR: ARITHMETIC IF statement must have a numeric expression
+!ERROR: ARITHMETIC IF expression must be a numeric expression
if ( L ) 102, 202, 302
102 CONTINUE
202 CONTINUE
302 CONTINUE
-!ERROR: ARITHMETIC IF statement must have a scalar numeric expression
+!ERROR: ARITHMETIC IF expression must be a scalar expression
if ( B ) 103, 203, 303
103 CONTINUE
203 CONTINUE
! See the License for the specific language governing permissions and
! limitations under the License.
-! Simple check that if iconstructs are ok.
+! Simple check that if constructs are ok.
if (a < b) then
a = 1
! See the License for the specific language governing permissions and
! limitations under the License.
-!ERROR: IF statement is not allowed
+!ERROR: IF statement is not allowed in IF statement
IF (A > 0.0) IF (B < 0.0) A = LOG (A)
END