gcc/libgfortran/runtime/ISO_Fortran_binding.c
Sandra Loosemore 93b6b2f614 libgfortran: Further fixes for GFC/CFI descriptor conversions.
This patch is for:
PR100907 - Bind(c): failure handling wide character
PR100911 - Bind(c): failure handling C_PTR
PR100914 - Bind(c): errors handling complex
PR100915 - Bind(c): failure handling C_FUNPTR
PR100917 - Bind(c): errors handling long double real

All of these problems are related to the GFC descriptors constructed
by the Fortran front end containing ambigous or incomplete
information.  This patch does not attempt to change the GFC data
structure or the front end, and only makes the runtime interpret it in
more reasonable ways.  It's not a complete fix for any of the listed
issues.

The Fortran front end does not distinguish between C_PTR and
C_FUNPTR, mapping both onto BT_VOID.  That is what this patch does also.

The other bugs are related to GFC descriptors only containing elem_len
and not kind.  For complex types, the elem_len needs to be divided by
2 and then mapped onto a real kind.  On x86 targets, the kind
corresponding to C long double is different than its elem_len; since
we cannot accurately disambiguate between a 16-byte kind 10 long
double from __float128, this patch arbitrarily prefers to interpret that as
the standard long double type rather than the GNU extension.

Similarly, for character types, the GFC descriptor cannot distinguish
between character(kind=c_char, len=4) and character(kind=ucs4, len=1).
But since the front end currently rejects anything other than len=1
(PR92482) this patch uses the latter interpretation.

2021-09-01  Sandra Loosemore  <sandra@codesourcery.com>
	    José Rui Faustino de Sousa  <jrfsousa@gmail.com>

gcc/testsuite/
	PR fortran/100911
	PR fortran/100915
	PR fortran/100916
	* gfortran.dg/PR100911.c: New file.
	* gfortran.dg/PR100911.f90: New file.
	* gfortran.dg/PR100914.c: New file.
	* gfortran.dg/PR100914.f90: New file.
	* gfortran.dg/PR100915.c: New file.
	* gfortran.dg/PR100915.f90: New file.

libgfortran/
	PR fortran/100907
	PR fortran/100911
	PR fortran/100914
	PR fortran/100915
	PR fortran/100917
	* ISO_Fortran_binding-1-tmpl.h (CFI_type_cfunptr): Make equivalent
	to CFI_type_cptr.
	* runtime/ISO_Fortran_binding.c (cfi_desc_to_gfc_desc): Fix
	handling of CFI_type_cptr and CFI_type_cfunptr.  Additional error
	checking and code cleanup.
	(gfc_desc_to_cfi_desc): Likewise.  Also correct kind mapping
	for character, complex, and long double types.
2021-09-02 16:41:02 -07:00

1024 lines
30 KiB
C

