To: J3 11-144r3 From: John Reid/Bill Long Subject: Interop functions UTI TR7 Date: 2011 February 18 References: N1838, ISO/IEC 1539-1:2010 DISCUSSION The following problems have been highlighted in other papers: 1. A C descriptor may be copied in C, which is often OK, but not for allocatable arrays (see 11-126). 2. Restrictions are needed on what changes are permitted in C to the values of the members of a C descriptor (see 11-127). There is a danger that we will miss necessary restrictions. 3. Updating C descriptors is allowed under some circumstances, but not others. E.g. C descriptors for assumed-shape dummies may not be updated. Also Craig Rasmussen pointed out in an email that we are missing CFI_bounds_to_cdesc. These problems may be avoided by following Nick Maclaren's "ALTERNATIVE APPROACH" in 10-235 of replacing three of the present functions by three new ones. The functions suggested here are not exactly those of 10-235 but are similar. I believe that they will be far more convenient than the present functions and provide all the functionality that a C programmer needs to interact with Fortran. For example, it is easy to establish an assumed-shape array or an array section and there is no need for complicated rules on what is allowed and what is not allowed. Initializing, updating, or copying C descriptors in other ways will be outwith the Standard. Accessing the members will be permitted, of course. Also, altering the value of the array it describes will be permitted, but not the properties of this array. No changes are proposed for the functions CFI_address, CFI_allocate, CFI_deallocate, and CFI_is_contiguous. Paper 11-123 proposes the removal of CFI_cdesc_to_bounds. I propose to replace the other three by these four: CFI_establish_cdesc Establish a C descriptor for an assumed-shape array, an unallocated allocatable, or a pointer. CFI_setpointer Alter a C descriptor for a pointer. CFI_section Initialize a C descriptor for a section of a given array. CFI_select_part Initialize a C descriptor for a section of parts of the elements of a given array. If this paper is accepted, the edit for [16:18+] in 11-134 will not be needed. This paper addresses the issues in UTI TR7. This paper contains two sections in the EDITS part that are delineated by \begin{UTI}...\end{UTI}. These are not formally part of the EDITS, but will be inserted in the TR draft at the indicated locations when the EDITS for this paper are entered. EDITS to N1838: [9:11] In 5.2.1 Summary of contents, in the list of functions that have prototypes in ISO_Fortran_binding.h, add the names of the functions added by this paper, arranging the list in alphabetical order. In 5.2.6 Functions, delete subclauses 5.2.6.2 (CFI_create_cdesc), 5.2.6.3 (CFI_initialize_cdesc), and 5.2.6.5 (CFI_associate) and add the following subclauses to 5.2.6 alphabetically based on the function names: 5.2.6.x int CFI_establish_cdesc ( CFI_cdesc_t * dv, void * base_addr, CFI_attribute_t attribute, CFI_type_t type, size_t elem_len, CFI_rank_t rank, const CFI_dim_t dim[] ); Description. CFI_establish_cdesc establishes a C descriptor for an assumed-shape array, an assumed-length character object, an unallocated allocatable, or a pointer. The properties of this object are given by the other arguments. The argument dv shall point to a C object large enough to hold a C descriptor of the appropriate rank. It shall not point to a C descriptor that describes an object that is described by a C descriptor pointed to by a formal parameter that corresponds to a Fortran dummy argument. If it points to a C descriptor that describes an allocatable object, the object shall be unallocated. If the argument base_addr is not NULL, it is used to set the base address of the object. It shall be appropriately aligned (ISO/IEC 9899:1999 3.2) for an object of the specified type. If it is derived from the C address of a Fortran object, CFI_establish_cdesc shall establish a C descriptor for that object or a subobject of it. If the argument base_addr is NULL, CFI_establish_cdesc establishes a C descriptor for an unallocated allocatable, or a disassociated pointer. The argument attribute shall be one of CFI_attribute_assumed, CFI_attribute_allocatable, or CFI_attribute_pointer. If the argument attribute is CFI_attribute_assumed, the argument base_addr shall not be NULL. If the argument attribute is CFI_attribute_allocatable, the argument base_addr shall be NULL. If the argument attribute is CFI_attribute_pointer and the argument base_addr is the C address of a Fortran object, the Fortran object shall have the TARGET attribute. The argument type shall be one of the type names in Table 5.2. The argument elem_len is ignored unless type is CFI_type_other or a character type. If the type is CFI_type_other, elem_len shall be greater than zero and equal to the size of an element of the object. If the object is a Fortran character, the value of elem_len shall be the length of an element of the character object. The argument rank shall be between 0 and 15 inclusive. If the argument rank is zero or the argument base_addr is NULL, the argument dim is ignored; otherwise, it points to an array with rank elements specifying the dim information. The function returns an error indicator. Example 1. The following code fragment establishes a C descriptor for an unallocated rank-one allocatable array to pass to Fortran for allocation there. CFI_rank_t rank; CFI_dim_t dim[1]; CFI_CDESC_T(1) field; int ind; rank = 1; ind = CFI_establish_cdesc ( &field, NULL, CFI_attribute_allocatable, CFI_type_double, 0, rank, dim ); Example 2. If source already points to a C descriptor for the Fortran array a declared thus: type,bind(c) :: t REAL(C_DOUBLE) x complex(C_DOUBLE_COMPLEX) y end type type(t) a(100) the following code fragment establishes a C descriptor for the array a(:)%y. struct { double x; double complex y;} t; CFI_dim_t dim[1]; CFI_CDESC_T(1) component; int ind; dim[0]->lower_bound = 0; dim[0]->extent = 100; dim[0]->sm = sizeof(struct t); ind = CFI_establish_cdesc ( &component, (char *)source->base_addr+offsetof(struct t, y), CFI_attribute_assumed, CFI_type_double_Complex, 0, source->rank, dim ); 5.2.6.x int CFI_setpointer ( CFI_cdesc_t * ptr_dv, CFI_cdesc_t * source, const CFI_dim_t dim[]); Description. CFI_setpointer updates a C descriptor for a Fortran pointer. The argument ptr_dv shall point to a C descriptor for a Fortran pointer. It is updated using information from the source and dim arguments. The argument source shall be NULL or point to a C descriptor for an assumed-shape array, an allocatable object, or a pointer object. If source is NULL or points to a C descriptor for an allocatable object that is not allocated or a pointer that is not associated, \cf{ptr_dv} becomes a disassociated pointer. If source is not NULL, the elem_len, rank, and type members of the source C descriptor shall be the same as the corresponding members of the ptr_dv C descriptor. If source is not NULL and the base_addr of the source C descriptor is the C address of a Fortran object, the Fortran object shall have the TARGET attribute. \begin{UTI}{TR15} Malcolm Comment: Actually, I disagree with this, because this does not apply to Fortran code (one just gives the dummy argument the TARGET attribute and it becomes targettable). Maybe "if \cf{ptr_dv} is not a local variable" plus some more words to make any C pointers go undefined on exit from this procedure. Please make a UTI to this effect. \end{UTI} If dim is NULL or the rank is zero, the target of \cf{ptr_dv} becomes a C descriptor for the object described by the source C descriptor. Otherwise, dim shall point to an array of rank elements; it specifies the dim information of a section of the object described by the source C descriptor. This section is the object described by the updated descriptor pointed to by ptr_dv. The function returns an error indicator. Example. If ptr already points to a C descriptor for an array pointer of rank 1, the following code makes it point instead to the section with bounds and stride (1:100:5). CFI_dim_t dim[1]; int ind; dim[0]->lower_bound = 1; dim[0]->extent = 20; dim[0]->sm = 5*ptr->dim[0].sm; ind = CFI_setpointer ( &ptr, &ptr, dim ); \begin{UTI}{TR16} Malcolm Comment: I don't see why CFI_setpointer has a half-baked array sectioning facility built in, viz one that does not allow the section to have lesser rank than the source. CFI_section allows that (accidentally?) and also seems to allow nonsensical rank changing! Some work will be required to straighten these out. Summary of related comments made during plenary discussion: It would be helpful to create a list of all of the possible forms of pointer association and argument association involving dope vectors, and illustrate how each is accomplished with corresponding calls to these functions. It is possible the exercise would lead to a slightly changed set of functions. \end{UTI} 5.2.6.x int CFI_select_part ( CFI_cdesc_t * result, CFI_attribute_t attribute, const CFI_cdesc_t * source, CFI_type_t type, size_t displacement, size_t elem_len ); Description. CFI_component establishes a C descriptor for an array whose elements are parts of the corresponding elements of an array. The parts may be a component of a structure, a substring, or the real or imaginary part of a complex value. The argument result shall point to a C object large enough to hold a C descriptor of the appropriate rank. It shall not point to a C descriptor that describes an object that is described by a C descriptor pointed to by a formal parameter that corresponds to a Fortran dummy argument. If it points to a C descriptor that describes an allocatable object, the object shall be unallocated. The argument attribute shall be CFI_attribute_assumed or CFI_attribute_pointer and determines whether the C descriptor pointed to by result on exit describes an assumed-shape array or array pointer. The C descriptor pointed to by source shall describe an assumed-shape array, an allocated allocatable array, or an associated pointer array. The values of the arguments displacement and elem_len shall be between 0 and the elem_len member of the C descriptor pointed to by source. On exit, the C descriptor pointed to by result will describe an array whose type is given by the argument type, and whose base address is the base address of the source array plus the value of the argument displacement. The resulting base address shall be appropriately aligned (ISO/IEC 9899:1999 3.2) for an object of the specified type. The argument elem_len is ignored unless type is CFI_type_other or a character type. If the type is CFI_type_other, elem_len shall be greater than zero and equal to the size of an element of the object. If the object is a Fortran character, the value of elem_len shall be the length of an element of the character object. The function returns an error indicator. Example. If source already points to a C descriptor for the Fortran array a declared thus: type,bind(c):: t real(C_DOUBLE) :: x complex(C_DOUBLE_COMPLEX) :: y end type type(t) a(100) the following code fragment establishes a C descriptor for the array a(:)%y. double d; CFI_CDESC_T(1) component,; int ind; ind = CFI_select_part ( &component, CFI_attribute_assumed, &source, CFI_type_double_complex, sizeof(d), 0 ); 5.2.6.x int CFI_section ( CFI_cdesc_t * result, CFI_attribute_t attribute, const CFI_cdesc_t * source, const CFI_dim_t dim[] ); Description. CFI_section establishes the C descriptor pointed to by result to refer to a section of an array pointed to by source. The argument result shall point to a C object large enough to hold a C descriptor of the appropriate rank. It shall not point to a C descriptor that describes an object that is described by a C descriptor pointed to by a formal parameter that corresponds to a Fortran dummy argument. If it points to a C descriptor that describes an allocatable object, the object shall be unallocated. The argument attribute shall be CFI_attribute_assumed or CFI_attribute_pointer and determines whether the C descriptor pointed to by result on exit describes an assumed-shape array or pointer object. The C descriptor pointed to by source shall describe an assumed-shape array, an allocated allocatable array, or an associated pointer. The argument dim points to an array of rank elements specifying the dim information of the array section. The function returns an error indicator. Example. If source already points to a C descriptor for the rank-one Fortran array A, the following code fragment establishes a C descriptor for the array section A(1:10:5). CFI_dim_t dim[1]; CFI_CDESC_T(1) section; int ind; dim[0]->lower_bound = 0; dim[0]->extent = 2; dim[0]->sm = 5*source->dim[0].sm; ind = CFI_section ( §ion, CFI_attribute_assumed, &source, dim ); [16:7-18] Replace 5.2.7 Restrictions on the use of C descriptors by 5.2.7 Use of C descriptors A C descriptor shall not be initialized, updated or copied other than by calling the functions specified here. A C descriptor that is pointed to by a formal parameter that corresponds to a Fortran dummy argument with the INTENT(IN) attribute shall not be updated. Calling CFI_allocate or CFI_deallocate for a C descriptor changes the allocation status of the Fortran variable it describes and causes the allocation status of any associated allocatable variable to change accordingly (6.7.1.3 of ISO/IEC 1539-1:2010). A C descriptor that is pointer to by a formal parameter or actual argument that corresponds to a Fortran dummy argument in a BIND(C) interface shall describe an object that is acceptable to both Fortran and C with the type specified in its type member. 5.2.7+ Restrictions on lifetimes When a Fortran object is deallocated, execution of its host instance is completed, or its allocation or association status becomes undefined, all C descriptors and C pointers to any part of it become undefined, and any further use of them is undefined behavior (ISO/IEC 9899:1999 3.4.3). A C descriptor that is pointed to by a formal parameter that corresponds to a Fortran dummy argument becomes undefined on return from a call to the function from Fortran. If the dummy argument does not have any of the TARGET, ASYNCHRONOUS or VOLATILE attributes, all C pointers to any part of the object it describes become undefined on return from the call, and any further use of them is undefined behavior. If a pointer to a C descriptor is passed as an actual argument, the lifetime of the C descriptor and that of the object it describes (ISO/IEC 9899:1999 6.2.4) shall not end before the return from the function call. A Fortran pointer variable that is associated with the object described by a C descriptor shall not be accessed beyond the end of the lifetime of the C descriptor and the object it describes.