diff --git a/flang/lib/Semantics/check-data.h b/flang/lib/Semantics/check-data.h --- a/flang/lib/Semantics/check-data.h +++ b/flang/lib/Semantics/check-data.h @@ -20,9 +20,14 @@ DataChecker(SemanticsContext &context) : context_{context} {} void Leave(const parser::DataStmtRepeat &); void Leave(const parser::DataStmtConstant &); + void Leave(const parser::DataStmtObject &); + void Leave(const parser::DataImpliedDo &); private: SemanticsContext &context_; + template void CheckIfConstantSubscript(const T &); + void CheckSubscript(const parser::SectionSubscript &); + bool CheckAllSubscriptsInDataRef(const parser::DataRef &, parser::CharBlock); }; } // namespace Fortran::semantics #endif // FORTRAN_SEMANTICS_CHECK_DATA_H_ diff --git a/flang/lib/Semantics/check-data.cpp b/flang/lib/Semantics/check-data.cpp --- a/flang/lib/Semantics/check-data.cpp +++ b/flang/lib/Semantics/check-data.cpp @@ -10,25 +10,116 @@ namespace Fortran::semantics { +template void DataChecker::CheckIfConstantSubscript(const T &x) { + evaluate::ExpressionAnalyzer exprAnalyzer{context_}; + if (MaybeExpr checked{exprAnalyzer.Analyze(x)}) { + if (!evaluate::IsConstantExpr(*checked)) { // C875,C881 + context_.Say(parser::FindSourceLocation(x), + "Data object must have constant bounds"_err_en_US); + } + } +} + +void DataChecker::CheckSubscript(const parser::SectionSubscript &subscript) { + std::visit( + common::visitors{ + [&](const parser::SubscriptTriplet &triplet) { + CheckIfConstantSubscript(std::get<0>(triplet.t)); + CheckIfConstantSubscript(std::get<1>(triplet.t)); + CheckIfConstantSubscript(std::get<2>(triplet.t)); + }, + [&](const parser::IntExpr &intExpr) { + CheckIfConstantSubscript(intExpr); + }, + }, + subscript.u); +} + +// Returns false if DataRef has no subscript +bool DataChecker::CheckAllSubscriptsInDataRef(const parser::DataRef &dataRef, + parser::CharBlock source) { + return std::visit( + common::visitors{ + [&](const parser::Name &) { return false; }, + [&](const common::Indirection + &structureComp) { + return CheckAllSubscriptsInDataRef(structureComp.value().base, + source); + }, + [&](const common::Indirection &arrayElem) { + for (auto &subscript : arrayElem.value().subscripts) { + CheckSubscript(subscript); + } + CheckAllSubscriptsInDataRef(arrayElem.value().base, source); + return true; + }, + [&](const common::Indirection + &coindexedObj) { // C874 + context_.Say( + source, + "Data object must not be a coindexed variable"_err_en_US); + CheckAllSubscriptsInDataRef(coindexedObj.value().base, source); + return true; + }, + }, + dataRef.u); +} + void DataChecker::Leave(const parser::DataStmtConstant &dataConst) { if (auto *structure{ std::get_if(&dataConst.u)}) { for (const auto &component : - std::get>(structure->t)) { + std::get>(structure->t)) { const parser::Expr &parsedExpr{ std::get(component.t).v.value()}; if (const auto *expr{GetExpr(parsedExpr)}) { if (!evaluate::IsConstantExpr(*expr)) { // C884 - context_.Say(parsedExpr.source, + 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 +// TODO: C876, C877, C879 +void DataChecker::Leave(const parser::DataImpliedDo &dataImpliedDo) { + for (const auto &object : + std::get>(dataImpliedDo.t)) { + if (const auto *designator{parser::Unwrap(object)}) { + if (auto *dataRef{std::get_if(&designator->u)}) { + evaluate::ExpressionAnalyzer exprAnalyzer{context_}; + if (MaybeExpr checked{exprAnalyzer.Analyze(*dataRef)}) { + if (evaluate::IsConstantExpr(*checked)) { // C878 + context_.Say(designator->source, + "Data implied do object must be a variable"_err_en_US); + } + } + if (!CheckAllSubscriptsInDataRef(*dataRef, + designator->source)) { // C880 + context_.Say(designator->source, + "Data implied do object must be subscripted"_err_en_US); + } + } + } + } +} + +void DataChecker::Leave(const parser::DataStmtObject &dataObject) { + if (std::get_if>(&dataObject.u)) { + if (const auto *designator{ + parser::Unwrap(dataObject)}) { + if (auto *dataRef{std::get_if(&designator->u)}) { + CheckAllSubscriptsInDataRef(*dataRef, designator->source); + } + } else { // C875 + context_.Say( + parser::FindSourceLocation(dataObject), + "Data object variable must not be a function reference"_err_en_US); + } + } +} void DataChecker::Leave(const parser::DataStmtRepeat &dataRepeat) { if (const auto *designator{parser::Unwrap(dataRepeat)}) { @@ -39,7 +130,8 @@ evaluate::Fold(context_.foldingContext(), std::move(checked))}; if (auto i64{ToInt64(expr)}) { if (*i64 < 0) { // C882 - context_.Say(designator->source, + context_.Say( + designator->source, "Repeat count for data value must not be negative"_err_en_US); } } diff --git a/flang/test/Semantics/data03.f90 b/flang/test/Semantics/data03.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Semantics/data03.f90 @@ -0,0 +1,83 @@ +! RUN: %B/test/Semantics/test_errors.sh %s %flang %t +!Testing data constraints : C874 - C875, C878 - C881 +module m + contains + function f(i) + integer ::i + integer ::result + result = i *1024 + end + subroutine CheckObject + type specialNumbers + integer one + integer numbers(5) + end type + type large + integer elt(10) + integer val + type(specialNumbers) nums + type(specialNumbers) numsArray(5) + end type + type(specialNumbers), parameter ::newNums = & + specialNumbers(1, (/ 1, 2, 3, 4, 5 /)) + type(specialNumbers), parameter ::newNumsArray(2) = & + (/ SpecialNumbers(1, (/ 1, 2, 3, 4, 5 /)), & + SpecialNumbers(1, (/ 1, 2, 3,4, 5 /)) /) + type(specialNumbers) nums + type(large) largeArray(5) + type(large) largeNumber + real :: a[*] + real :: b(5) + integer :: x + real, parameter:: c(5) = (/ 1, 2, 3, 4, 5 /) + integer :: d(10, 10) + character :: name(12) + integer :: ind = 2 + !C874 + !ERROR: Data object must not be a coindexed variable + DATA a[1] / 1 / + !C874 + !ERROR: Data object must not be a coindexed variable + DATA(a[i], i = 1, 5) / 5 * 1 / + !C875 + !ERROR: Data object variable must not be a function reference + DATA f(1) / 1 / + !C875 + !ERROR: Data object must have constant bounds + DATA b(ind) / 1 / + !C875 + !ERROR: Data object must have constant bounds + DATA name( : ind) / 'Ancd' / + !C875 + !ERROR: Data object must have constant bounds + DATA name(ind:) / 'Ancd' / + !C878 + !ERROR: Data implied do object must be a variable + DATA(c(i), i = 1, 5) / 5 * 1 / + !C878 + !ERROR: Data implied do object must be a variable + DATA(newNumsArray(i), i = 1, 2) & + / specialNumbers(1, 2 * (/ 1, 2, 3, 4, 5 /)) / + !C880 + !ERROR: Data implied do object must be subscripted + DATA(nums % one, i = 1, 5) / 5 * 1 / + !C880 + !OK: Correct use + DATA(largeArray(j) % nums % one, j = 1, 10) / 10 * 1 / + !C880 + !OK: Correct use + DATA(largeNumber % numsArray(j) % one, j = 1, 10) / 10 * 1 / + !C881 + !ERROR: Data object must have constant bounds + DATA(b(x), i = 1, 5) / 5 * 1 / + !C881 + !OK: Correct use + DATA(nums % numbers(i), i = 1, 5) / 5 * 1 / + !C881 + !OK: Correct use + DATA((d(i, j), i = 1, 10), j = 1, 10) / 100 * 1 / + !C881 + !OK: Correct use + DATA(d(i, 1), i = 1, 10) / 10 * 1 / + end + end