Skip to content

Commit f521338

Browse files
authored
[flang] Correct defined assignment case (#142020)
When a generic ASSIGNMENT(=) has elemental and non-elemental specific procedures that match the actual arguments, the non-elemental procedure must take precedence. We get this right for generics defined with interface blocks, but the type-bound case fails if the non-elemental specific takes a non-default PASS argument. Fixes #141807.
1 parent 7b9518a commit f521338

File tree

2 files changed

+54
-12
lines changed

2 files changed

+54
-12
lines changed

flang/lib/Semantics/expression.cpp

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2907,7 +2907,7 @@ std::pair<const Symbol *, bool> ExpressionAnalyzer::ResolveGeneric(
29072907
continue;
29082908
}
29092909
// Matching distance is smaller than the previously matched
2910-
// specific. Let it go thourgh so the current procedure is picked.
2910+
// specific. Let it go through so the current procedure is picked.
29112911
} else {
29122912
// 16.9.144(6): a bare NULL() is not allowed as an actual
29132913
// argument to a generic procedure if the specific procedure
@@ -4824,31 +4824,41 @@ bool ArgumentAnalyzer::OkLogicalIntegerAssignment(
48244824

48254825
std::optional<ProcedureRef> ArgumentAnalyzer::GetDefinedAssignmentProc() {
48264826
const Symbol *proc{nullptr};
4827+
bool isProcElemental{false};
48274828
std::optional<int> passedObjectIndex;
48284829
std::string oprNameString{"assignment(=)"};
48294830
parser::CharBlock oprName{oprNameString};
48304831
const auto &scope{context_.context().FindScope(source_)};
4831-
// If multiple resolutions were possible, they will have been already
4832-
// diagnosed.
48334832
{
48344833
auto restorer{context_.GetContextualMessages().DiscardMessages()};
48354834
if (const Symbol *symbol{scope.FindSymbol(oprName)}) {
48364835
ExpressionAnalyzer::AdjustActuals noAdjustment;
48374836
proc =
48384837
context_.ResolveGeneric(*symbol, actuals_, noAdjustment, true).first;
4838+
if (proc) {
4839+
isProcElemental = IsElementalProcedure(*proc);
4840+
}
48394841
}
4840-
for (std::size_t i{0}; !proc && i < actuals_.size(); ++i) {
4842+
for (std::size_t i{0}; (!proc || isProcElemental) && i < actuals_.size();
4843+
++i) {
48414844
const Symbol *generic{nullptr};
48424845
if (const Symbol *
48434846
binding{FindBoundOp(oprName, i, generic, /*isSubroutine=*/true)}) {
4844-
if (CheckAccessibleSymbol(scope, DEREF(generic))) {
4845-
// ignore inaccessible type-bound ASSIGNMENT(=) generic
4846-
} else if (const Symbol *
4847-
resolution{GetBindingResolution(GetType(i), *binding)}) {
4848-
proc = resolution;
4849-
} else {
4850-
proc = binding;
4851-
passedObjectIndex = i;
4847+
// ignore inaccessible type-bound ASSIGNMENT(=) generic
4848+
if (!CheckAccessibleSymbol(scope, DEREF(generic))) {
4849+
const Symbol *resolution{GetBindingResolution(GetType(i), *binding)};
4850+
const Symbol &newProc{*(resolution ? resolution : binding)};
4851+
bool isElemental{IsElementalProcedure(newProc)};
4852+
if (!proc || !isElemental) {
4853+
// Non-elemental resolution overrides elemental
4854+
proc = &newProc;
4855+
isProcElemental = isElemental;
4856+
if (resolution) {
4857+
passedObjectIndex.reset();
4858+
} else {
4859+
passedObjectIndex = i;
4860+
}
4861+
}
48524862
}
48534863
}
48544864
}

flang/test/Semantics/bug141807.f90

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
!RUN: %flang_fc1 -fdebug-unparse %s | FileCheck %s
2+
!Ensure that non-elemental specific takes precedence over elemental
3+
!defined assignment, even with non-default PASS argument.
4+
module m
5+
type base
6+
integer :: n = -999
7+
contains
8+
procedure, pass(from) :: array_assign_scalar
9+
procedure :: elemental_assign
10+
generic :: assignment(=) => array_assign_scalar, elemental_assign
11+
end type
12+
contains
13+
subroutine array_assign_scalar(to, from)
14+
class(base), intent(out) :: to(:)
15+
class(base), intent(in) :: from
16+
to%n = from%n
17+
end
18+
impure elemental subroutine elemental_assign(to, from)
19+
class(base), intent(out) :: to
20+
class(base), intent(in) :: from
21+
to%n = from%n
22+
end
23+
end
24+
25+
use m
26+
type(base) :: array(1), scalar
27+
scalar%n = 1
28+
!CHECK: CALL array_assign_scalar(array,(scalar))
29+
array = scalar
30+
!CHECK: CALL elemental_assign(array,[base::scalar])
31+
array = [scalar]
32+
end

0 commit comments

Comments
 (0)