/* Functions to convert descriptors between CFI and gfortran
and the CFI function declarations whose prototypes appear
in ISO_Fortran_binding.h.
Copyright (C) 2018-2021 Free Software Foundation, Inc.
Contributed by Daniel Celis Garza <celisdanieljr@gmail.com>
and Paul Thomas <pault@gcc.gnu.org>
This file is part of the GNU Fortran runtime library (libgfortran).
Libgfortran is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public
License as published by the Free Software Foundation; either
version 3 of the License, or (at your option) any later version.
Libgfortran is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
Under Section 7 of GPL version 3, you are granted additional
permissions described in the GCC Runtime Library Exception, version
3.1, as published by the Free Software Foundation.
You should have received a copy of the GNU General Public License and
a copy of the GCC Runtime Library Exception along with this program;
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
<http://www.gnu.org/licenses/>. */
#include "libgfortran.h"
#include "ISO_Fortran_binding.h"
#include <string.h>
#include <inttypes.h> /* for PRIiPTR */
extern void cfi_desc_to_gfc_desc (gfc_array_void *, CFI_cdesc_t **);
export_proto(cfi_desc_to_gfc_desc);
void
cfi_desc_to_gfc_desc (gfc_array_void *d, CFI_cdesc_t **s_ptr)
{
signed char type;
size_t size;
int n;
CFI_cdesc_t *s = *s_ptr;
if (!s)
return;
/* Verify descriptor. */
switch (s->attribute)
{
case CFI_attribute_pointer:
case CFI_attribute_allocatable:
break;
case CFI_attribute_other:
if (s->base_addr)
break;
runtime_error ("Nonallocatable, nonpointer actual argument to BIND(C) "
"dummy argument where the effective argument is either "
"not allocated or not associated");
break;
default:
runtime_error ("Invalid attribute type %d in CFI_cdesc_t descriptor",
(int) s->attribute);
break;
}
GFC_DESCRIPTOR_DATA (d) = s->base_addr;
/* Correct the unfortunate difference in order with types. */
type = (signed char)(s->type & CFI_type_mask);
switch (type)
{
case CFI_type_Character:
type = BT_CHARACTER;
break;
case CFI_type_struct:
type = BT_DERIVED;
break;
case CFI_type_cptr:
/* FIXME: PR 100915. GFC descriptors do not distinguish between
CFI_type_cptr and CFI_type_cfunptr. */
type = BT_VOID;
break;
default:
break;
}
GFC_DESCRIPTOR_TYPE (d) = type;
GFC_DESCRIPTOR_SIZE (d) = s->elem_len;
d->dtype.version = 0;
if (s->rank < 0 || s->rank > CFI_MAX_RANK)
internal_error (NULL, "Invalid rank in descriptor");
GFC_DESCRIPTOR_RANK (d) = (signed char)s->rank;
d->dtype.attribute = (signed short)s->attribute;
if (s->rank)
{
if ((size_t)s->dim[0].sm % s->elem_len)
d->span = (index_type)s->dim[0].sm;
else
d->span = (index_type)s->elem_len;
}
d->offset = 0;
if (GFC_DESCRIPTOR_DATA (d))
for (n = 0; n < GFC_DESCRIPTOR_RANK (d); n++)
{
CFI_index_t lb = 1;
if (s->attribute != CFI_attribute_other)
lb = s->dim[n].lower_bound;
GFC_DESCRIPTOR_LBOUND(d, n) = (index_type)lb;
GFC_DESCRIPTOR_UBOUND(d, n) = (index_type)(s->dim[n].extent + lb - 1);
GFC_DESCRIPTOR_STRIDE(d, n) = (index_type)(s->dim[n].sm / s->elem_len);
d->offset -= GFC_DESCRIPTOR_STRIDE(d, n) * GFC_DESCRIPTOR_LBOUND(d, n);
}
}
extern void gfc_desc_to_cfi_desc (CFI_cdesc_t **, const gfc_array_void *);
export_proto(gfc_desc_to_cfi_desc);
void
gfc_desc_to_cfi_desc (CFI_cdesc_t **d_ptr, const gfc_array_void *s)
{
int n;
CFI_cdesc_t *d;
signed char type, kind;
/* Play it safe with allocation of the flexible array member 'dim'
by setting the length to CFI_MAX_RANK. This should not be necessary
but valgrind complains accesses after the allocated block. */
if (*d_ptr == NULL)
d = calloc (1, (sizeof (CFI_cdesc_t)
+ (CFI_type_t)(CFI_MAX_RANK * sizeof (CFI_dim_t))));
else
d = *d_ptr;
/* Verify descriptor. */
switch (s->dtype.attribute)
{
case CFI_attribute_pointer:
case CFI_attribute_allocatable:
break;
case CFI_attribute_other:
if (s->base_addr)
break;
runtime_error ("Nonallocatable, nonpointer actual argument to BIND(C) "
"dummy argument where the effective argument is either "
"not allocated or not associated");
break;
default:
internal_error (NULL, "Invalid attribute in gfc_array descriptor");
break;
}
d->base_addr = GFC_DESCRIPTOR_DATA (s);
d->elem_len = GFC_DESCRIPTOR_SIZE (s);
if (d->elem_len <= 0)
internal_error (NULL, "Invalid size in descriptor");
d->version = CFI_VERSION;
d->rank = (CFI_rank_t)GFC_DESCRIPTOR_RANK (s);
if (d->rank < 0 || d->rank > CFI_MAX_RANK)
internal_error (NULL, "Invalid rank in descriptor");
d->attribute = (CFI_attribute_t)s->dtype.attribute;
type = GFC_DESCRIPTOR_TYPE (s);
switch (type)
{
case BT_CHARACTER:
d->type = CFI_type_Character;
break;
case BT_DERIVED:
d->type = CFI_type_struct;
break;
case BT_VOID:
/* FIXME: PR 100915. GFC descriptors do not distinguish between
CFI_type_cptr and CFI_type_cfunptr. */
d->type = CFI_type_cptr;
break;
default:
d->type = (CFI_type_t)type;
break;
}
switch (d->type)
{
case CFI_type_Integer:
case CFI_type_Logical:
case CFI_type_Real:
kind = (signed char)d->elem_len;
break;
case CFI_type_Complex:
kind = (signed char)(d->elem_len >> 1);
break;
case CFI_type_Character:
/* FIXME: we can't distinguish between kind/len because
the GFC descriptor only encodes the elem_len..
Until PR92482 is fixed, assume elem_len refers to the
character size and not the string length. */
kind = (signed char)d->elem_len;
break;
case CFI_type_struct:
case CFI_type_cptr:
case CFI_type_other:
/* FIXME: PR 100915. GFC descriptors do not distinguish between
CFI_type_cptr and CFI_type_cfunptr. */
kind = 0;
break;
default:
internal_error (NULL, "Invalid type in descriptor");
}
if (kind < 0)
internal_error (NULL, "Invalid kind in descriptor");
/* FIXME: This is PR100917. Because the GFC descriptor encodes only the
elem_len and not the kind, we get into trouble with long double kinds
that do not correspond directly to the elem_len, specifically the
kind 10 80-bit long double on x86 targets. On x86_64, this has size
16 and cannot be differentiated from true __float128. Prefer the
standard long double type over the GNU extension in that case. */
if (d->type == CFI_type_Real && kind == sizeof (long double))
d->type = CFI_type_long_double;
else if (d->type == CFI_type_Complex && kind == sizeof (long double))
d->type = CFI_type_long_double_Complex;
else
d->type = (CFI_type_t)(d->type
+ ((CFI_type_t)kind << CFI_type_kind_shift));
if (d->base_addr)
/* Full pointer or allocatable arrays retain their lower_bounds. */
for (n = 0; n < GFC_DESCRIPTOR_RANK (s); n++)
{
if (d->attribute != CFI_attribute_other)
d->dim[n].lower_bound = (CFI_index_t)GFC_DESCRIPTOR_LBOUND(s, n);
else
d->dim[n].lower_bound = 0;
/* Assumed size arrays have gfc ubound == 0 and CFI extent = -1. */
if (n == GFC_DESCRIPTOR_RANK (s) - 1
&& GFC_DESCRIPTOR_LBOUND(s, n) == 1
&& GFC_DESCRIPTOR_UBOUND(s, n) == 0)
d->dim[n].extent = -1;
else
d->dim[n].extent = (CFI_index_t)GFC_DESCRIPTOR_UBOUND(s, n)
- (CFI_index_t)GFC_DESCRIPTOR_LBOUND(s, n) + 1;
d->dim[n].sm = (CFI_index_t)(GFC_DESCRIPTOR_STRIDE(s, n) * s->span);
}
if (*d_ptr == NULL)
*d_ptr = d;
}
void *CFI_address (const CFI_cdesc_t *dv, const CFI_index_t subscripts[])
{
int i;
char *base_addr = (char *)dv->base_addr;
if (unlikely (compile_options.bounds_check))
{
/* C descriptor must not be NULL. */
if (dv == NULL)
{
fprintf (stderr, "CFI_address: C descriptor is NULL.\n");
return NULL;
}
/* Base address of C descriptor must not be NULL. */
if (dv->base_addr == NULL)
{
fprintf (stderr, "CFI_address: base address of C descriptor "
"must not be NULL.\n");
return NULL;
}
}
/* Return base address if C descriptor is a scalar. */
if (dv->rank == 0)
return dv->base_addr;
/* Calculate the appropriate base address if dv is not a scalar. */
else
{
/* Base address is the C address of the element of the object
specified by subscripts. */
for (i = 0; i < dv->rank; i++)
{
CFI_index_t idx = subscripts[i] - dv->dim[i].lower_bound;
if (unlikely (compile_options.bounds_check)
&& ((dv->dim[i].extent != -1 && idx >= dv->dim[i].extent)
|| idx < 0))
{
fprintf (stderr, "CFI_address: subscripts[%d] is out of "
"bounds. For dimension = %d, subscripts = %d, "
"lower_bound = %" PRIiPTR ", upper bound = %" PRIiPTR
", extent = %" PRIiPTR "\n",
i, i, (int)subscripts[i],
(ptrdiff_t)dv->dim[i].lower_bound,
(ptrdiff_t)(dv->dim[i].extent - dv->dim[i].lower_bound),
(ptrdiff_t)dv->dim[i].extent);
return NULL;
}
base_addr = base_addr + (CFI_index_t)(idx * dv->dim[i].sm);
}
}
return (void *)base_addr;
}
int
CFI_allocate (CFI_cdesc_t *dv, const CFI_index_t lower_bounds[],
const CFI_index_t upper_bounds[], size_t elem_len)
{
if (unlikely (compile_options.bounds_check))
{
/* C descriptor must not be NULL. */
if (dv == NULL)
{
fprintf (stderr, "CFI_allocate: C descriptor is NULL.\n");
return CFI_INVALID_DESCRIPTOR;
}
/* The C descriptor must be for an allocatable or pointer object. */
if (dv->attribute == CFI_attribute_other)
{
fprintf (stderr, "CFI_allocate: The object of the C descriptor "
"must be a pointer or allocatable variable.\n");
return CFI_INVALID_ATTRIBUTE;
}
/* Base address of C descriptor must be NULL. */
if (dv->base_addr != NULL)
{
fprintf (stderr, "CFI_allocate: Base address of C descriptor "
"must be NULL.\n");
return CFI_ERROR_BASE_ADDR_NOT_NULL;
}
}
/* If the type is a Fortran character type, the descriptor's element
length is replaced by the elem_len argument. */
if (dv->type == CFI_type_char || dv->type == CFI_type_ucs4_char)
dv->elem_len = elem_len;
/* Dimension information and calculating the array length. */
size_t arr_len = 1;
/* If rank is greater than 0, lower_bounds and upper_bounds are used. They're
ignored otherwise. */
if (dv->rank > 0)
{
if (unlikely (compile_options.bounds_check)
&& (lower_bounds == NULL || upper_bounds == NULL))
{
fprintf (stderr, "CFI_allocate: The lower_bounds and "
"upper_bounds arguments must be non-NULL when "
"rank is greater than zero.\n");
return CFI_INVALID_EXTENT;
}
for (int i = 0; i < dv->rank; i++)
{
dv->dim[i].lower_bound = lower_bounds[i];
dv->dim[i].extent = upper_bounds[i] - dv->dim[i].lower_bound + 1;
dv->dim[i].sm = dv->elem_len * arr_len;
arr_len *= dv->dim[i].extent;
}
}
dv->base_addr = calloc (arr_len, dv->elem_len);
if (dv->base_addr == NULL)
{
fprintf (stderr, "CFI_allocate: Failure in memory allocation.\n");
return CFI_ERROR_MEM_ALLOCATION;
}
return CFI_SUCCESS;
}
int
CFI_deallocate (CFI_cdesc_t *dv)
{
if (unlikely (compile_options.bounds_check))
{
/* C descriptor must not be NULL */
if (dv == NULL)
{
fprintf (stderr, "CFI_deallocate: C descriptor is NULL.\n");
return CFI_INVALID_DESCRIPTOR;
}
/* Base address must not be NULL. */
if (dv->base_addr == NULL)
{
fprintf (stderr, "CFI_deallocate: Base address is already NULL.\n");
return CFI_ERROR_BASE_ADDR_NULL;
}
/* C descriptor must be for an allocatable or pointer variable. */
if (dv->attribute == CFI_attribute_other)
{
fprintf (stderr, "CFI_deallocate: C descriptor must describe a "
"pointer or allocatable object.\n");
return CFI_INVALID_ATTRIBUTE;
}
}
/* Free and nullify memory. */
free (dv->base_addr);
dv->base_addr = NULL;
return CFI_SUCCESS;
}
int CFI_establish (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_index_t extents[])
{
if (unlikely (compile_options.bounds_check))
{
/* C descriptor must not be NULL. */
if (dv == NULL)
{
fprintf (stderr, "CFI_establish: C descriptor is NULL.\n");
return CFI_INVALID_DESCRIPTOR;
}
/* Rank must be between 0 and CFI_MAX_RANK. */
if (rank < 0 || rank > CFI_MAX_RANK)
{
fprintf (stderr, "CFI_establish: Rank must be between 0 and %d, "
"0 < rank (0 !< %d).\n", CFI_MAX_RANK, (int)rank);
return CFI_INVALID_RANK;
}
/* If base address is not NULL, the established C descriptor is for a
nonallocatable entity. */
if (attribute == CFI_attribute_allocatable && base_addr != NULL)
{
fprintf (stderr, "CFI_establish: If base address is not NULL, "
"the established C descriptor must be "
"for a nonallocatable entity.\n");
return CFI_INVALID_ATTRIBUTE;
}
}
dv->base_addr = base_addr;
if (type == CFI_type_char || type == CFI_type_ucs4_char
|| type == CFI_type_struct || type == CFI_type_other)
{
/* Note that elem_len has type size_t, which is unsigned. */
if (unlikely (compile_options.bounds_check) && elem_len == 0)
{
fprintf (stderr, "CFI_establish: The supplied elem_len must "
"be greater than zero.\n");
return CFI_INVALID_ELEM_LEN;
}
dv->elem_len = elem_len;
}
else if (type == CFI_type_cptr)
dv->elem_len = sizeof (void *);
else if (type == CFI_type_cfunptr)
dv->elem_len = sizeof (void (*)(void));
else if (unlikely (compile_options.bounds_check) && type < 0)
{
fprintf (stderr, "CFI_establish: Invalid type (type = %d).\n",
(int)type);
return CFI_INVALID_TYPE;
}
else
{
/* base_type describes the intrinsic type with kind parameter. */
size_t base_type = type & CFI_type_mask;
/* base_type_size is the size in bytes of the variable as given by its
* kind parameter. */
size_t base_type_size = (type - base_type) >> CFI_type_kind_shift;
/* Kind type 10 maps onto the 80-bit long double encoding on x86.
Note that this has different storage size for -m32 than -m64. */
if (base_type_size == 10)
base_type_size = sizeof (long double);
/* Complex numbers are twice the size of their real counterparts. */
if (base_type == CFI_type_Complex)
base_type_size *= 2;
dv->elem_len = base_type_size;
}
dv->version = CFI_VERSION;
dv->rank = rank;
dv->attribute = attribute;
dv->type = type;
/* Extents must not be NULL if rank is greater than zero and base_addr is not
NULL */
if (rank > 0 && base_addr != NULL)
{
if (unlikely (compile_options.bounds_check) && extents == NULL)
{
fprintf (stderr, "CFI_establish: Extents must not be NULL "
"if rank is greater than zero and base address is "
"not NULL.\n");
return CFI_INVALID_EXTENT;
}
for (int i = 0; i < rank; i++)
{
/* The standard requires all dimensions to be nonnegative.
Apparently you can have an extent-zero dimension but can't
construct an assumed-size array with -1 as the extent
of the last dimension. */
if (unlikely (compile_options.bounds_check) && extents[i] < 0)
{
fprintf (stderr, "CFI_establish: Extents must be nonnegative "
"(extents[%d] = %" PRIiPTR ").\n",
i, (ptrdiff_t)extents[i]);
return CFI_INVALID_EXTENT;
}
dv->dim[i].lower_bound = 0;
dv->dim[i].extent = extents[i];
if (i == 0)
dv->dim[i].sm = dv->elem_len;
else
{
CFI_index_t extents_product = 1;
for (int j = 0; j < i; j++)
extents_product *= extents[j];
dv->dim[i].sm = (CFI_index_t)(dv->elem_len * extents_product);
}
}
}
return CFI_SUCCESS;
}
int CFI_is_contiguous (const CFI_cdesc_t *dv)
{
if (unlikely (compile_options.bounds_check))
{
/* C descriptor must not be NULL. */
if (dv == NULL)
{
fprintf (stderr, "CFI_is_contiguous: C descriptor is NULL.\n");
return 0;
}
/* Base address must not be NULL. */
if (dv->base_addr == NULL)
{
fprintf (stderr, "CFI_is_contiguous: Base address of C descriptor "
"is already NULL.\n");
return 0;
}
/* Must be an array. */
if (dv->rank <= 0)
{
fprintf (stderr, "CFI_is_contiguous: C descriptor must describe "
"an array.\n");
return 0;
}
}
/* Assumed size arrays are always contiguous. */
if (dv->rank > 0 && dv->dim[dv->rank - 1].extent == -1)
return 1;
/* If an array is not contiguous the memory stride is different to
the element length. */
for (int i = 0; i < dv->rank; i++)
{
if (i == 0 && dv->dim[i].sm == (CFI_index_t)dv->elem_len)
continue;
else if (i > 0
&& dv->dim[i].sm == (CFI_index_t)(dv->dim[i - 1].sm
* dv->dim[i - 1].extent))
continue;
return 0;
}
/* Array sections are guaranteed to be contiguous by the previous test. */
return 1;
}
int CFI_section (CFI_cdesc_t *result, const CFI_cdesc_t *source,
const CFI_index_t lower_bounds[],
const CFI_index_t upper_bounds[], const CFI_index_t strides[])
{
/* Dimension information. */
CFI_index_t lower[CFI_MAX_RANK];
CFI_index_t upper[CFI_MAX_RANK];
CFI_index_t stride[CFI_MAX_RANK];
int zero_count = 0;
if (unlikely (compile_options.bounds_check))
{
/* C descriptors must not be NULL. */
if (source == NULL)
{
fprintf (stderr, "CFI_section: Source must not be NULL.\n");
return CFI_INVALID_DESCRIPTOR;
}
if (result == NULL)
{
fprintf (stderr, "CFI_section: Result must not be NULL.\n");
return CFI_INVALID_DESCRIPTOR;
}
/* Base address of source must not be NULL. */
if (source->base_addr == NULL)
{
fprintf (stderr, "CFI_section: Base address of source must "
"not be NULL.\n");
return CFI_ERROR_BASE_ADDR_NULL;
}
/* Result must not be an allocatable array. */
if (result->attribute == CFI_attribute_allocatable)
{
fprintf (stderr, "CFI_section: Result must not describe an "
"allocatable array.\n");
return CFI_INVALID_ATTRIBUTE;
}
/* Source must be some form of array (nonallocatable nonpointer array,
allocated allocatable array or an associated pointer array). */
if (source->rank <= 0)
{
fprintf (stderr, "CFI_section: Source must describe an array.\n");
return CFI_INVALID_RANK;
}
/* Element lengths of source and result must be equal. */
if (result->elem_len != source->elem_len)
{
fprintf (stderr, "CFI_section: The element lengths of "
"source (source->elem_len = %" PRIiPTR ") and result "
"(result->elem_len = %" PRIiPTR ") must be equal.\n",
(ptrdiff_t)source->elem_len, (ptrdiff_t)result->elem_len);
return CFI_INVALID_ELEM_LEN;
}
/* Types must be equal. */
if (result->type != source->type)
{
fprintf (stderr, "CFI_section: Types of source "
"(source->type = %d) and result (result->type = %d) "
"must be equal.\n", source->type, result->type);
return CFI_INVALID_TYPE;
}
}
/* Stride of zero in the i'th dimension means rank reduction in that
dimension. */
for (int i = 0; i < source->rank; i++)
{
if (strides[i] == 0)
zero_count++;
}
/* Rank of result must be equal the the rank of source minus the number of
* zeros in strides. */
if (unlikely (compile_options.bounds_check)
&& result->rank != source->rank - zero_count)
{
fprintf (stderr, "CFI_section: Rank of result must be equal to the "
"rank of source minus the number of zeros in strides "
"(result->rank = source->rank - zero_count, %d != %d "
"- %d).\n", result->rank, source->rank, zero_count);
return CFI_INVALID_RANK;
}
/* Lower bounds. */
if (lower_bounds == NULL)
{
for (int i = 0; i < source->rank; i++)
lower[i] = source->dim[i].lower_bound;
}
else
{
for (int i = 0; i < source->rank; i++)
lower[i] = lower_bounds[i];
}
/* Upper bounds. */
if (upper_bounds == NULL)
{
if (unlikely (compile_options.bounds_check)
&& source->dim[source->rank - 1].extent == -1)
{
fprintf (stderr, "CFI_section: Source must not be an assumed-size "
"array if upper_bounds is NULL.\n");
return CFI_INVALID_EXTENT;
}
for (int i = 0; i < source->rank; i++)
upper[i] = source->dim[i].lower_bound + source->dim[i].extent - 1;
}
else
{
for (int i = 0; i < source->rank; i++)
upper[i] = upper_bounds[i];
}
/* Stride */
if (strides == NULL)
{
for (int i = 0; i < source->rank; i++)
stride[i] = 1;
}
else
{
for (int i = 0; i < source->rank; i++)
{
stride[i] = strides[i];
/* If stride[i] == 0 then lower[i] and upper[i] must be equal. */
if (unlikely (compile_options.bounds_check)
&& stride[i] == 0 && lower[i] != upper[i])
{
fprintf (stderr, "CFI_section: If strides[%d] = 0, then "
"lower_bounds[%d] = %" PRIiPTR " and "
"upper_bounds[%d] = %" PRIiPTR " must be equal.\n",
i, i, (ptrdiff_t)lower_bounds[i], i,
(ptrdiff_t)upper_bounds[i]);
return CFI_ERROR_OUT_OF_BOUNDS;
}
}
}
/* Check that section upper and lower bounds are within the array bounds. */
if (unlikely (compile_options.bounds_check))
for (int i = 0; i < source->rank; i++)
{
bool assumed_size
= (i == source->rank - 1 && source->dim[i].extent == -1);
CFI_index_t ub
= source->dim[i].lower_bound + source->dim[i].extent - 1;
if (lower_bounds != NULL
&& (lower[i] < source->dim[i].lower_bound
|| (!assumed_size && lower[i] > ub)))
{
fprintf (stderr, "CFI_section: Lower bounds must be within "
"the bounds of the Fortran array "
"(source->dim[%d].lower_bound "
"<= lower_bounds[%d] <= source->dim[%d].lower_bound "
"+ source->dim[%d].extent - 1, "
"%" PRIiPTR " <= %" PRIiPTR " <= %" PRIiPTR ").\n",
i, i, i, i,
(ptrdiff_t)source->dim[i].lower_bound,
(ptrdiff_t)lower[i],
(ptrdiff_t)ub);
return CFI_ERROR_OUT_OF_BOUNDS;
}
if (upper_bounds != NULL
&& (upper[i] < source->dim[i].lower_bound
|| (!assumed_size && upper[i] > ub)))
{
fprintf (stderr, "CFI_section: Upper bounds must be within "
"the bounds of the Fortran array "
"(source->dim[%d].lower_bound "
"<= upper_bounds[%d] <= source->dim[%d].lower_bound "
"+ source->dim[%d].extent - 1, "
"%" PRIiPTR " !<= %" PRIiPTR " !<= %" PRIiPTR ").\n",
i, i, i, i,
(ptrdiff_t)source->dim[i].lower_bound,
(ptrdiff_t)upper[i],
(ptrdiff_t)ub);
return CFI_ERROR_OUT_OF_BOUNDS;
}
if (upper[i] < lower[i] && stride[i] >= 0)
{
fprintf (stderr, "CFI_section: If the upper bound is smaller than "
"the lower bound for a given dimension (upper[%d] < "
"lower[%d], %" PRIiPTR " < %" PRIiPTR "), then the "
"stride for said dimension must be negative "
"(stride[%d] < 0, %" PRIiPTR " < 0).\n",
i, i, (ptrdiff_t)upper[i], (ptrdiff_t)lower[i],
i, (ptrdiff_t)stride[i]);
return CFI_INVALID_STRIDE;
}
}
/* Set the base address. We have to compute this first in the case
where source == result, before we overwrite the dimension data. */
result->base_addr = CFI_address (source, lower);
/* Set the appropriate dimension information that gives us access to the
* data. */
for (int i = 0, o = 0; i < source->rank; i++)
{
if (stride[i] == 0)
continue;
result->dim[o].lower_bound = 0;
result->dim[o].extent = 1 + (upper[i] - lower[i])/stride[i];
result->dim[o].sm = stride[i] * source->dim[i].sm;
o++;
}
return CFI_SUCCESS;
}
int CFI_select_part (CFI_cdesc_t *result, const CFI_cdesc_t *source,
size_t displacement, size_t elem_len)
{
if (unlikely (compile_options.bounds_check))
{
/* C descriptors must not be NULL. */
if (source == NULL)
{
fprintf (stderr, "CFI_select_part: Source must not be NULL.\n");
return CFI_INVALID_DESCRIPTOR;
}
if (result == NULL)
{
fprintf (stderr, "CFI_select_part: Result must not be NULL.\n");
return CFI_INVALID_DESCRIPTOR;
}
/* Attribute of result will be CFI_attribute_other or
CFI_attribute_pointer. */
if (result->attribute == CFI_attribute_allocatable)
{
fprintf (stderr, "CFI_select_part: Result must not describe an "
"allocatable object (result->attribute != %d).\n",
CFI_attribute_allocatable);
return CFI_INVALID_ATTRIBUTE;
}
/* Base address of source must not be NULL. */
if (source->base_addr == NULL)
{
fprintf (stderr, "CFI_select_part: Base address of source must "
"not be NULL.\n");
return CFI_ERROR_BASE_ADDR_NULL;
}
/* Source and result must have the same rank. */
if (source->rank != result->rank)
{
fprintf (stderr, "CFI_select_part: Source and result must have "
"the same rank (source->rank = %d, result->rank = %d).\n",
(int)source->rank, (int)result->rank);
return CFI_INVALID_RANK;
}
/* Nonallocatable nonpointer must not be an assumed size array. */
if (source->rank > 0 && source->dim[source->rank - 1].extent == -1)
{
fprintf (stderr, "CFI_select_part: Source must not describe an "
"assumed size array (source->dim[%d].extent != -1).\n",
source->rank - 1);
return CFI_INVALID_DESCRIPTOR;
}
}
/* Element length is ignored unless result->type specifies a Fortran
character type. */
if (result->type == CFI_type_char || result->type == CFI_type_ucs4_char)
result->elem_len = elem_len;
if (unlikely (compile_options.bounds_check))
{
/* Ensure displacement is within the bounds of the element length
of source.*/
if (displacement > source->elem_len - 1)
{
fprintf (stderr, "CFI_select_part: Displacement must be within the "
"bounds of source (0 <= displacement <= source->elem_len "
"- 1, 0 <= %" PRIiPTR " <= %" PRIiPTR ").\n",
(ptrdiff_t)displacement,
(ptrdiff_t)(source->elem_len - 1));
return CFI_ERROR_OUT_OF_BOUNDS;
}
/* Ensure displacement and element length of result are less than or
equal to the element length of source. */
if (displacement + result->elem_len > source->elem_len)
{
fprintf (stderr, "CFI_select_part: Displacement plus the element "
"length of result must be less than or equal to the "
"element length of source (displacement + result->elem_len "
"<= source->elem_len, "
"%" PRIiPTR " + %" PRIiPTR " = %" PRIiPTR " <= %" PRIiPTR
").\n",
(ptrdiff_t)displacement, (ptrdiff_t)result->elem_len,
(ptrdiff_t)(displacement + result->elem_len),
(ptrdiff_t)source->elem_len);
return CFI_ERROR_OUT_OF_BOUNDS;
}
}
if (result->rank > 0)
{
for (int i = 0; i < result->rank; i++)
{
result->dim[i].lower_bound = source->dim[i].lower_bound;
result->dim[i].extent = source->dim[i].extent;
result->dim[i].sm = source->dim[i].sm;
}
}
result->base_addr = (char *) source->base_addr + displacement;
return CFI_SUCCESS;
}
int CFI_setpointer (CFI_cdesc_t *result, CFI_cdesc_t *source,
const CFI_index_t lower_bounds[])
{
/* Result must not be NULL and must be a Fortran pointer. */
if (unlikely (compile_options.bounds_check))
{
if (result == NULL)
{
fprintf (stderr, "CFI_setpointer: Result is NULL.\n");
return CFI_INVALID_DESCRIPTOR;
}
if (result->attribute != CFI_attribute_pointer)
{
fprintf (stderr, "CFI_setpointer: Result shall be the address of a "
"C descriptor for a Fortran pointer.\n");
return CFI_INVALID_ATTRIBUTE;
}
}
/* If source is NULL, the result is a C descriptor that describes a
* disassociated pointer. */
if (source == NULL)
{
result->base_addr = NULL;
result->version = CFI_VERSION;
}
else
{
/* Check that the source is valid and that element lengths, ranks
and types of source and result are the same. */
if (unlikely (compile_options.bounds_check))
{
if (source->base_addr == NULL
&& source->attribute == CFI_attribute_allocatable)
{
fprintf (stderr, "CFI_setpointer: The source is an "
"allocatable object but is not allocated.\n");
return CFI_ERROR_BASE_ADDR_NULL;
}
if (source->rank > 0
&& source->dim[source->rank - 1].extent == -1)
{
fprintf (stderr, "CFI_setpointer: The source is an "
"assumed-size array.\n");
return CFI_INVALID_EXTENT;
}
if (result->elem_len != source->elem_len)
{
fprintf (stderr, "CFI_setpointer: Element lengths of result "
"(result->elem_len = %" PRIiPTR ") and source "
"(source->elem_len = %" PRIiPTR ") "
" must be the same.\n",
(ptrdiff_t)result->elem_len,
(ptrdiff_t)source->elem_len);
return CFI_INVALID_ELEM_LEN;
}
if (result->rank != source->rank)
{
fprintf (stderr, "CFI_setpointer: Ranks of result "
"(result->rank = %d) and source (source->rank = %d) "
"must be the same.\n", result->rank, source->rank);
return CFI_INVALID_RANK;
}
if (result->type != source->type)
{
fprintf (stderr, "CFI_setpointer: Types of result "
"(result->type = %d) and source (source->type = %d) "
"must be the same.\n", result->type, source->type);
return CFI_INVALID_TYPE;
}
}
/* If the source is a disassociated pointer, the result must also
describe a disassociated pointer. */
if (source->base_addr == NULL
&& source->attribute == CFI_attribute_pointer)
result->base_addr = NULL;
else
result->base_addr = source->base_addr;
/* Assign components to result. */
result->version = source->version;
/* Dimension information. */
for (int i = 0; i < source->rank; i++)
{
if (lower_bounds != NULL)
result->dim[i].lower_bound = lower_bounds[i];
else
result->dim[i].lower_bound = source->dim[i].lower_bound;
result->dim[i].extent = source->dim[i].extent;
result->dim[i].sm = source->dim[i].sm;
}
}
return CFI_SUCCESS;
}