Skip to content

Commit 09b4649

Browse files
authored
[flang] Fix passing NULL to OPTIONAL procedure pointers (#80267)
Procedure pointer lowering used `prepareUserCallActualArgument` because it was convenient, but this helper was not meant for POINTERs when originally written and it did not handled passing NULL to an OPTIONAL procedure pointer correctly. The resulting argument should be a disassociated pointer, not an absent pointer (Fortran 15.5.2.12 point 1.). Move the logic for procedure pointer argument "cooking" in its own helper to avoid triggering the logic that created an absent argument in this case.
1 parent 4eb0810 commit 09b4649

File tree

2 files changed

+61
-27
lines changed

2 files changed

+61
-27
lines changed

flang/lib/Lower/ConvertCall.cpp

Lines changed: 41 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -912,37 +912,16 @@ static PreparedDummyArgument preparePresentUserCallActualArgument(
912912
// element if this is an array in an elemental call.
913913
hlfir::Entity actual = preparedActual.getActual(loc, builder);
914914

915-
// Handle the procedure pointer actual arguments.
916-
if (actual.isProcedurePointer()) {
917-
// Procedure pointer actual to procedure pointer dummy.
918-
if (fir::isBoxProcAddressType(dummyType))
919-
return PreparedDummyArgument{actual, /*cleanups=*/{}};
915+
// Handle procedure arguments (procedure pointers should go through
916+
// prepareProcedurePointerActualArgument).
917+
if (hlfir::isFortranProcedureValue(dummyType)) {
920918
// Procedure pointer actual to procedure dummy.
921-
if (hlfir::isFortranProcedureValue(dummyType)) {
919+
if (actual.isProcedurePointer()) {
922920
actual = hlfir::derefPointersAndAllocatables(loc, builder, actual);
923921
return PreparedDummyArgument{actual, /*cleanups=*/{}};
924922
}
925-
}
926-
927-
// NULL() actual to procedure pointer dummy
928-
if (Fortran::evaluate::IsNullProcedurePointer(expr) &&
929-
fir::isBoxProcAddressType(dummyType)) {
930-
auto boxTy{Fortran::lower::getUntypedBoxProcType(builder.getContext())};
931-
auto tempBoxProc{builder.createTemporary(loc, boxTy)};
932-
hlfir::Entity nullBoxProc(
933-
fir::factory::createNullBoxProc(builder, loc, boxTy));
934-
builder.create<fir::StoreOp>(loc, nullBoxProc, tempBoxProc);
935-
return PreparedDummyArgument{tempBoxProc, /*cleanups=*/{}};
936-
}
937-
938-
if (actual.isProcedure()) {
939-
// Procedure actual to procedure pointer dummy.
940-
if (fir::isBoxProcAddressType(dummyType)) {
941-
auto tempBoxProc{builder.createTemporary(loc, actual.getType())};
942-
builder.create<fir::StoreOp>(loc, actual, tempBoxProc);
943-
return PreparedDummyArgument{tempBoxProc, /*cleanups=*/{}};
944-
}
945923
// Procedure actual to procedure dummy.
924+
assert(actual.isProcedure());
946925
// Do nothing if this is a procedure argument. It is already a
947926
// fir.boxproc/fir.tuple<fir.boxproc, len> as it should.
948927
if (actual.getType() != dummyType)
@@ -1219,6 +1198,34 @@ static PreparedDummyArgument prepareUserCallActualArgument(
12191198
return result;
12201199
}
12211200

1201+
/// Prepare actual argument for a procedure pointer dummy.
1202+
static PreparedDummyArgument prepareProcedurePointerActualArgument(
1203+
mlir::Location loc, fir::FirOpBuilder &builder,
1204+
const Fortran::lower::PreparedActualArgument &preparedActual,
1205+
mlir::Type dummyType,
1206+
const Fortran::lower::CallerInterface::PassedEntity &arg,
1207+
const Fortran::lower::SomeExpr &expr, CallContext &callContext) {
1208+
1209+
// NULL() actual to procedure pointer dummy
1210+
if (Fortran::evaluate::UnwrapExpr<Fortran::evaluate::NullPointer>(expr) &&
1211+
fir::isBoxProcAddressType(dummyType)) {
1212+
auto boxTy{Fortran::lower::getUntypedBoxProcType(builder.getContext())};
1213+
auto tempBoxProc{builder.createTemporary(loc, boxTy)};
1214+
hlfir::Entity nullBoxProc(
1215+
fir::factory::createNullBoxProc(builder, loc, boxTy));
1216+
builder.create<fir::StoreOp>(loc, nullBoxProc, tempBoxProc);
1217+
return PreparedDummyArgument{tempBoxProc, /*cleanups=*/{}};
1218+
}
1219+
hlfir::Entity actual = preparedActual.getActual(loc, builder);
1220+
if (actual.isProcedurePointer())
1221+
return PreparedDummyArgument{actual, /*cleanups=*/{}};
1222+
assert(actual.isProcedure());
1223+
// Procedure actual to procedure pointer dummy.
1224+
auto tempBoxProc{builder.createTemporary(loc, actual.getType())};
1225+
builder.create<fir::StoreOp>(loc, actual, tempBoxProc);
1226+
return PreparedDummyArgument{tempBoxProc, /*cleanups=*/{}};
1227+
}
1228+
12221229
/// Lower calls to user procedures with actual arguments that have been
12231230
/// pre-lowered but not yet prepared according to the interface.
12241231
/// This can be called for elemental procedures, but only with scalar
@@ -1284,14 +1291,21 @@ genUserCall(Fortran::lower::PreparedActualArguments &loweredActuals,
12841291
case PassBy::CharBoxValueAttribute:
12851292
case PassBy::Box:
12861293
case PassBy::BaseAddress:
1287-
case PassBy::BoxProcRef:
12881294
case PassBy::BoxChar: {
12891295
PreparedDummyArgument preparedDummy = prepareUserCallActualArgument(
12901296
loc, builder, *preparedActual, argTy, arg, *expr, callContext);
12911297
callCleanUps.append(preparedDummy.cleanups.rbegin(),
12921298
preparedDummy.cleanups.rend());
12931299
caller.placeInput(arg, preparedDummy.dummy);
12941300
} break;
1301+
case PassBy::BoxProcRef: {
1302+
PreparedDummyArgument preparedDummy =
1303+
prepareProcedurePointerActualArgument(loc, builder, *preparedActual,
1304+
argTy, arg, *expr, callContext);
1305+
callCleanUps.append(preparedDummy.cleanups.rbegin(),
1306+
preparedDummy.cleanups.rend());
1307+
caller.placeInput(arg, preparedDummy.dummy);
1308+
} break;
12951309
case PassBy::AddressAndLength:
12961310
// PassBy::AddressAndLength is only used for character results. Results
12971311
// are not handled here.

flang/test/Lower/HLFIR/procedure-pointer.f90

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,26 @@ subroutine sub12()
340340
! CHECK: fir.call @_QPfoo2(%[[VAL_17]]) fastmath<contract> : (!fir.ref<!fir.boxproc<() -> ()>>) -> ()
341341
end
342342

343+
subroutine test_opt_pointer()
344+
interface
345+
subroutine takes_opt_proc_ptr(p)
346+
procedure(), pointer, optional :: p
347+
end subroutine
348+
end interface
349+
call takes_opt_proc_ptr(NULL())
350+
call takes_opt_proc_ptr()
351+
end subroutine
352+
! CHECK-LABEL: func.func @_QPtest_opt_pointer() {
353+
! CHECK: %[[VAL_0:.*]] = fir.alloca !fir.boxproc<() -> ()>
354+
! CHECK: %[[VAL_1:.*]] = fir.zero_bits () -> ()
355+
! CHECK: %[[VAL_2:.*]] = fir.emboxproc %[[VAL_1]] : (() -> ()) -> !fir.boxproc<() -> ()>
356+
! CHECK: fir.store %[[VAL_2]] to %[[VAL_0]] : !fir.ref<!fir.boxproc<() -> ()>>
357+
! CHECK: fir.call @_QPtakes_opt_proc_ptr(%[[VAL_0]]) fastmath<contract> : (!fir.ref<!fir.boxproc<() -> ()>>) -> ()
358+
! CHECK: %[[VAL_3:.*]] = fir.absent !fir.ref<!fir.boxproc<() -> ()>>
359+
! CHECK: fir.call @_QPtakes_opt_proc_ptr(%[[VAL_3]]) fastmath<contract> : (!fir.ref<!fir.boxproc<() -> ()>>) -> ()
360+
361+
362+
343363
! CHECK-LABEL: fir.global internal @_QFsub1Ep2 : !fir.boxproc<(!fir.ref<f32>) -> f32> {
344364
! CHECK: %[[VAL_0:.*]] = fir.zero_bits (!fir.ref<f32>) -> f32
345365
! CHECK: %[[VAL_1:.*]] = fir.emboxproc %[[VAL_0]] : ((!fir.ref<f32>) -> f32) -> !fir.boxproc<(!fir.ref<f32>) -> f32>

0 commit comments

Comments
 (0)