auto result{Analyze(x.thing)};
if (result) {
*result = Fold(std::move(*result));
- if (!IsConstantExpr(*result)) {
+ if (!IsConstantExpr(*result)) { //C886,C887
SayAt(x, "Must be a constant value"_err_en_US);
ResetExpr(x);
return std::nullopt;
check-arithmeticif.cpp
check-call.cpp
check-coarray.cpp
+ check-data.cpp
check-deallocate.cpp
check-declarations.cpp
check-do-forall.cpp
--- /dev/null
+//===-- lib/semantics/check-data.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-data.h"
+
+namespace Fortran::semantics {
+
+void DataChecker::Leave(const parser::DataStmtConstant &dataConst) {
+ if (auto *structure{
+ std::get_if<parser::StructureConstructor>(&dataConst.u)}) {
+ for (const auto &component :
+ std::get<std::list<parser::ComponentSpec>>(structure->t)) {
+ const parser::Expr &parsedExpr{
+ std::get<parser::ComponentDataSource>(component.t).v.value()};
+ if (const auto *expr{GetExpr(parsedExpr)}) {
+ if (!evaluate::IsConstantExpr(*expr)) { // C884
+ context_.Say(parsedExpr.source,
+ "Structure constructor in data value must be a constant expression"_err_en_US);
+ }
+ }
+ }
+ }
+ // TODO: C886 and C887 for data-stmt-constant
+}
+
+// TODO: C874-C881
+
+void DataChecker::Leave(const parser::DataStmtRepeat &dataRepeat) {
+ if (const auto *designator{parser::Unwrap<parser::Designator>(dataRepeat)}) {
+ if (auto *dataRef{std::get_if<parser::DataRef>(&designator->u)}) {
+ evaluate::ExpressionAnalyzer exprAnalyzer{context_};
+ if (MaybeExpr checked{exprAnalyzer.Analyze(*dataRef)}) {
+ auto expr{
+ evaluate::Fold(context_.foldingContext(), std::move(checked))};
+ if (auto i64{ToInt64(expr)}) {
+ if (*i64 < 0) { // C882
+ context_.Say(designator->source,
+ "Repeat count for data value must not be negative"_err_en_US);
+ }
+ }
+ }
+ }
+ }
+}
+}
--- /dev/null
+//===-------lib/semantics/check-data.h ------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef FORTRAN_SEMANTICS_CHECK_DATA_H_
+#define FORTRAN_SEMANTICS_CHECK_DATA_H_
+
+#include "flang/parser/parse-tree.h"
+#include "flang/parser/tools.h"
+#include "flang/semantics/semantics.h"
+#include "flang/semantics/tools.h"
+
+namespace Fortran::semantics {
+class DataChecker : public virtual BaseChecker {
+public:
+ DataChecker(SemanticsContext &context) : context_{context} {}
+ void Leave(const parser::DataStmtRepeat &);
+ void Leave(const parser::DataStmtConstant &);
+
+private:
+ SemanticsContext &context_;
+};
+}
+#endif // FORTRAN_SEMANTICS_CHECK_DATA_H_
const MaybeExpr &result, TypeCategory category, bool defaultKind) {
if (result) {
if (auto type{result->GetType()}) {
- if (type->category() != category) {
+ if (type->category() != category) { // C885
Say(at, "Must have %s type, but is %s"_err_en_US,
ToUpperCase(EnumToString(category)),
ToUpperCase(type->AsFortran()));
if (ConvertToObjectEntity(symbol)) {
Initialization(name, *init, false);
}
- } else if (attrs.test(Attr::PARAMETER)) {
+ } else if (attrs.test(Attr::PARAMETER)) { // C882, C883
Say(name, "Missing initialization for parameter '%s'"_err_en_US);
}
}
DerivedTypeDetails details;
details.set_isForwardReferenced();
symbol->set_details(std::move(details));
- } else {
+ } else { // C883
Say(name, "Derived type '%s' not found"_err_en_US);
return std::nullopt;
}
#include "check-allocate.h"
#include "check-arithmeticif.h"
#include "check-coarray.h"
+#include "check-data.h"
#include "check-deallocate.h"
#include "check-declarations.h"
#include "check-do-forall.h"
};
using StatementSemanticsPass1 = ExprChecker;
-using StatementSemanticsPass2 = SemanticsVisitor< //
+using StatementSemanticsPass2 = SemanticsVisitor<
AllocateChecker, ArithmeticIfStmtChecker, AssignmentChecker, CoarrayChecker,
- DeallocateChecker, DoForallChecker, IfStmtChecker, IoChecker,
+ DataChecker, DeallocateChecker, DoForallChecker, IfStmtChecker, IoChecker,
NullifyChecker, OmpStructureChecker, PurityChecker, ReturnStmtChecker,
StopChecker>;
critical02.f90
critical03.f90
block-data01.f90
+ data01.f90
)
# These test files have expected symbols in the source
--- /dev/null
+!Test for checking data constraints, C882-C887
+module m1
+ type person
+ integer :: age
+ character(len=25) :: name
+ end type
+ integer, parameter::digits(5) = ( /-11,-22,-33,44,55/ )
+ integer ::notConstDigits(5) = ( /-11,-22,-33,44,55/ )
+ real, parameter::numbers(5) = ( /-11.11,-22.22,-33.33,44.44,55.55/ )
+ integer, parameter :: repeat = -1
+ integer :: myAge = 2
+ type(person) myName
+end
+
+subroutine CheckRepeat
+ use m1
+ !C882
+ !ERROR: Missing initialization for parameter 'uninitialized'
+ integer, parameter :: uninitialized
+ !C882
+ !ERROR: Repeat count for data value must not be negative
+ DATA myName%age / repeat * 35 /
+ !C882
+ !ERROR: Repeat count for data value must not be negative
+ DATA myName%age / digits(1) * 35 /
+ !C882
+ !ERROR: Must be a constant value
+ DATA myName%age / repet * 35 /
+ !C885
+ !ERROR: Must have INTEGER type, but is REAL(4)
+ DATA myName%age / numbers(1) * 35 /
+ !C886
+ !ERROR: Must be a constant value
+ DATA myName%age / notConstDigits(1) * 35 /
+ !C887
+ !ERROR: Must be a constant value
+ DATA myName%age / digits(myAge) * 35 /
+end
+
+subroutine CheckValue
+ use m1
+ !C883
+ !ERROR: Derived type 'persn' not found
+ DATA myname / persn(2, 'Abcd Efgh') /
+ !C884
+ !ERROR: Structure constructor in data value must be a constant expression
+ DATA myname / person(myAge, 'Abcd Ijkl') /
+end