Skip to content

Commit 29025a0

Browse files
authored
[flang] Catch more semantic errors with coarrays (#125536)
Detect and report a bunch of uncaught semantic errors with coarray declarations. Add more tests, and clean up bad usage in existing tests.
1 parent a21089a commit 29025a0

26 files changed

+207
-76
lines changed

flang/include/flang/Semantics/tools.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -631,6 +631,8 @@ using PotentialAndPointerComponentIterator =
631631
// dereferenced.
632632
PotentialComponentIterator::const_iterator FindEventOrLockPotentialComponent(
633633
const DerivedTypeSpec &, bool ignoreCoarrays = false);
634+
PotentialComponentIterator::const_iterator FindCoarrayPotentialComponent(
635+
const DerivedTypeSpec &);
634636
UltimateComponentIterator::const_iterator FindCoarrayUltimateComponent(
635637
const DerivedTypeSpec &);
636638
UltimateComponentIterator::const_iterator FindPointerUltimateComponent(

flang/lib/Evaluate/tools.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1812,7 +1812,11 @@ bool IsSaved(const Symbol &original) {
18121812
} else if (scopeKind == Scope::Kind::DerivedType) {
18131813
return false; // this is a component
18141814
} else if (symbol.attrs().test(Attr::SAVE)) {
1815-
return true; // explicit SAVE attribute
1815+
// explicit or implied SAVE attribute
1816+
// N.B.: semantics sets implied SAVE for main program
1817+
// local variables whose derived types have coarray
1818+
// potential subobject components.
1819+
return true;
18161820
} else if (IsDummy(symbol) || IsFunctionResult(symbol) ||
18171821
IsAutomatic(symbol) || IsNamedConstant(symbol)) {
18181822
return false;

flang/lib/Semantics/check-declarations.cpp

Lines changed: 80 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -683,20 +683,10 @@ void CheckHelper::CheckObjectEntity(
683683
const DeclTypeSpec *type{details.type()};
684684
const DerivedTypeSpec *derived{type ? type->AsDerived() : nullptr};
685685
bool isComponent{symbol.owner().IsDerivedType()};
686-
if (details.coshape().empty()) { // not a coarray
687-
if (!isComponent && !IsPointer(symbol) && derived) {
688-
if (IsEventTypeOrLockType(derived)) {
689-
messages_.Say(
690-
"Variable '%s' with EVENT_TYPE or LOCK_TYPE must be a coarray"_err_en_US,
691-
symbol.name());
692-
} else if (auto component{FindEventOrLockPotentialComponent(
693-
*derived, /*ignoreCoarrays=*/true)}) {
694-
messages_.Say(
695-
"Variable '%s' with EVENT_TYPE or LOCK_TYPE potential component '%s' must be a coarray"_err_en_US,
696-
symbol.name(), component.BuildResultDesignatorName());
697-
}
698-
}
699-
} else { // it's a coarray
686+
const Symbol *commonBlock{FindCommonBlockContaining(symbol)};
687+
bool isLocalVariable{!commonBlock && !isComponent && !details.isDummy() &&
688+
symbol.owner().kind() != Scope::Kind::OtherConstruct};
689+
if (int corank{evaluate::GetCorank(symbol)}; corank > 0) { // it's a coarray
700690
bool isDeferredCoshape{details.coshape().CanBeDeferredShape()};
701691
if (IsAllocatable(symbol)) {
702692
if (!isDeferredCoshape) { // C827
@@ -726,6 +716,46 @@ void CheckHelper::CheckObjectEntity(
726716
messages_.Say("Coarray '%s' may not be an assumed-rank array"_err_en_US,
727717
symbol.name());
728718
}
719+
if (IsNamedConstant(symbol)) {
720+
messages_.Say(
721+
"Coarray '%s' may not be a named constant"_err_en_US, symbol.name());
722+
}
723+
if (IsFunctionResult(symbol)) {
724+
messages_.Say("Function result may not be a coarray"_err_en_US);
725+
} else if (commonBlock) {
726+
messages_.Say("Coarray '%s' may not be in COMMON block '/%s/'"_err_en_US,
727+
symbol.name(), commonBlock->name());
728+
} else if (isLocalVariable && !IsAllocatableOrPointer(symbol) &&
729+
!IsSaved(symbol)) {
730+
messages_.Say("Local coarray must have the SAVE attribute"_err_en_US);
731+
}
732+
for (int j{0}; j < corank; ++j) {
733+
if (auto lcbv{evaluate::ToInt64(evaluate::Fold(
734+
context().foldingContext(), evaluate::GetLCOBOUND(symbol, j)))}) {
735+
if (auto ucbv{
736+
evaluate::ToInt64(evaluate::Fold(context().foldingContext(),
737+
evaluate::GetUCOBOUND(symbol, j)))}) {
738+
if (ucbv < lcbv) {
739+
messages_.Say(
740+
"Cobounds %jd:%jd of codimension %d produce an empty coarray"_err_en_US,
741+
std::intmax_t{*lcbv}, std::intmax_t{*ucbv}, j + 1);
742+
}
743+
}
744+
}
745+
}
746+
} else { // not a coarray
747+
if (!isComponent && !IsPointer(symbol) && derived) {
748+
if (IsEventTypeOrLockType(derived)) {
749+
messages_.Say(
750+
"Variable '%s' with EVENT_TYPE or LOCK_TYPE must be a coarray"_err_en_US,
751+
symbol.name());
752+
} else if (auto component{FindEventOrLockPotentialComponent(
753+
*derived, /*ignoreCoarrays=*/true)}) {
754+
messages_.Say(
755+
"Variable '%s' with EVENT_TYPE or LOCK_TYPE potential component '%s' must be a coarray"_err_en_US,
756+
symbol.name(), component.BuildResultDesignatorName());
757+
}
758+
}
729759
}
730760
if (details.isDummy()) {
731761
if (IsIntentOut(symbol)) {
@@ -926,6 +956,42 @@ void CheckHelper::CheckObjectEntity(
926956
symbol.name());
927957
}
928958

959+
if (derived) {
960+
bool isUnsavedLocal{
961+
isLocalVariable && !IsAllocatable(symbol) && !IsSaved(symbol)};
962+
if (IsFunctionResult(symbol) || IsPointer(symbol) ||
963+
evaluate::IsCoarray(symbol) || isUnsavedLocal) {
964+
if (auto badPotential{FindCoarrayPotentialComponent(*derived)}) {
965+
if (IsFunctionResult(symbol)) { // F'2023 C825
966+
SayWithDeclaration(*badPotential,
967+
"Function result '%s' may not have a coarray potential component '%s'"_err_en_US,
968+
symbol.name(), badPotential.BuildResultDesignatorName());
969+
} else if (IsPointer(symbol)) { // F'2023 C825
970+
SayWithDeclaration(*badPotential,
971+
"Pointer '%s' may not have a coarray potential component '%s'"_err_en_US,
972+
symbol.name(), badPotential.BuildResultDesignatorName());
973+
} else if (evaluate::IsCoarray(symbol)) { // F'2023 C825
974+
SayWithDeclaration(*badPotential,
975+
"Coarray '%s' may not have a coarray potential component '%s'"_err_en_US,
976+
symbol.name(), badPotential.BuildResultDesignatorName());
977+
} else if (isUnsavedLocal) { // F'2023 C826
978+
SayWithDeclaration(*badPotential,
979+
"Local variable '%s' without the SAVE attribute may not have a coarray potential subobject component '%s'"_err_en_US,
980+
symbol.name(), badPotential.BuildResultDesignatorName());
981+
} else {
982+
DIE("caught unexpected bad coarray potential component");
983+
}
984+
}
985+
} else if (isComponent && (IsAllocatable(symbol) || symbol.Rank() > 0)) {
986+
if (auto badUltimate{FindCoarrayUltimateComponent(*derived)}) {
987+
// TODO: still an error in F'2023?
988+
SayWithDeclaration(*badUltimate,
989+
"Allocatable or array component '%s' may not have a coarray ultimate component '%s'"_err_en_US,
990+
symbol.name(), badUltimate.BuildResultDesignatorName());
991+
}
992+
}
993+
}
994+
929995
// Check CUDA attributes and special circumstances of being in device
930996
// subprograms
931997
const Scope &progUnit{GetProgramUnitContaining(symbol)};
@@ -3161,10 +3227,6 @@ parser::Messages CheckHelper::WhyNotInteroperableFunctionResult(
31613227
msgs.Say(symbol.name(),
31623228
"Interoperable function result must be scalar"_err_en_US);
31633229
}
3164-
if (symbol.Corank()) {
3165-
msgs.Say(symbol.name(),
3166-
"Interoperable function result may not be a coarray"_err_en_US);
3167-
}
31683230
return msgs;
31693231
}
31703232

flang/lib/Semantics/resolve-names.cpp

Lines changed: 15 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -6127,32 +6127,6 @@ void DeclarationVisitor::Post(const parser::ComponentDecl &x) {
61276127
"POINTER or ALLOCATABLE"_err_en_US);
61286128
}
61296129
}
6130-
// TODO: This would be more appropriate in CheckDerivedType()
6131-
if (auto it{FindCoarrayUltimateComponent(*derived)}) { // C748
6132-
std::string ultimateName{it.BuildResultDesignatorName()};
6133-
// Strip off the leading "%"
6134-
if (ultimateName.length() > 1) {
6135-
ultimateName.erase(0, 1);
6136-
if (attrs.HasAny({Attr::POINTER, Attr::ALLOCATABLE})) {
6137-
evaluate::AttachDeclaration(
6138-
Say(name.source,
6139-
"A component with a POINTER or ALLOCATABLE attribute may "
6140-
"not "
6141-
"be of a type with a coarray ultimate component (named "
6142-
"'%s')"_err_en_US,
6143-
ultimateName),
6144-
derived->typeSymbol());
6145-
}
6146-
if (!arraySpec().empty() || !coarraySpec().empty()) {
6147-
evaluate::AttachDeclaration(
6148-
Say(name.source,
6149-
"An array or coarray component may not be of a type with a "
6150-
"coarray ultimate component (named '%s')"_err_en_US,
6151-
ultimateName),
6152-
derived->typeSymbol());
6153-
}
6154-
}
6155-
}
61566130
}
61576131
}
61586132
if (OkToAddComponent(name)) {
@@ -9889,6 +9863,21 @@ void ResolveNamesVisitor::ResolveSpecificationParts(ProgramTree &node) {
98899863
object->set_cudaDataAttr(common::CUDADataAttr::Device);
98909864
}
98919865
}
9866+
// Main program local objects usually don't have an implied SAVE attribute,
9867+
// as one might think, but in the exceptional case of a derived type
9868+
// local object that contains a coarray, we have to mark it as an
9869+
// implied SAVE so that evaluate::IsSaved() will return true.
9870+
if (node.scope()->kind() == Scope::Kind::MainProgram) {
9871+
if (const auto *object{symbol.detailsIf<ObjectEntityDetails>()}) {
9872+
if (const DeclTypeSpec * type{object->type()}) {
9873+
if (const DerivedTypeSpec * derived{type->AsDerived()}) {
9874+
if (!IsSaved(symbol) && FindCoarrayPotentialComponent(*derived)) {
9875+
SetImplicitAttr(symbol, Attr::SAVE);
9876+
}
9877+
}
9878+
}
9879+
}
9880+
}
98929881
}
98939882
}
98949883

flang/lib/Semantics/tools.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1386,6 +1386,13 @@ template class ComponentIterator<ComponentKind::Potential>;
13861386
template class ComponentIterator<ComponentKind::Scope>;
13871387
template class ComponentIterator<ComponentKind::PotentialAndPointer>;
13881388

1389+
PotentialComponentIterator::const_iterator FindCoarrayPotentialComponent(
1390+
const DerivedTypeSpec &derived) {
1391+
PotentialComponentIterator potentials{derived};
1392+
return std::find_if(potentials.begin(), potentials.end(),
1393+
[](const Symbol &symbol) { return evaluate::IsCoarray(symbol); });
1394+
}
1395+
13891396
UltimateComponentIterator::const_iterator FindCoarrayUltimateComponent(
13901397
const DerivedTypeSpec &derived) {
13911398
UltimateComponentIterator ultimates{derived};

flang/test/Lower/pre-fir-tree04.f90

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
! CHECK: Subroutine test_coarray
66
Subroutine test_coarray
77
use iso_fortran_env, only: team_type, event_type, lock_type
8+
save
89
type(team_type) :: t
910
type(event_type) :: done[*]
1011
type(lock_type) :: alock[*]

flang/test/Semantics/allocate11.f90

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,14 @@ subroutine C937(var)
3838

3939
type B
4040
type(A) y
41-
!ERROR: A component with a POINTER or ALLOCATABLE attribute may not be of a type with a coarray ultimate component (named 'y%x')
41+
!ERROR: Allocatable or array component 'forward' may not have a coarray ultimate component '%y%x'
42+
type(B), allocatable :: forward
43+
real :: u
44+
end type
45+
46+
type B2
47+
type(A) y
48+
!ERROR: Pointer 'forward' may not have a coarray potential component '%y%x'
4249
type(B), pointer :: forward
4350
real :: u
4451
end type
@@ -48,11 +55,14 @@ subroutine C937(var)
4855
end type
4956

5057
type D
51-
!ERROR: A component with a POINTER or ALLOCATABLE attribute may not be of a type with a coarray ultimate component (named 'x')
52-
type(A), pointer :: potential
58+
!ERROR: Allocatable or array component 'potential' may not have a coarray ultimate component '%x'
59+
type(A), allocatable :: potential
5360
end type
5461

55-
62+
type D2
63+
!ERROR: Pointer 'potential' may not have a coarray potential component '%x'
64+
type(A), pointer :: potential
65+
end type
5666

5767
class(*), allocatable :: var
5868
! unlimited polymorphic is the ONLY way to get an allocatable/pointer 'var' that can be

flang/test/Semantics/assign02.f90

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,8 @@ subroutine s4(x)
7474

7575
! C1020
7676
subroutine s5
77-
real, target :: x[*]
78-
real, target, volatile :: y[*]
77+
real, target, save :: x[*]
78+
real, target, volatile, save :: y[*]
7979
real, pointer :: p
8080
real, pointer, volatile :: q
8181
p => x
@@ -148,7 +148,7 @@ function f2()
148148

149149
! C1026 (R1037) A data-target shall not be a coindexed object.
150150
subroutine s10
151-
real, target :: a[*]
151+
real, target, save :: a[*]
152152
real, pointer :: b
153153
!ERROR: A coindexed object may not be a pointer target
154154
b => a[1]

flang/test/Semantics/associated.f90

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ subroutine test(assumedRank)
9090
type(t2) :: t2x
9191
type(t2), target :: t2xtarget
9292
integer, target :: targetIntArr(2)
93-
integer, target :: targetIntCoarray[*]
93+
integer, target, save :: targetIntCoarray[*]
9494
integer, pointer :: intPointerArr(:)
9595
procedure(objPtrFunc), pointer :: objPtrFuncPointer
9696

flang/test/Semantics/bind-c09.f90

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,6 @@ function func8() result(res) bind(c)
4444
end
4545

4646
function func9() result(res) bind(c)
47-
! ERROR: Interoperable function result may not be a coarray
47+
! ERROR: Function result may not be a coarray
4848
integer :: res[10, *]
4949
end

flang/test/Semantics/call10.f90

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -200,8 +200,9 @@ pure subroutine s13
200200
!ERROR: An image control statement may not appear in a pure subprogram
201201
sync all ! C1599
202202
end subroutine
203-
pure subroutine s14
204-
integer :: img, nimgs, i[*], tmp
203+
pure subroutine s14(i)
204+
integer :: img, nimgs, tmp
205+
integer, intent(in out) :: i[*]
205206
! implicit sync all
206207
img = this_image()
207208
nimgs = num_images()

flang/test/Semantics/call12.f90

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,9 @@ pure function test(ptr, in, hpd, hhpd)
4040
type(hasHiddenPtr), intent(in) :: hhpd
4141
type(hasPtr), allocatable :: alloc
4242
type(hasHiddenPtr), allocatable :: hpAlloc
43+
!ERROR: Pointer 'hcp' may not have a coarray potential component '%co'
4344
type(hasCoarray), pointer :: hcp
45+
type(hasCoarray), allocatable :: hca
4446
integer :: n
4547
common /block/ y
4648
external :: extfunc
@@ -60,8 +62,8 @@ pure function test(ptr, in, hpd, hhpd)
6062
!BECAUSE: 'in' is an INTENT(IN) dummy argument
6163
in%a = 0. ! C1594(1)
6264
!ERROR: Left-hand side of assignment is not definable
63-
!BECAUSE: A pure subprogram may not define the coindexed object 'hcp%co[1_8]'
64-
hcp%co[1] = 0. ! C1594(1)
65+
!BECAUSE: A pure subprogram may not define the coindexed object 'hca%co[1_8]'
66+
hca%co[1] = 0. ! C1594(1)
6567
!ERROR: The left-hand side of a pointer assignment is not definable
6668
!BECAUSE: 'ptr' may not be defined in pure subprogram 'test' because it is a POINTER dummy argument of a pure function
6769
ptr => z ! C1594(2)

flang/test/Semantics/change_team01.f90

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
subroutine test
66
use, intrinsic :: iso_fortran_env, only: team_type
7+
save
78
type(team_type) :: team
89
integer, codimension[*] :: selector
910
integer, codimension[2,*] :: selector2d

flang/test/Semantics/coarrays01.f90

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
! Test selector and team-value in CHANGE TEAM statement
33

44
! OK
5-
subroutine s1
5+
subroutine s1(y)
66
use iso_fortran_env, only: team_type
77
type(team_type) :: t
88
real :: y[10,*]
@@ -11,7 +11,7 @@ subroutine s1
1111
form team(1, t)
1212
end
1313

14-
subroutine s2
14+
subroutine s2(y,y2,x)
1515
use iso_fortran_env
1616
type(team_type) :: t
1717
real :: y[10,*], y2[*], x[*]
@@ -27,7 +27,7 @@ subroutine s2
2727
end team
2828
end
2929

30-
subroutine s3
30+
subroutine s3(y)
3131
type :: team_type
3232
end type
3333
type :: foo

0 commit comments

Comments
 (0)