Skip to content

Commit b8513e4

Browse files
authored
[flang] Better handling of weird pointer assignment case (#120628)
F'2023 C1017 permits the assignment of an unlimited polymorphic data target to a monomorphic LHS pointer when the LHS pointer has a sequence derived type (BIND(C) or SEQUENCE attribute). We allowed for this in pointer assignments that don't have a function reference as their RHS. Extend this support to function references, and also ensure that rank compatibility is still checked.
1 parent 7453d76 commit b8513e4

File tree

2 files changed

+81
-20
lines changed

2 files changed

+81
-20
lines changed

flang/lib/Semantics/pointer-assignment.cpp

Lines changed: 35 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ class PointerAssignmentChecker {
7676
const Procedure * = nullptr,
7777
const evaluate::SpecificIntrinsic *specific = nullptr);
7878
bool LhsOkForUnlimitedPoly() const;
79+
std::optional<MessageFormattedText> CheckRanks(const TypeAndShape &rhs) const;
7980
template <typename... A> parser::Message *Say(A &&...);
8081
template <typename FeatureOrUsageWarning, typename... A>
8182
parser::Message *Warn(FeatureOrUsageWarning, A &&...);
@@ -278,10 +279,19 @@ bool PointerAssignmentChecker::Check(const evaluate::FunctionRef<T> &f) {
278279
} else if (lhsType_) {
279280
const auto *frTypeAndShape{funcResult->GetTypeAndShape()};
280281
CHECK(frTypeAndShape);
281-
if (!lhsType_->IsCompatibleWith(foldingContext_.messages(), *frTypeAndShape,
282-
"pointer", "function result",
283-
/*omitShapeConformanceCheck=*/isBoundsRemapping_ || isAssumedRank_,
284-
evaluate::CheckConformanceFlags::BothDeferredShape)) {
282+
if (frTypeAndShape->type().IsUnlimitedPolymorphic() &&
283+
LhsOkForUnlimitedPoly()) {
284+
// Special case exception to type checking (F'2023 C1017);
285+
// still check rank compatibility.
286+
if (auto msg{CheckRanks(*frTypeAndShape)}) {
287+
Say(*msg);
288+
return false;
289+
}
290+
} else if (!lhsType_->IsCompatibleWith(foldingContext_.messages(),
291+
*frTypeAndShape, "pointer", "function result",
292+
/*omitShapeConformanceCheck=*/isBoundsRemapping_ ||
293+
isAssumedRank_,
294+
evaluate::CheckConformanceFlags::BothDeferredShape)) {
285295
return false; // IsCompatibleWith() emitted message
286296
}
287297
}
@@ -324,27 +334,17 @@ bool PointerAssignmentChecker::Check(const evaluate::Designator<T> &d) {
324334
msg = "Pointer must be VOLATILE when target is a"
325335
" VOLATILE coarray"_err_en_US;
326336
}
337+
} else if (auto m{CheckRanks(*rhsType)}) {
338+
msg = std::move(*m);
327339
} else if (rhsType->type().IsUnlimitedPolymorphic()) {
328340
if (!LhsOkForUnlimitedPoly()) {
329341
msg = "Pointer type must be unlimited polymorphic or non-extensible"
330342
" derived type when target is unlimited polymorphic"_err_en_US;
331343
}
332-
} else {
333-
if (!lhsType_->type().IsTkLenCompatibleWith(rhsType->type())) {
334-
msg = MessageFormattedText{
335-
"Target type %s is not compatible with pointer type %s"_err_en_US,
336-
rhsType->type().AsFortran(), lhsType_->type().AsFortran()};
337-
338-
} else if (!isBoundsRemapping_ &&
339-
!lhsType_->attrs().test(TypeAndShape::Attr::AssumedRank)) {
340-
int lhsRank{lhsType_->Rank()};
341-
int rhsRank{rhsType->Rank()};
342-
if (lhsRank != rhsRank) {
343-
msg = MessageFormattedText{
344-
"Pointer has rank %d but target has rank %d"_err_en_US, lhsRank,
345-
rhsRank};
346-
}
347-
}
344+
} else if (!lhsType_->type().IsTkLenCompatibleWith(rhsType->type())) {
345+
msg = MessageFormattedText{
346+
"Target type %s is not compatible with pointer type %s"_err_en_US,
347+
rhsType->type().AsFortran(), lhsType_->type().AsFortran()};
348348
}
349349
}
350350
if (msg) {
@@ -434,6 +434,21 @@ bool PointerAssignmentChecker::LhsOkForUnlimitedPoly() const {
434434
}
435435
}
436436

437+
std::optional<MessageFormattedText> PointerAssignmentChecker::CheckRanks(
438+
const TypeAndShape &rhs) const {
439+
if (!isBoundsRemapping_ &&
440+
!lhsType_->attrs().test(TypeAndShape::Attr::AssumedRank)) {
441+
int lhsRank{lhsType_->Rank()};
442+
int rhsRank{rhs.Rank()};
443+
if (lhsRank != rhsRank) {
444+
return MessageFormattedText{
445+
"Pointer has rank %d but target has rank %d"_err_en_US, lhsRank,
446+
rhsRank};
447+
}
448+
}
449+
return std::nullopt;
450+
}
451+
437452
template <typename... A>
438453
parser::Message *PointerAssignmentChecker::Say(A &&...x) {
439454
auto *msg{foldingContext_.messages().Say(std::forward<A>(x)...)};

flang/test/Semantics/assign16.f90

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
! RUN: %python %S/test_errors.py %s %flang_fc1
2+
! The RHS of a pointer assignment can be unlimited polymorphic
3+
! if the LHS is a sequence type.
4+
program main
5+
type nonSeqType
6+
integer j
7+
end type
8+
type seqType
9+
sequence
10+
integer j
11+
end type
12+
type(nonSeqType), target :: xNonSeq = nonSeqType(1)
13+
type(nonSeqType), pointer :: pNonSeq
14+
type(seqType), target :: xSeq = seqType(1), aSeq(1)
15+
type(seqType), pointer :: pSeq, paSeq(:)
16+
!ERROR: function result type 'CLASS(*)' is not compatible with pointer type 'nonseqtype'
17+
pNonSeq => polyPtr(xNonSeq)
18+
pSeq => polyPtr(xSeq) ! ok
19+
!ERROR: Pointer has rank 1 but target has rank 0
20+
paSeq => polyPtr(xSeq)
21+
!ERROR: Pointer has rank 0 but target has rank 1
22+
pSeq => polyPtrArr(aSeq)
23+
contains
24+
function polyPtr(target)
25+
class(*), intent(in), target :: target
26+
class(*), pointer :: polyPtr
27+
polyPtr => target
28+
end
29+
function polyPtrArr(target)
30+
class(*), intent(in), target :: target(:)
31+
class(*), pointer :: polyPtrArr(:)
32+
polyPtrArr => target
33+
end
34+
function err1(target)
35+
class(*), intent(in), target :: target(:)
36+
class(*), pointer :: err1
37+
!ERROR: Pointer has rank 0 but target has rank 1
38+
err1 => target
39+
end
40+
function err2(target)
41+
class(*), intent(in), target :: target
42+
class(*), pointer :: err2(:)
43+
!ERROR: Pointer has rank 1 but target has rank 0
44+
err2 => target
45+
end
46+
end

0 commit comments

Comments
 (0)