Skip to content

Commit c116867

Browse files
committed
[flang] Add warning for FINAL pitfall
Fortran's FINAL feature is sensitive to object rank. When an object's rank excludes it from finalization, but the type has FINAL subroutines for other ranks, emit a warning. This should be especially helpful in the case of a scalar FINAL subroutine not being declared (IMPURE) ELEMENTAL. Differential revision: https://reviews.llvm.org/D90495
1 parent 0a512a5 commit c116867

File tree

4 files changed

+124
-0
lines changed

4 files changed

+124
-0
lines changed

flang/include/flang/Semantics/symbol.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,8 @@ class DerivedTypeDetails {
271271
}
272272
}
273273

274+
const Symbol *GetFinalForRank(int) const;
275+
274276
private:
275277
// These are (1) the names of the derived type parameters in the order
276278
// in which they appear on the type definition statement(s), and (2) the

flang/lib/Semantics/check-declarations.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ class CheckHelper {
8585
void CheckBlockData(const Scope &);
8686
void CheckGenericOps(const Scope &);
8787
bool CheckConflicting(const Symbol &, Attr, Attr);
88+
void WarnMissingFinal(const Symbol &);
8889
bool InPure() const {
8990
return innermostSymbol_ && IsPureProcedure(*innermostSymbol_);
9091
}
@@ -412,6 +413,7 @@ void CheckHelper::CheckObjectEntity(
412413
Check(details.shape());
413414
Check(details.coshape());
414415
CheckAssumedTypeEntity(symbol, details);
416+
WarnMissingFinal(symbol);
415417
if (!details.coshape().empty()) {
416418
bool isDeferredShape{details.coshape().IsDeferredShape()};
417419
if (IsAllocatable(symbol)) {
@@ -1242,6 +1244,38 @@ bool CheckHelper::CheckConflicting(const Symbol &symbol, Attr a1, Attr a2) {
12421244
}
12431245
}
12441246

1247+
void CheckHelper::WarnMissingFinal(const Symbol &symbol) {
1248+
const auto *object{symbol.detailsIf<ObjectEntityDetails>()};
1249+
if (!object || IsPointer(symbol)) {
1250+
return;
1251+
}
1252+
const DeclTypeSpec *type{object->type()};
1253+
const DerivedTypeSpec *derived{type ? type->AsDerived() : nullptr};
1254+
const Symbol *derivedSym{derived ? &derived->typeSymbol() : nullptr};
1255+
int rank{object->shape().Rank()};
1256+
const Symbol *initialDerivedSym{derivedSym};
1257+
while (const auto *derivedDetails{
1258+
derivedSym ? derivedSym->detailsIf<DerivedTypeDetails>() : nullptr}) {
1259+
if (!derivedDetails->finals().empty() &&
1260+
!derivedDetails->GetFinalForRank(rank)) {
1261+
if (auto *msg{derivedSym == initialDerivedSym
1262+
? messages_.Say(symbol.name(),
1263+
"'%s' of derived type '%s' does not have a FINAL subroutine for its rank (%d)"_en_US,
1264+
symbol.name(), derivedSym->name(), rank)
1265+
: messages_.Say(symbol.name(),
1266+
"'%s' of derived type '%s' extended from '%s' does not have a FINAL subroutine for its rank (%d)"_en_US,
1267+
symbol.name(), initialDerivedSym->name(),
1268+
derivedSym->name(), rank)}) {
1269+
msg->Attach(derivedSym->name(),
1270+
"Declaration of derived type '%s'"_en_US, derivedSym->name());
1271+
}
1272+
return;
1273+
}
1274+
derived = derivedSym->GetParentTypeSpec();
1275+
derivedSym = derived ? &derived->typeSymbol() : nullptr;
1276+
}
1277+
}
1278+
12451279
const Procedure *CheckHelper::Characterize(const Symbol &symbol) {
12461280
auto it{characterizeCache_.find(symbol)};
12471281
if (it == characterizeCache_.end()) {

flang/lib/Semantics/symbol.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -565,6 +565,25 @@ const Symbol *DerivedTypeDetails::GetParentComponent(const Scope &scope) const {
565565
return nullptr;
566566
}
567567

568+
const Symbol *DerivedTypeDetails::GetFinalForRank(int rank) const {
569+
for (const auto &pair : finals_) {
570+
const Symbol &symbol{*pair.second};
571+
if (const auto *details{symbol.detailsIf<SubprogramDetails>()}) {
572+
if (details->dummyArgs().size() == 1) {
573+
if (const Symbol * arg{details->dummyArgs().at(0)}) {
574+
if (const auto *object{arg->detailsIf<ObjectEntityDetails>()}) {
575+
if (rank == object->shape().Rank() || object->IsAssumedRank() ||
576+
symbol.attrs().test(Attr::ELEMENTAL)) {
577+
return &symbol;
578+
}
579+
}
580+
}
581+
}
582+
}
583+
}
584+
return nullptr;
585+
}
586+
568587
void TypeParamDetails::set_type(const DeclTypeSpec &type) {
569588
CHECK(!type_);
570589
type_ = &type;

flang/test/Semantics/final02.f90

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
!RUN: %f18 -fparse-only %s 2>&1 | FileCheck %s
2+
module m
3+
type :: t1
4+
integer :: n
5+
contains
6+
final :: t1f0, t1f1
7+
end type
8+
type :: t2
9+
integer :: n
10+
contains
11+
final :: t2fe
12+
end type
13+
type :: t3
14+
integer :: n
15+
contains
16+
final :: t3far
17+
end type
18+
type, extends(t1) :: t4
19+
end type
20+
type :: t5
21+
!CHECK-NOT: 'scalar' of derived type 't1'
22+
type(t1) :: scalar
23+
!CHECK-NOT: 'vector' of derived type 't1'
24+
type(t1) :: vector(2)
25+
!CHECK: 'matrix' of derived type 't1' does not have a FINAL subroutine for its rank (2)
26+
type(t1) :: matrix(2, 2)
27+
end type
28+
contains
29+
subroutine t1f0(x)
30+
type(t1) :: x
31+
end subroutine
32+
subroutine t1f1(x)
33+
type(t1) :: x(:)
34+
end subroutine
35+
impure elemental subroutine t2fe(x)
36+
type(t2) :: x
37+
end subroutine
38+
impure elemental subroutine t3far(x)
39+
type(t3) :: x(..)
40+
end subroutine
41+
end module
42+
43+
subroutine test ! *not* a main program, since they don't finalize locals
44+
use m
45+
!CHECK-NOT: 'scalar1' of derived type 't1'
46+
type(t1) :: scalar1
47+
!CHECK-NOT: 'vector1' of derived type 't1'
48+
type(t1) :: vector1(2)
49+
!CHECK: 'matrix1' of derived type 't1' does not have a FINAL subroutine for its rank (2)
50+
type(t1) :: matrix1(2,2)
51+
!CHECK-NOT: 'scalar2' of derived type 't2'
52+
type(t2) :: scalar2
53+
!CHECK-NOT: 'vector2' of derived type 't2'
54+
type(t2) :: vector2(2)
55+
!CHECK-NOT: 'matrix2' of derived type 't2'
56+
type(t2) :: matrix2(2,2)
57+
!CHECK-NOT: 'scalar3' of derived type 't3'
58+
type(t3) :: scalar3
59+
!CHECK-NOT: 'vector3' of derived type 't3'
60+
type(t3) :: vector3(2)
61+
!CHECK-NOT: 'matrix3' of derived type 't2'
62+
type(t3) :: matrix3(2,2)
63+
!CHECK-NOT: 'scalar4' of derived type 't4'
64+
type(t4) :: scalar4
65+
!CHECK-NOT: 'vector4' of derived type 't4'
66+
type(t4) :: vector4(2)
67+
!CHECK: 'matrix4' of derived type 't4' extended from 't1' does not have a FINAL subroutine for its rank (2)
68+
type(t4) :: matrix4(2,2)
69+
end

0 commit comments

Comments
 (0)