Index: flang/lib/Lower/CallInterface.cpp =================================================================== --- flang/lib/Lower/CallInterface.cpp +++ flang/lib/Lower/CallInterface.cpp @@ -886,7 +886,14 @@ if (isBindC) { passBy = PassEntityBy::Value; prop = Property::Value; - passType = type; + auto recTy = type.dyn_cast_or_null(); + if (recTy && recTy.getTypeList().size() == 1 && + recTy.getTypeList()[0].first.compare("__address") == 0) { + auto fieldTy = recTy.getTypeList()[0].second; + passType = fir::ReferenceType::get(fieldTy); + } else { + passType = type; + } } else { passBy = PassEntityBy::BaseAddressValueAttribute; } Index: flang/lib/Lower/ConvertExpr.cpp =================================================================== --- flang/lib/Lower/ConvertExpr.cpp +++ flang/lib/Lower/ConvertExpr.cpp @@ -2469,6 +2469,29 @@ return res; } + /// Lower a type(C_PTR/C_FUNPTR) argument with VALUE attribute into a + /// reference. A C pointer can correspond to a Fortran dummy argument of type + /// C_PTR with the VALUE attribute. (see 18.3.6 note 3). + static mlir::Value + genRecordCPtrValueArg(Fortran::lower::AbstractConverter &converter, + mlir::Value rec, mlir::Type ty) { + assert(fir::isa_derived(ty)); + auto recTy = ty.dyn_cast(); + assert(recTy.getTypeList().size() == 1); + auto fieldName = recTy.getTypeList()[0].first; + auto fieldTy = recTy.getTypeList()[0].second; + fir::FirOpBuilder &builder = converter.getFirOpBuilder(); + mlir::Location loc = converter.getCurrentLocation(); + auto fieldIndexType = fir::FieldType::get(ty.getContext()); + mlir::Value field = + builder.create(loc, fieldIndexType, fieldName, recTy, + /*typeParams=*/mlir::ValueRange{}); + mlir::Value cAddr = builder.create( + loc, builder.getRefType(fieldTy), rec, field); + mlir::Value val = builder.create(loc, cAddr); + return builder.createConvert(loc, builder.getRefType(fieldTy), val); + } + /// Given a call site for which the arguments were already lowered, generate /// the call and return the result. This function deals with explicit result /// allocation and lowering if needed. It also deals with passing the host @@ -2677,14 +2700,24 @@ cast = builder.create(loc, boxProcTy, fst); } } else { - if (fir::isa_derived(snd)) { + mlir::Type fromTy = fst.getType(); + auto recTy = + fir::unwrapRefType(fromTy).dyn_cast_or_null(); + // The interface for type(C_PTR/C_FUNPTR) is "!fir.ref". + if (fromTy.isa() && recTy && + recTy.getTypeList().size() == 1 && + recTy.getTypeList()[0].first.compare("__address") == 0 && + snd.isa() && + fir::isa_integer(fir::unwrapRefType(snd))) { + cast = genRecordCPtrValueArg(converter, fst, recTy); + } else if (fir::isa_derived(snd)) { // FIXME: This seems like a serious bug elsewhere in lowering. Paper // over the problem for now. TODO(loc, "derived type argument passed by value"); + } else { + cast = builder.convertWithSemantics(loc, snd, fst, + callingImplicitInterface); } - assert(!fir::isa_derived(snd)); - cast = builder.convertWithSemantics(loc, snd, fst, - callingImplicitInterface); } operands.push_back(cast); } Index: flang/test/Lower/c-interoperability-c-pointer.f90 =================================================================== --- /dev/null +++ flang/test/Lower/c-interoperability-c-pointer.f90 @@ -0,0 +1,33 @@ +! RUN: bbc -emit-fir %s -o - | FileCheck %s + +! CHECK-LABEL: func.func @_QPtest( +! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref> {fir.bindc_name = "ptr1"}, +! CHECK-SAME: %[[VAL_1:.*]]: !fir.ref> {fir.bindc_name = "ptr2"}) { +! CHECK: %[[VAL_2:.*]] = fir.field_index __address, !fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}> +! CHECK: %[[VAL_3:.*]] = fir.coordinate_of %[[VAL_0]], %[[VAL_2]] : (!fir.ref>, !fir.field) -> !fir.ref +! CHECK: %[[VAL_4:.*]] = fir.load %[[VAL_3]] : !fir.ref +! CHECK: %[[VAL_5:.*]] = fir.convert %[[VAL_4]] : (i64) -> !fir.ref +! CHECK: %[[VAL_6:.*]] = fir.field_index __address, !fir.type<_QM__fortran_builtinsT__builtin_c_funptr{__address:i64}> +! CHECK: %[[VAL_7:.*]] = fir.coordinate_of %[[VAL_1]], %[[VAL_6]] : (!fir.ref>, !fir.field) -> !fir.ref +! CHECK: %[[VAL_8:.*]] = fir.load %[[VAL_7]] : !fir.ref +! CHECK: %[[VAL_9:.*]] = fir.convert %[[VAL_8]] : (i64) -> !fir.ref +! CHECK: fir.call @c_func(%[[VAL_5]], %[[VAL_9]]) : (!fir.ref, !fir.ref) -> () +! CHECK: return +! CHECK: } +! CHECK: func.func private @c_func(!fir.ref, !fir.ref) attributes {fir.bindc_name = "c_func"} + +subroutine test(ptr1, ptr2) + use, intrinsic :: iso_c_binding + type(c_ptr) :: ptr1 + type(c_funptr) :: ptr2 + + interface + subroutine c_func(c_t1, c_t2) bind(c, name="c_func") + import :: c_ptr, c_funptr + type(c_ptr), value :: c_t1 + type(c_funptr), value :: c_t2 + end + end interface + + call c_func(ptr1, ptr2) +end