Skip to content

Commit d629439

Browse files
klauslergithub-actions[bot]
authored andcommitted
Automerge: [flang] Emit error on impossible-to-implement construct (#160384)
An assignment to a whole polymorphic allocatable changes its dynamic type to the type of the right-hand side expression. But when the assignment is under control of a WHERE statement, or a FORALL / DO CONCURRENT with a mask expression, there is no interpretation of the assignment, as the type of a variable must be the same for all of its elements. There is no restriction in the standard against this usage, and no other Fortran compiler complains about it. But it is not possible to implement it in general, and the behavior produced by other compilers is not reasonable, much less worthy of emulating. It's best to simply disallow it with an error message. Fixes llvm/llvm-project#133669, or more accurately, resolves it.
2 parents d74f3c5 + 2780c20 commit d629439

File tree

3 files changed

+67
-1
lines changed

3 files changed

+67
-1
lines changed

flang/docs/Extensions.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -557,6 +557,17 @@ end
557557
generic intrinsic function's inferred result type does not
558558
match an explicit declaration. This message is a warning.
559559

560+
* There is no restriction in the standard against assigning
561+
to a whole polymorphic allocatable under control of a `WHERE`
562+
construct or statement, but there is no good portable
563+
behavior to implement and the standard isn't entirely clear
564+
what it should mean.
565+
(Other compilers allow it, but the results are never meaningful;
566+
some never change the type, some change the type according to
567+
the value of the last mask element, some treat these
568+
assignment statements as no-ops, and the rest crash during compilation.)
569+
The compiler flags this case as an error.
570+
560571
## Standard features that might as well not be
561572

562573
* f18 supports designators with constant expressions, properly

flang/lib/Semantics/assignment.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@ class AssignmentContext {
4141
void PopWhereContext();
4242
void Analyze(const parser::AssignmentStmt &);
4343
void Analyze(const parser::PointerAssignmentStmt &);
44-
void Analyze(const parser::ConcurrentControl &);
4544
SemanticsContext &context() { return context_; }
4645

4746
private:
@@ -76,6 +75,11 @@ void AssignmentContext::Analyze(const parser::AssignmentStmt &stmt) {
7675
whole{evaluate::UnwrapWholeSymbolOrComponentDataRef(lhs)}) {
7776
if (IsAllocatable(whole->GetUltimate())) {
7877
flags.set(DefinabilityFlag::PotentialDeallocation);
78+
if (IsPolymorphic(*whole) && whereDepth_ > 0) {
79+
Say(lhsLoc,
80+
"Assignment to whole polymorphic allocatable '%s' may not be nested in a WHERE statement or construct"_err_en_US,
81+
whole->name());
82+
}
7983
}
8084
}
8185
if (auto whyNot{WhyNotDefinable(lhsLoc, scope, flags, lhs)}) {

flang/test/Semantics/bug133669.f90

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
!RUN: %python %S/test_errors.py %s %flang_fc1
2+
module m
3+
contains
4+
subroutine s(x, y, mask)
5+
class(*), allocatable, intent(in out) :: x(:), y(:)
6+
logical, intent(in) :: mask(:)
7+
select type(x)
8+
type is(integer)
9+
print *, 'before, x is integer', x
10+
type is(real)
11+
print *, 'before, x is real', x
12+
class default
13+
print *, 'before, x has some other type'
14+
end select
15+
select type(y)
16+
type is(integer)
17+
print *, 'y is integer', y
18+
type is(real)
19+
print *, 'y is real', y
20+
end select
21+
print *, 'mask', mask
22+
!ERROR: Assignment to whole polymorphic allocatable 'x' may not be nested in a WHERE statement or construct
23+
where(mask) x = y
24+
select type(x)
25+
type is(integer)
26+
print *, 'after, x is integer', x
27+
type is(real)
28+
print *, 'after, x is real', x
29+
class default
30+
print *, 'before, x has some other type'
31+
end select
32+
print *
33+
end
34+
end
35+
36+
program main
37+
use m
38+
class(*), allocatable :: x(:), y(:)
39+
x = [1, 2]
40+
y = [3., 4.]
41+
call s(x, y, [.false., .false.])
42+
x = [1, 2]
43+
y = [3., 4.]
44+
call s(x, y, [.false., .true.])
45+
x = [1, 2]
46+
y = [3., 4.]
47+
call s(x, y, [.true., .false.])
48+
x = [1, 2]
49+
y = [3., 4.]
50+
call s(x, y, [.true., .true.])
51+
end program main

0 commit comments

Comments
 (0)