Skip to content

Commit 12b2fa2

Browse files
committed
handle base that is allocation
1 parent be2135b commit 12b2fa2

File tree

7 files changed

+96
-11
lines changed

7 files changed

+96
-11
lines changed

flang/docs/ImplementingASemanticCheck.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -775,7 +775,7 @@ to make sure that the names were clear. Here's what I ended up with:
775775

776776
```C++
777777
void DoChecker::Leave(const parser::Expr &parsedExpr) {
778-
ActualArgumentSet argSet{CollectActualArguments(GetExpr(parsedExpr))};
778+
ActualArgumentSet argSet{CollectActualArguments((parsedExpr))};
779779
for (const evaluate::ActualArgumentRef &argRef : argSet) {
780780
if (const SomeExpr * argExpr{argRef->UnwrapExpr()}) {
781781
if (const Symbol * var{evaluate::UnwrapWholeSymbolDataRef(*argExpr)}) {

flang/include/flang/Evaluate/variable.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -289,7 +289,7 @@ struct DataRef {
289289
const Symbol &GetLastSymbol() const;
290290
std::optional<Expr<SubscriptInteger>> LEN() const;
291291
llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const;
292-
292+
bool IsPathFrom(const DataRef &) const;
293293
std::variant<SymbolRef, Component, ArrayRef, CoarrayRef> u;
294294
};
295295

@@ -400,7 +400,7 @@ template <typename T> class Designator {
400400
const Symbol *GetLastSymbol() const;
401401
std::optional<Expr<SubscriptInteger>> LEN() const;
402402
llvm::raw_ostream &AsFortran(llvm::raw_ostream &o) const;
403-
403+
bool IsPathFrom(const Designator<T> &) const;
404404
Variant u;
405405
};
406406

flang/lib/Evaluate/variable.cpp

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -751,6 +751,65 @@ bool DescriptorInquiry::operator==(const DescriptorInquiry &that) const {
751751
return field_ == that.field_ && base_ == that.base_ &&
752752
dimension_ == that.dimension_;
753753
}
754+
#include <type_traits>
755+
#include <utility>
756+
template <typename T, typename = void> struct has_union : std::false_type {};
757+
template <typename T>
758+
struct has_union<T, std::void_t<decltype(T::u)>> : std::true_type {};
759+
template <typename T, typename = void> struct has_base : std::false_type {};
760+
template <typename T>
761+
struct has_base<T, std::void_t<decltype(std::declval<T>().base())>>
762+
: std::true_type {};
763+
template <typename T, typename = void>
764+
struct has_GetFirstSymbol : std::false_type {};
765+
template <typename T>
766+
struct has_GetFirstSymbol<T,
767+
std::void_t<decltype(std::declval<T>().GetFirstSymbol())>>
768+
: std::true_type {};
769+
770+
template <typename P, typename R>
771+
bool TestVariableIsPathFromRoot(const P &path, const R &root) {
772+
const SymbolRef *pathSym, *rootSym;
773+
if constexpr (has_union<P>::value) {
774+
pathSym = std::get_if<SymbolRef>(&path.u);
775+
}
776+
if constexpr (has_union<R>::value) {
777+
rootSym = std::get_if<SymbolRef>(&root.u);
778+
}
779+
if (pathSym) {
780+
return rootSym && AreSameSymbol(*rootSym, *pathSym);
781+
}
782+
if constexpr (has_GetFirstSymbol<P>::value) {
783+
if (rootSym) {
784+
return AreSameSymbol(path.GetFirstSymbol(), *rootSym);
785+
}
786+
}
787+
if constexpr (std::is_same_v<P, R>) {
788+
if (path == root) {
789+
return true;
790+
}
791+
}
792+
if constexpr (has_base<P>::value) {
793+
return TestVariableIsPathFromRoot(path.base(), root);
794+
}
795+
if constexpr (has_union<P>::value) {
796+
return common::visit(
797+
common::visitors{
798+
[&](const auto &x) { return TestVariableIsPathFromRoot(x, root); },
799+
},
800+
path.u);
801+
}
802+
return false;
803+
}
804+
805+
bool DataRef::IsPathFrom(const DataRef &that) const {
806+
return TestVariableIsPathFromRoot(*this, that);
807+
}
808+
809+
template <typename T>
810+
bool Designator<T>::IsPathFrom(const Designator<T> &that) const {
811+
return TestVariableIsPathFromRoot(*this, that);
812+
}
754813

755814
#ifdef _MSC_VER // disable bogus warning about missing definitions
756815
#pragma warning(disable : 4661)

flang/lib/Semantics/check-allocate.cpp

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -470,6 +470,29 @@ static bool HaveCompatibleLengths(
470470
}
471471
}
472472

473+
bool IsSameAllocation(const SomeExpr *root, const SomeExpr *path) {
474+
if (root) {
475+
if (std::optional<evaluate::DataRef> rootRef{ExtractDataRef(root)}) {
476+
if (path) {
477+
if (std::optional<evaluate::DataRef> pathRef{ExtractDataRef(path)}) {
478+
if (pathRef->IsPathFrom(*rootRef)) {
479+
return true;
480+
}
481+
} else {
482+
if (*root == *path) {
483+
return true;
484+
}
485+
}
486+
}
487+
} else {
488+
if (path && *root == *path) {
489+
return true;
490+
}
491+
}
492+
}
493+
return false;
494+
}
495+
473496
bool AllocationCheckerHelper::RunChecks(SemanticsContext &context) {
474497
if (!ultimate_) {
475498
CHECK(context.AnyFatalError());
@@ -700,12 +723,13 @@ bool AllocationCheckerHelper::RunChecks(SemanticsContext &context) {
700723
"Object in ALLOCATE must have DEVICE attribute when STREAM option is specified"_err_en_US);
701724
}
702725
}
726+
703727
if (const SomeExpr *allocObj{GetExpr(context, allocateObject_)}) {
704-
if (allocateInfo_.statVar && *allocObj == *allocateInfo_.statVar) {
728+
if (IsSameAllocation(allocObj, allocateInfo_.statVar)) {
705729
context.Say(allocateInfo_.statSource.value_or(name_.source),
706730
"STAT variable in ALLOCATE must not be the variable being allocated"_err_en_US);
707731
}
708-
if (allocateInfo_.msgVar && *allocObj == *allocateInfo_.msgVar) {
732+
if (IsSameAllocation(allocObj, allocateInfo_.msgVar)) {
709733
context.Say(allocateInfo_.msgSource.value_or(name_.source),
710734
"ERRMSG variable in ALLOCATE must not be the variable being allocated"_err_en_US);
711735
}

flang/lib/Semantics/check-allocate.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,6 @@ class AllocateChecker : public virtual BaseChecker {
2424
private:
2525
SemanticsContext &context_;
2626
};
27+
bool IsSameAllocation(const SomeExpr *root, const SomeExpr *path);
2728
} // namespace Fortran::semantics
2829
#endif // FORTRAN_SEMANTICS_CHECK_ALLOCATE_H_

flang/lib/Semantics/check-deallocate.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
//===----------------------------------------------------------------------===//
88

99
#include "check-deallocate.h"
10+
#include "check-allocate.h"
1011
#include "definable.h"
1112
#include "flang/Evaluate/type.h"
1213
#include "flang/Parser/message.h"
@@ -134,11 +135,11 @@ void DeallocateChecker::Leave(const parser::DeallocateStmt &deallocateStmt) {
134135
},
135136
allocateObject.u);
136137
if (const SomeExpr *allocObj{GetExpr(context_, allocateObject)}) {
137-
if (statVar && *allocObj == *statVar) {
138+
if (IsSameAllocation(allocObj, statVar)) {
138139
context_.Say(statSource.value_or(source),
139140
"STAT variable in DEALLOCATE must not be the variable being deallocated"_err_en_US);
140141
}
141-
if (msgVar && *allocObj == *msgVar) {
142+
if (IsSameAllocation(allocObj, msgVar)) {
142143
context_.Say(msgSource.value_or(source),
143144
"ERRMSG variable in DEALLOCATE must not be the variable being deallocated"_err_en_US);
144145
}

flang/test/Semantics/allocate14.f90

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,11 @@ program allocate14
4646
!ERROR: ERRMSG variable in DEALLOCATE must not be the variable being deallocated
4747
deallocate(tt(2)%msg, stat=tt(2)%i, errmsg=tt(2)%msg)
4848

49-
!FIXME: STAT variable in ALLOCATE must not be the variable being allocated
50-
!FIXME: ERRMSG variable in ALLOCATE must not be the variable being allocated
49+
!ERROR: STAT variable in ALLOCATE must not be the variable being allocated
50+
!ERROR: ERRMSG variable in ALLOCATE must not be the variable being allocated
5151
allocate(ts(10), stat=ts(1)%i, errmsg=ts(1)%msg)
52-
!FIXME: STAT variable in DEALLOCATE must not be the variable being deallocated
53-
!FIXME: ERRMSG variable in DEALLOCATE must not be the variable being deallocated
52+
!ERROR: STAT variable in DEALLOCATE must not be the variable being deallocated
53+
!ERROR: ERRMSG variable in DEALLOCATE must not be the variable being deallocated
5454
deallocate(ts, stat=ts(1)%i, errmsg=ts(1)%msg)
5555
end program
5656

0 commit comments

Comments
 (0)