[flang] Parenthesize RHS arguments to defined assignments (bug #62599)

The right-hand sides of assignment statements are always expressions,
never variables.  When an assignment statement is converted into a call
to a defined assignment subroutine, and the actual argument being associated
with the second dummy argument is a variable, and the dummy argument does
not have the VALUE attribute, wrap it with parentheses so that lowering
will pass it by means of a temporary.

Fixes https://github.com/llvm/llvm-project/issues/62599.

Differential Revision: https://reviews.llvm.org/D150331
This commit is contained in:
Peter Klausler
2023-05-10 16:18:47 -07:00
parent 7c1f279328
commit 01e22dfb10
4 changed files with 657 additions and 618 deletions

View File

@@ -4067,7 +4067,7 @@ bool ArgumentAnalyzer::OkLogicalIntegerAssignment(
std::optional<ProcedureRef> ArgumentAnalyzer::GetDefinedAssignmentProc() {
const Symbol *proc{nullptr};
int passedObjectIndex{-1};
std::optional<int> passedObjectIndex;
std::string oprNameString{"assignment(=)"};
parser::CharBlock oprName{oprNameString};
const auto &scope{context_.context().FindScope(source_)};
@@ -4099,8 +4099,23 @@ std::optional<ProcedureRef> ArgumentAnalyzer::GetDefinedAssignmentProc() {
return std::nullopt;
}
ActualArguments actualsCopy{actuals_};
if (passedObjectIndex >= 0) {
actualsCopy[passedObjectIndex]->set_isPassedObject();
// Ensure that the RHS argument is not passed as a variable unless
// the dummy argument has the VALUE attribute.
if (evaluate::IsVariable(actualsCopy.at(1).value().UnwrapExpr())) {
auto chars{evaluate::characteristics::Procedure::Characterize(
*proc, context_.GetFoldingContext())};
const auto *rhsDummy{chars && chars->dummyArguments.size() == 2
? std::get_if<evaluate::characteristics::DummyDataObject>(
&chars->dummyArguments.at(1).u)
: nullptr};
if (!rhsDummy ||
!rhsDummy->attrs.test(
evaluate::characteristics::DummyDataObject::Attr::Value)) {
actualsCopy.at(1).value().Parenthesize();
}
}
if (passedObjectIndex) {
actualsCopy[*passedObjectIndex]->set_isPassedObject();
}
return ProcedureRef{ProcedureDesignator{*proc}, std::move(actualsCopy)};
}

File diff suppressed because it is too large Load Diff

View File

@@ -17,6 +17,10 @@ subroutine user_assignment(a, i)
end subroutine
end interface
type(t) :: a
! CHECK: fir.call @_QPmy_assign(%[[arg0]], %[[arg1]])
! CHECK: %[[V_0:[0-9]+]] = fir.alloca i32
! CHECK: %[[V_1:[0-9]+]] = fir.load %arg1 : !fir.ref<i32>
! CHECK: %[[V_2:[0-9]+]] = fir.no_reassoc %[[V_1:[0-9]+]] : i32
! CHECK: fir.store %[[V_2]] to %[[V_0:[0-9]+]] : !fir.ref<i32>
! CHECK: fir.call @_QPmy_assign(%arg0, %[[V_0]]) fastmath<contract> : (!fir.ref<!fir.type<_QFuser_assignmentTt{x:f32,i:i32}>>, !fir.ref<i32>) -> ()
a = i
end subroutine

View File

@@ -13,7 +13,7 @@ module m1
contains
subroutine s1(x, y)
class(t), intent(out) :: x
integer, intent(in) :: y
integer, intent(in), value :: y
end
subroutine s2(x, y)
real, intent(out) :: x
@@ -22,9 +22,13 @@ contains
subroutine test1(x)
type(t) :: x
real :: a
integer :: j
!CHECK: CALL s1(x,1_4)
x = 1
!CHECK: CALL s2(a,x)
j = 1
!CHECK: CALL s1(x,j)
x = j ! no parentheses due to VALUE
!CHECK: CALL s2(a,(x))
a = x
end
subroutine test2(x)
@@ -32,7 +36,7 @@ contains
real :: a
!CHECK: CALL x%b1(1_4)
x = 1
!CHECK: CALL x%b2(a)
!CHECK: CALL (x)%b2(a)
a = x
end
end
@@ -73,6 +77,10 @@ module m3
real, intent(out) :: x
class(*), intent(in) :: y
end
subroutine s3(x, y)
integer, intent(out) :: x
class(*), intent(in), value :: y
end
end interface
interface operator(+)
integer function f(x, y)
@@ -89,7 +97,9 @@ contains
x = 2
!CHECK: i=f(x,y)
i = x + y
!CHECK: CALL s2(a,z)
!CHECK: CALL s2(a,(z))
a = z
!CHECK: CALL s3(i,z)
i = z
end
end