`parser::AllocateObject` and `parser::PointerObject` can be represented as typed expressions once analyzed. This simplifies the work for parse-tree consumers that work with typed expressions to deal with allocatable and pointer objects such as lowering. This change also makes it easier to add typedExpr in the future by automatically handling nodes that have this member when possible. Changes: - Add a `mutable TypedExpr typedExpr` field to `parser::PointerObject` and `parser::AllocateObject`. - Add a `parser::HasTypedExpr<T>` helper to better share code relating to typedExpr in the parse tree. - Add hooks in `semantics::ExprChecker` for AllocateObject and PointerObject nodes, and use ExprOrVariable on it to analyze and set the tyedExpr field during expression analysis. This required adding overloads for `AssumedTypeDummy`. - Update check-nullify.cpp and check-deallocate.cpp to not re-analyze the StructureComponent but to use the typedExpr field instead. - Update dump/unparse to use HasTypedExpr and use the typedExpr when there is one. Differential Revision: https://reviews.llvm.org/D98256
74 lines
2.9 KiB
C++
74 lines
2.9 KiB
C++
//===-- lib/Semantics/check-deallocate.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-deallocate.h"
|
|
#include "flang/Parser/message.h"
|
|
#include "flang/Parser/parse-tree.h"
|
|
#include "flang/Semantics/expression.h"
|
|
#include "flang/Semantics/tools.h"
|
|
|
|
namespace Fortran::semantics {
|
|
|
|
void DeallocateChecker::Leave(const parser::DeallocateStmt &deallocateStmt) {
|
|
for (const parser::AllocateObject &allocateObject :
|
|
std::get<std::list<parser::AllocateObject>>(deallocateStmt.t)) {
|
|
std::visit(
|
|
common::visitors{
|
|
[&](const parser::Name &name) {
|
|
auto const *symbol{name.symbol};
|
|
if (context_.HasError(symbol)) {
|
|
// already reported an error
|
|
} else if (!IsVariableName(*symbol)) {
|
|
context_.Say(name.source,
|
|
"name in DEALLOCATE statement must be a variable name"_err_en_US);
|
|
} else if (!IsAllocatableOrPointer(*symbol)) { // C932
|
|
context_.Say(name.source,
|
|
"name in DEALLOCATE statement must have the ALLOCATABLE or POINTER attribute"_err_en_US);
|
|
} else {
|
|
context_.CheckIndexVarRedefine(name);
|
|
}
|
|
},
|
|
[&](const parser::StructureComponent &structureComponent) {
|
|
// Only perform structureComponent checks it was successfully
|
|
// analyzed in expression analysis.
|
|
if (GetExpr(allocateObject)) {
|
|
if (!IsAllocatableOrPointer(
|
|
*structureComponent.component.symbol)) { // C932
|
|
context_.Say(structureComponent.component.source,
|
|
"component in DEALLOCATE statement must have the ALLOCATABLE or POINTER attribute"_err_en_US);
|
|
}
|
|
}
|
|
},
|
|
},
|
|
allocateObject.u);
|
|
}
|
|
bool gotStat{false}, gotMsg{false};
|
|
for (const parser::StatOrErrmsg &deallocOpt :
|
|
std::get<std::list<parser::StatOrErrmsg>>(deallocateStmt.t)) {
|
|
std::visit(
|
|
common::visitors{
|
|
[&](const parser::StatVariable &) {
|
|
if (gotStat) {
|
|
context_.Say(
|
|
"STAT may not be duplicated in a DEALLOCATE statement"_err_en_US);
|
|
}
|
|
gotStat = true;
|
|
},
|
|
[&](const parser::MsgVariable &) {
|
|
if (gotMsg) {
|
|
context_.Say(
|
|
"ERRMSG may not be duplicated in a DEALLOCATE statement"_err_en_US);
|
|
}
|
|
gotMsg = true;
|
|
},
|
|
},
|
|
deallocOpt.u);
|
|
}
|
|
}
|
|
} // namespace Fortran::semantics
|