Community
cancel
Showing results for 
Search instead for 
Did you mean: 
Highlighted
Beginner
30 Views

Polymorphic dummy argument not interoperable

I'm trying to do some black magic.....namely, I've created a C routine which performs a memset() on the array or structure passed to it:

typedef ptrdiff_t CFI_type_t;

typedef struct CFI_dim_t_
{
  CFI_index_t extent;
  CFI_index_t sm;
  CFI_index_t lower_bound;
} CFI_dim_t;

typedef struct CFI_cdesc_t_
{
  void *base_addr;
  size_t elem_len;
  int version;
  CFI_attribute_t attribute;
  CFI_rank_t rank;
  CFI_type_t type;
  // Begin Intel-specific fields - these are for
  // Intel compiler/library use only and should
  // not be modified
  intptr_t intel_flags;
  intptr_t intel_reserved1;
  intptr_t intel_reserved2;
  // End Intel-specific fields
  CFI_dim_t dim[];
} CFI_cdesc_t;

void fortran_init( CFI_cdesc_t *a ) {
  memset( a->base_addr, 0, a->elem_len );
  return;
}

My Fortran interface definition goes as such:

INTERFACE
  SUBROUTINE FORTRAN_INIT( A ) BIND(C, NAME='fortran_init')
    IMPLICIT    NONE
    CLASS (*), INTENT(IN)    :: A
  END SUBROUTINE FORTRAN_INIT
END INTERFACE

When I compile this using version 15.0.2, everything works fine, and the execution behaves as-expected (I can view all the descriptor properties in the debugger).  However, when I compile with the newest version of ifort, I get the following:

#8789: Polymorphic dummy argument to a BIND(C) procedure is not interoperable.

Should I be using a different prototype on the Fortran side to get the CFI_cdesc_t descriptor passed to it properly?

Thanks in advance.

0 Kudos
4 Replies
Highlighted
Black Belt Retired Employee
30 Views

The error message is correct - polymorphic entities are not interoperable.

First, please do NOT try to roll your own declarations of the CFI structures. ONLY, ONLY, ONLY! use ISO_Fortran_binding.h!

What you probably want instead is:

INTERFACE
  SUBROUTINE FORTRAN_INIT( A ) BIND(C, NAME='fortran_init')
    IMPLICIT    NONE
    TYPE(*), DIMENSION(..),  INTENT(OUT)  :: A
  END SUBROUTINE FORTRAN_INIT
END INTERFACE

Note that I said INTENT(OUT) - you had INTENT(IN) which is not what you're doing!

Your C routine is setting only the first element. I doubt that's what you intended. You'd need to compute the number of elements by iterating through the extents.

0 Kudos
Highlighted
Beginner
30 Views

Actually, it is always my preference to use compiler-provided headers, but in this case, I only have iso_c_binding.f90 and not ISO_Fortran_binding.h in my installation (there are other C header files in the compiler's include folder, but not that).  Where should I be looking for this header?  I believe I got those definitions from the compiler documentation.  I checked .../composerxe-2015.2.164/compiler/include, and actually searched the entire compiler installation path, but no dice.

And yes, thanks for pointing out my incorrect INTENT, though shouldn't it be INOUT?  Or does INOUT only refer to the data pointed to, not the CFI structure itself?

Our internal documentation specifies explicitly that this is only for one-dimensional arrays; in the future we may expand it to include the higher-order dimensions, but our immediate needs were only for large 1-D vectors.

However, with the above proposed alternative, I receive:

error #5082: Syntax error, found ',' when expecting one of: , <END-OF-STATEMENT> ;
      TYPE(*), DIMENSION(..), INTENT(OUT)  :: A
      -------^
error #5082: Syntax error, found '.' when expecting one of: <IDENTIFIER>
      TYPE(*), DIMENSION(..), INTENT(OUT)  :: A
      --------------------^
error #6404: This name does not have a type, and must have an explicit type.  

...unless you had meant I was supposed to replace the (..) with the requested dimension, but in this case, the intention was for Fortran to pass me all of the dimension info in the CFI structure, so I can do as-needed on the C side of things.

P.S. -- The first error message is intriguing: "Error: I found 'FOO' when I was really expecting 'FOO'."  ??

0 Kudos
Highlighted
Honored Contributor I
30 Views

".. I've created a C routine which performs a memset() .. " - how do you plan to use it?

#include <stdio.h>
#include "ISO_Fortran_binding.h"

void init_data(CFI_cdesc_t *some_data)
{
    size_t data_size;
    int i;

    data_size = some_data->elem_len;
    for (i=0; i<some_data->rank; i++) {
        data_size *= some_data->dim.extent;
    }
    memset(some_data->base_addr, 0, data_size);
}
module m

   implicit none

   private

   interface

      subroutine init_data( some_data ) bind(C, name="init_data")

         implicit none

         type(*), intent(inout) :: some_data(..)

      end subroutine init_data

   end interface
   
   public :: init_data

end module m
program p

   use m, only : init_data

   blk1: block

      integer :: foo

      foo = 42
      print *, "before init_data: foo = ", foo

      call init_data( foo )
      print *, "after init_data: foo = ", foo

   end block blk1

   blk2: block

      integer :: bar(2,3)

      bar = 42
      print *, "before init_data: bar = ", bar

      call init_data( bar )
      print *, "after init_data: bar = ", bar

   end block blk2

   stop

end program p

Upon execution using compiler 17 update 1,

 before init_data: foo =  42
 after init_data: foo =  0
 before init_data: bar =  42 42 42 42 42 42
 after init_data: bar =  0 0 0 0 0 0

 

0 Kudos
Highlighted
Black Belt Retired Employee
30 Views

You may be using an old version of the compiler. ISO_Fortran_binding.h is supplied in the Fortran include folder, not the C include folder. The (..) syntax (and TYPE(*)) are part of the Fortran 2015 "Further interoperability with C" features supported in compiler version 16.

I explicitly used DIMENSION(..), assumed-rank, as this triggers passing the argument by C descriptor. It allows any rank, including scalar, to be passed. FortranFan shows how to do it.

INTENT(OUT) is correct here as your C routine doesn't ever reference the data before zeroing it.

0 Kudos