Fortran: Fix Bind(C) Array-Descriptor Conversion

gfortran uses internally a different array descriptor ("gfc") as
Fortran 2018 alias TS291113 defines for C interoperability via
ISO_Fortran_binding.h ("CFI").  Hence, when calling a C function
from Fortran, it has to be converted in the callee - and if a
BIND(C) procedure is written in Fortran, the CFI argument has
to be converted to gfc in order work with the rest of the FE
code and the library calls.

Before this patch, part was handled in the FE generated code and
other parts in libgfortran.  With this patch, all code is generated
and CFI is defined as proper type - visible in the debugger and to
the middle end - avoiding both alias issues and missed optimization
issues.

This patch also fixes issues like: intent(out) deallocation in
the bind(C) callee, using the CFI descriptor also for allocatable
and pointer scalars and for len=* character strings.
For 'select rank', it also optimizes the code + avoid accessing
uninitialized memory if the dummy argument is allocatable/a pointer.
It additionally rejects passing a descriptorless type(*) to an
assumed-rank dummy argument. [F2018:C711]

	PR fortran/102086
	PR fortran/92189
	PR fortran/92621
	PR fortran/101308
	PR fortran/101309
	PR fortran/101635
	PR fortran/92482

gcc/fortran/ChangeLog:

	* decl.c (gfc_verify_c_interop_param): Remove 'sorry' for
	scalar allocatable/pointer and len=*.
	* expr.c (is_CFI_desc): Return true for for those.
	* gfortran.h (CFI_type_kind_shift, CFI_type_mask,
	CFI_type_from_type_kind, CFI_VERSION, CFI_MAX_RANK,
	CFI_attribute_pointer, CFI_attribute_allocatable,
	CFI_attribute_other, CFI_type_Integer, CFI_type_Logical,
	CFI_type_Real, CFI_type_Complex, CFI_type_Character,
	CFI_type_ucs4_char, CFI_type_struct, CFI_type_cptr,
	CFI_type_cfunptr, CFI_type_other): New #define.
	* trans-array.c (CFI_FIELD_BASE_ADDR, CFI_FIELD_ELEM_LEN,
	CFI_FIELD_VERSION, CFI_FIELD_RANK, CFI_FIELD_ATTRIBUTE,
	CFI_FIELD_TYPE, CFI_FIELD_DIM, CFI_DIM_FIELD_LOWER_BOUND,
	CFI_DIM_FIELD_EXTENT, CFI_DIM_FIELD_SM,
	gfc_get_cfi_descriptor_field, gfc_get_cfi_desc_base_addr,
	gfc_get_cfi_desc_elem_len, gfc_get_cfi_desc_version,
	gfc_get_cfi_desc_rank, gfc_get_cfi_desc_type,
	gfc_get_cfi_desc_attribute, gfc_get_cfi_dim_item,
	gfc_get_cfi_dim_lbound, gfc_get_cfi_dim_extent, gfc_get_cfi_dim_sm):
	New define/functions to access the CFI array descriptor.
	(gfc_conv_descriptor_type): New function for the GFC descriptor.
	(gfc_get_array_span): Handle expr of CFI descriptors and
	assumed-type descriptors.
	(gfc_trans_array_bounds): Remove 'static'.
	(gfc_conv_expr_descriptor): For assumed type, use the dtype of
	the actual argument.
	(structure_alloc_comps): Remove ' ' inside tabs.
	* trans-array.h (gfc_trans_array_bounds, gfc_conv_descriptor_type,
	gfc_get_cfi_desc_base_addr, gfc_get_cfi_desc_elem_len,
	gfc_get_cfi_desc_version, gfc_get_cfi_desc_rank,
	gfc_get_cfi_desc_type, gfc_get_cfi_desc_attribute,
	gfc_get_cfi_dim_lbound, gfc_get_cfi_dim_extent, gfc_get_cfi_dim_sm):
	New prototypes.
	* trans-decl.c (gfor_fndecl_cfi_to_gfc, gfor_fndecl_gfc_to_cfi):
	Remove global vars.
	(gfc_build_builtin_function_decls): Remove their initialization.
	(gfc_get_symbol_decl, create_function_arglist,
	gfc_trans_deferred_vars): Update for CFI.
	(convert_CFI_desc): Remove and replace by ...
	(gfc_conv_cfi_to_gfc): ... this function
	(gfc_generate_function_code): Call it; create local GFC var for CFI.
	* trans-expr.c (gfc_maybe_dereference_var): Handle CFI.
	(gfc_conv_subref_array_arg): Handle the if-noncontigous-only copy in
	when the result should be a descriptor.
	(gfc_conv_gfc_desc_to_cfi_desc): Completely rewritten.
	(gfc_conv_procedure_call): CFI fixes.
	* trans-openmp.c (gfc_omp_is_optional_argument,
	gfc_omp_check_optional_argument): Handle optional
	CFI.
	* trans-stmt.c (gfc_trans_select_rank_cases): Cleanup, avoid invalid
	code for allocatable/pointer dummies, which cannot be assumed size.
	* trans-types.c (gfc_cfi_descriptor_base): New global var.
	(gfc_get_dtype_rank_type): Skip rank init for rank < 0.
	(gfc_sym_type): Handle CFI dummies.
	(gfc_get_function_type): Update call.
	(gfc_get_cfi_dim_type, gfc_get_cfi_type): New.
	* trans-types.h (gfc_sym_type): Update prototype.
	(gfc_get_cfi_type): New prototype.
	* trans.c (gfc_trans_runtime_check): Make conditions more consistent
	to avoid '<logical> AND_THEN <long int>' in conditions.
	* trans.h (gfor_fndecl_cfi_to_gfc, gfor_fndecl_gfc_to_cfi): Remove
	global-var declaration.

libgfortran/ChangeLog:

	* ISO_Fortran_binding.h (CFI_type_cfunptr): Make unique type again.
	* runtime/ISO_Fortran_binding.c (cfi_desc_to_gfc_desc,
	gfc_desc_to_cfi_desc): Add comment that those are no longer called
	by new code.

libgomp/ChangeLog:

	* testsuite/libgomp.fortran/optional-bind-c.f90: New test.

gcc/testsuite/ChangeLog:

	* gfortran.dg/ISO_Fortran_binding_4.f90: Extend testcase.
	* gfortran.dg/PR100914.f90: Remove xfail.
	* gfortran.dg/PR100915.c: Expect CFI_type_cfunptr.
	* gfortran.dg/PR100915.f90: Handle CFI_type_cfunptr != CFI_type_cptr.
	* gfortran.dg/PR93963.f90: Extend select-rank tests.
	* gfortran.dg/bind-c-intent-out.f90: Change to dg-do run,
	update scan-dump.
	* gfortran.dg/bind_c_array_params_2.f90: Update/extend scan-dump.
	* gfortran.dg/bind_c_char_10.f90: Update scan-dump.
	* gfortran.dg/bind_c_char_8.f90: Remove dg-error "sorry".
	* gfortran.dg/c-interop/allocatable-dummy.f90: Remove xfail.
	* gfortran.dg/c-interop/c1255-1.f90: Likewise.
	* gfortran.dg/c-interop/c407c-1.f90: Update dg-error.
	* gfortran.dg/c-interop/cf-descriptor-5.f90: Remove xfail.
	* gfortran.dg/c-interop/cf-out-descriptor-3.f90: Likewise.
	* gfortran.dg/c-interop/cf-out-descriptor-4.f90: Likewise.
	* gfortran.dg/c-interop/cf-out-descriptor-5.f90: Likewise.
	* gfortran.dg/c-interop/contiguous-2.f90: Likewise.
	* gfortran.dg/c-interop/contiguous-3.f90: Likewise.
	* gfortran.dg/c-interop/deferred-character-1.f90: Likewise.
	* gfortran.dg/c-interop/deferred-character-2.f90: Likewise.
	* gfortran.dg/c-interop/fc-descriptor-3.f90: Likewise.
	* gfortran.dg/c-interop/fc-descriptor-5.f90: Likewise.
	* gfortran.dg/c-interop/fc-descriptor-6.f90: Likewise.
	* gfortran.dg/c-interop/fc-out-descriptor-3.f90: Likewise.
	* gfortran.dg/c-interop/fc-out-descriptor-4.f90: Likewise.
	* gfortran.dg/c-interop/fc-out-descriptor-5.f90: Likewise.
	* gfortran.dg/c-interop/fc-out-descriptor-6.f90: Likewise.
	* gfortran.dg/c-interop/ff-descriptor-5.f90: Likewise.
	* gfortran.dg/c-interop/ff-descriptor-6.f90: Likewise.
	* gfortran.dg/c-interop/fc-descriptor-7.f90: Remove xfail + extend.
	* gfortran.dg/c-interop/fc-descriptor-7-c.c: Update for changes.
	* gfortran.dg/c-interop/shape.f90: Add implicit none.
	* gfortran.dg/c-interop/typecodes-array-char-c.c: Add kind=4 char.
	* gfortran.dg/c-interop/typecodes-array-char.f90: Likewise.
	* gfortran.dg/c-interop/typecodes-array-float128.f90: Remove xfail.
	* gfortran.dg/c-interop/typecodes-scalar-basic.f90: Likewise.
	* gfortran.dg/c-interop/typecodes-scalar-float128.f90: Likewise.
	* gfortran.dg/c-interop/typecodes-scalar-int128.f90: Likewise.
	* gfortran.dg/c-interop/typecodes-scalar-longdouble.f90: Likewise.
	* gfortran.dg/iso_c_binding_char_1.f90: Remove dg-error "sorry".
	* gfortran.dg/pr93792.f90: Turn XFAIL into PASS.
	* gfortran.dg/ISO_Fortran_binding_19.f90: New test.
	* gfortran.dg/assumed_type_12.f90: New test.
	* gfortran.dg/assumed_type_13.c: New test.
	* gfortran.dg/assumed_type_13.f90: New test.
	* gfortran.dg/bind-c-char-descr.f90: New test.
	* gfortran.dg/bind-c-contiguous-1.c: New test.
	* gfortran.dg/bind-c-contiguous-1.f90: New test.
	* gfortran.dg/bind-c-contiguous-2.f90: New test.
	* gfortran.dg/bind-c-contiguous-3.c: New test.
	* gfortran.dg/bind-c-contiguous-3.f90: New test.
	* gfortran.dg/bind-c-contiguous-4.c: New test.
	* gfortran.dg/bind-c-contiguous-4.f90: New test.
	* gfortran.dg/bind-c-contiguous-5.c: New test.
	* gfortran.dg/bind-c-contiguous-5.f90: New test.
This commit is contained in:
Tobias Burnus 2021-10-18 09:51:36 +02:00
parent a5b1b2a186
commit 64f9623765
71 changed files with 9151 additions and 483 deletions

View file

@ -1605,15 +1605,6 @@ gfc_verify_c_interop_param (gfc_symbol *sym)
sym->name, &sym->declared_at,
sym->ns->proc_name->name))
retval = false;
else if (!sym->attr.dimension)
{
/* FIXME: Use CFI array descriptor for scalars. */
gfc_error ("Sorry, deferred-length scalar character dummy "
"argument %qs at %L of procedure %qs with "
"BIND(C) not yet supported", sym->name,
&sym->declared_at, sym->ns->proc_name->name);
retval = false;
}
}
else if (sym->attr.value
&& (!cl || !cl->length
@ -1636,20 +1627,6 @@ gfc_verify_c_interop_param (gfc_symbol *sym)
"attribute", sym->name, &sym->declared_at,
sym->ns->proc_name->name))
retval = false;
else if (!sym->attr.dimension
|| sym->as->type == AS_ASSUMED_SIZE
|| sym->as->type == AS_EXPLICIT)
{
/* FIXME: Valid - should use the CFI array descriptor, but
not yet handled for scalars and assumed-/explicit-size
arrays. */
gfc_error ("Sorry, character dummy argument %qs at %L "
"with assumed length is not yet supported for "
"procedure %qs with BIND(C) attribute",
sym->name, &sym->declared_at,
sym->ns->proc_name->name);
retval = false;
}
}
else if (cl->length->expr_type != EXPR_CONSTANT
|| mpz_cmp_si (cl->length->value.integer, 1) != 0)

View file

@ -1110,11 +1110,13 @@ is_CFI_desc (gfc_symbol *sym, gfc_expr *e)
if (sym && sym->attr.dummy
&& sym->ns->proc_name->attr.is_bind_c
&& sym->attr.dimension
&& (sym->attr.pointer
|| sym->attr.allocatable
|| sym->as->type == AS_ASSUMED_SHAPE
|| sym->as->type == AS_ASSUMED_RANK))
|| (sym->attr.dimension
&& (sym->as->type == AS_ASSUMED_SHAPE
|| sym->as->type == AS_ASSUMED_RANK))
|| (sym->ts.type == BT_CHARACTER
&& (!sym->ts.u.cl || !sym->ts.u.cl->length))))
return true;
return false;

View file

@ -105,6 +105,40 @@ typedef struct
}
mstring;
/* ISO_Fortran_binding.h
CAUTION: This has to be kept in sync with libgfortran. */
#define CFI_type_kind_shift 8
#define CFI_type_mask 0xFF
#define CFI_type_from_type_kind(t, k) (t + (k << CFI_type_kind_shift))
/* Constants, defined as macros. */
#define CFI_VERSION 1
#define CFI_MAX_RANK 15
/* Attributes. */
#define CFI_attribute_pointer 0
#define CFI_attribute_allocatable 1
#define CFI_attribute_other 2
#define CFI_type_mask 0xFF
#define CFI_type_kind_shift 8
/* Intrinsic types. Their kind number defines their storage size. */
#define CFI_type_Integer 1
#define CFI_type_Logical 2
#define CFI_type_Real 3
#define CFI_type_Complex 4
#define CFI_type_Character 5
/* Combined type (for more, see ISO_Fortran_binding.h). */
#define CFI_type_ucs4_char (CFI_type_Character + (4 << CFI_type_kind_shift))
/* Types with no kind. */
#define CFI_type_struct 6
#define CFI_type_cptr 7
#define CFI_type_cfunptr 8
#define CFI_type_other -1
/*************************** Enums *****************************/

View file

@ -103,6 +103,111 @@ gfc_array_dataptr_type (tree desc)
return (GFC_TYPE_ARRAY_DATAPTR_TYPE (TREE_TYPE (desc)));
}
/* Build expressions to access members of the CFI descriptor. */
#define CFI_FIELD_BASE_ADDR 0
#define CFI_FIELD_ELEM_LEN 1
#define CFI_FIELD_VERSION 2
#define CFI_FIELD_RANK 3
#define CFI_FIELD_ATTRIBUTE 4
#define CFI_FIELD_TYPE 5
#define CFI_FIELD_DIM 6
#define CFI_DIM_FIELD_LOWER_BOUND 0
#define CFI_DIM_FIELD_EXTENT 1
#define CFI_DIM_FIELD_SM 2
static tree
gfc_get_cfi_descriptor_field (tree desc, unsigned field_idx)
{
tree type = TREE_TYPE (desc);
gcc_assert (TREE_CODE (type) == RECORD_TYPE
&& TYPE_FIELDS (type)
&& (strcmp ("base_addr",
IDENTIFIER_POINTER (DECL_NAME (TYPE_FIELDS (type))))
== 0));
tree field = gfc_advance_chain (TYPE_FIELDS (type), field_idx);
gcc_assert (field != NULL_TREE);
return fold_build3_loc (input_location, COMPONENT_REF, TREE_TYPE (field),
desc, field, NULL_TREE);
}
tree
gfc_get_cfi_desc_base_addr (tree desc)
{
return gfc_get_cfi_descriptor_field (desc, CFI_FIELD_BASE_ADDR);
}
tree
gfc_get_cfi_desc_elem_len (tree desc)
{
return gfc_get_cfi_descriptor_field (desc, CFI_FIELD_ELEM_LEN);
}
tree
gfc_get_cfi_desc_version (tree desc)
{
return gfc_get_cfi_descriptor_field (desc, CFI_FIELD_VERSION);
}
tree
gfc_get_cfi_desc_rank (tree desc)
{
return gfc_get_cfi_descriptor_field (desc, CFI_FIELD_RANK);
}
tree
gfc_get_cfi_desc_type (tree desc)
{
return gfc_get_cfi_descriptor_field (desc, CFI_FIELD_TYPE);
}
tree
gfc_get_cfi_desc_attribute (tree desc)
{
return gfc_get_cfi_descriptor_field (desc, CFI_FIELD_ATTRIBUTE);
}
static tree
gfc_get_cfi_dim_item (tree desc, tree idx, unsigned field_idx)
{
tree tmp = gfc_get_cfi_descriptor_field (desc, CFI_FIELD_DIM);
tmp = gfc_build_array_ref (tmp, idx, NULL);
tree field = gfc_advance_chain (TYPE_FIELDS (TREE_TYPE (tmp)), field_idx);
gcc_assert (field != NULL_TREE);
return fold_build3_loc (input_location, COMPONENT_REF, TREE_TYPE (field),
tmp, field, NULL_TREE);
}
tree
gfc_get_cfi_dim_lbound (tree desc, tree idx)
{
return gfc_get_cfi_dim_item (desc, idx, CFI_DIM_FIELD_LOWER_BOUND);
}
tree
gfc_get_cfi_dim_extent (tree desc, tree idx)
{
return gfc_get_cfi_dim_item (desc, idx, CFI_DIM_FIELD_EXTENT);
}
tree
gfc_get_cfi_dim_sm (tree desc, tree idx)
{
return gfc_get_cfi_dim_item (desc, idx, CFI_DIM_FIELD_SM);
}
#undef CFI_FIELD_BASE_ADDR
#undef CFI_FIELD_ELEM_LEN
#undef CFI_FIELD_VERSION
#undef CFI_FIELD_RANK
#undef CFI_FIELD_ATTRIBUTE
#undef CFI_FIELD_TYPE
#undef CFI_FIELD_DIM
#undef CFI_DIM_FIELD_LOWER_BOUND
#undef CFI_DIM_FIELD_EXTENT
#undef CFI_DIM_FIELD_SM
/* Build expressions to access the members of an array descriptor.
It's surprisingly easy to mess up here, so never access
@ -288,6 +393,20 @@ gfc_conv_descriptor_attribute (tree desc)
dtype, tmp, NULL_TREE);
}
tree
gfc_conv_descriptor_type (tree desc)
{
tree tmp;
tree dtype;
dtype = gfc_conv_descriptor_dtype (desc);
tmp = gfc_advance_chain (TYPE_FIELDS (TREE_TYPE (dtype)), GFC_DTYPE_TYPE);
gcc_assert (tmp!= NULL_TREE
&& TREE_TYPE (tmp) == signed_char_type_node);
return fold_build3_loc (input_location, COMPONENT_REF, TREE_TYPE (tmp),
dtype, tmp, NULL_TREE);
}
tree
gfc_get_descriptor_dimension (tree desc)
{
@ -825,7 +944,11 @@ gfc_get_array_span (tree desc, gfc_expr *expr)
{
tree tmp;
if (is_pointer_array (desc) || get_CFI_desc (NULL, expr, &desc, NULL))
if (is_pointer_array (desc)
|| (get_CFI_desc (NULL, expr, &desc, NULL)
&& (POINTER_TYPE_P (TREE_TYPE (desc))
? GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (TREE_TYPE (desc)))
: GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (desc)))))
{
if (POINTER_TYPE_P (TREE_TYPE (desc)))
desc = build_fold_indirect_ref_loc (input_location, desc);
@ -833,6 +956,14 @@ gfc_get_array_span (tree desc, gfc_expr *expr)
/* This will have the span field set. */
tmp = gfc_conv_descriptor_span_get (desc);
}
else if (expr->ts.type == BT_ASSUMED)
{
if (DECL_LANG_SPECIFIC (desc) && GFC_DECL_SAVED_DESCRIPTOR (desc))
desc = GFC_DECL_SAVED_DESCRIPTOR (desc);
if (POINTER_TYPE_P (TREE_TYPE (desc)))
desc = build_fold_indirect_ref_loc (input_location, desc);
tmp = gfc_conv_descriptor_span_get (desc);
}
else if (TREE_CODE (desc) == COMPONENT_REF
&& GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (desc))
&& GFC_CLASS_TYPE_P (TREE_TYPE (TREE_OPERAND (desc, 0))))
@ -6286,7 +6417,7 @@ gfc_trans_array_cobounds (tree type, stmtblock_t * pblock,
/* Generate code to evaluate non-constant array bounds. Sets *poffset and
returns the size (in elements) of the array. */
static tree
tree
gfc_trans_array_bounds (tree type, gfc_symbol * sym, tree * poffset,
stmtblock_t * pblock)
{
@ -7755,6 +7886,15 @@ gfc_conv_expr_descriptor (gfc_se *se, gfc_expr *expr)
tmp = gfc_conv_descriptor_dtype (parm);
if (se->unlimited_polymorphic)
dtype = gfc_get_dtype (TREE_TYPE (desc), &loop.dimen);
else if (expr->ts.type == BT_ASSUMED)
{
tree tmp2 = desc;
if (DECL_LANG_SPECIFIC (tmp2) && GFC_DECL_SAVED_DESCRIPTOR (tmp2))
tmp2 = GFC_DECL_SAVED_DESCRIPTOR (tmp2);
if (POINTER_TYPE_P (TREE_TYPE (tmp2)))
tmp2 = build_fold_indirect_ref_loc (input_location, tmp2);
dtype = gfc_conv_descriptor_dtype (tmp2);
}
else
dtype = gfc_get_dtype (parmtype);
gfc_add_modify (&loop.pre, tmp, dtype);
@ -9006,7 +9146,7 @@ structure_alloc_comps (gfc_symbol * der_type, tree decl,
DECL_ARTIFICIAL (cdesc) = 1;
gfc_add_modify (&tmpblock, gfc_conv_descriptor_dtype (cdesc),
gfc_get_dtype_rank_type (1, tmp));
gfc_get_dtype_rank_type (1, tmp));
gfc_conv_descriptor_lbound_set (&tmpblock, cdesc,
gfc_index_zero_node,
gfc_index_one_node);

View file

@ -160,7 +160,8 @@ tree gfc_conv_array_stride (tree, int);
tree gfc_conv_array_lbound (tree, int);
tree gfc_conv_array_ubound (tree, int);
/* Set cobounds of an array. */
/* Set (co)bounds of an array. */
tree gfc_trans_array_bounds (tree, gfc_symbol *, tree *, stmtblock_t *);
void gfc_trans_array_cobounds (tree, stmtblock_t *, const gfc_symbol *);
/* Build expressions for accessing components of an array descriptor. */
@ -175,6 +176,7 @@ tree gfc_conv_descriptor_dtype (tree);
tree gfc_conv_descriptor_rank (tree);
tree gfc_conv_descriptor_elem_len (tree);
tree gfc_conv_descriptor_attribute (tree);
tree gfc_conv_descriptor_type (tree);
tree gfc_get_descriptor_dimension (tree);
tree gfc_conv_descriptor_stride_get (tree, tree);
tree gfc_conv_descriptor_lbound_get (tree, tree);
@ -188,6 +190,18 @@ void gfc_conv_descriptor_stride_set (stmtblock_t *, tree, tree, tree);
void gfc_conv_descriptor_lbound_set (stmtblock_t *, tree, tree, tree);
void gfc_conv_descriptor_ubound_set (stmtblock_t *, tree, tree, tree);
/* CFI descriptor. */
tree gfc_get_cfi_desc_base_addr (tree);
tree gfc_get_cfi_desc_elem_len (tree);
tree gfc_get_cfi_desc_version (tree);
tree gfc_get_cfi_desc_rank (tree);
tree gfc_get_cfi_desc_type (tree);
tree gfc_get_cfi_desc_attribute (tree);
tree gfc_get_cfi_dim_lbound (tree, tree);
tree gfc_get_cfi_dim_extent (tree, tree);
tree gfc_get_cfi_dim_sm (tree, tree);
/* Shift lower bound of descriptor, updating ubound and offset. */
void gfc_conv_shift_descriptor_lbound (stmtblock_t*, tree, int, tree);

File diff suppressed because it is too large Load diff

View file

@ -2866,6 +2866,9 @@ tree
gfc_maybe_dereference_var (gfc_symbol *sym, tree var, bool descriptor_only_p,
bool is_classarray)
{
if (is_CFI_desc (sym, NULL))
return build_fold_indirect_ref_loc (input_location, var);
/* Characters are entirely different from other types, they are treated
separately. */
if (sym->ts.type == BT_CHARACTER)
@ -4922,7 +4925,7 @@ gfc_conv_subref_array_arg (gfc_se *se, gfc_expr * expr, int g77,
if (fsym && proc_name)
msg = xasprintf ("An array temporary was created for argument "
"'%s' of procedure '%s'", fsym->name, proc_name);
"'%s' of procedure '%s'", fsym->name, proc_name);
else
msg = xasprintf ("An array temporary was created");
@ -5220,6 +5223,8 @@ class_array_fcn:
tree post_cond;
type = TREE_TYPE (parmse->expr);
if (POINTER_TYPE_P (type) && GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (type)))
type = TREE_TYPE (type);
pointer = gfc_create_var (type, "arg_ptr");
if (check_contiguous)
@ -5263,17 +5268,25 @@ class_array_fcn:
gfc_add_block_to_block (&se->pre, &(&array_se)->pre);
gfc_add_block_to_block (&se->pre, &(&array_se)->post);
/* if_stmt = { pointer = &a[0]; } . */
/* if_stmt = { descriptor ? pointer = a : pointer = &a[0]; } . */
gfc_init_block (&if_block);
tmp = gfc_conv_array_data (array_se.expr);
tmp = fold_convert (type, tmp);
gfc_add_modify (&if_block, pointer, tmp);
if (GFC_DESCRIPTOR_TYPE_P (type))
gfc_add_modify (&if_block, pointer, array_se.expr);
else
{
tmp = gfc_conv_array_data (array_se.expr);
tmp = fold_convert (type, tmp);
gfc_add_modify (&if_block, pointer, tmp);
}
if_stmt = gfc_finish_block (&if_block);
/* else_stmt = { parmse->pre(); pointer = parmse->expr; } . */
gfc_init_block (&else_block);
gfc_add_block_to_block (&else_block, &parmse->pre);
gfc_add_modify (&else_block, pointer, parmse->expr);
tmp = (GFC_DESCRIPTOR_TYPE_P (type)
? build_fold_indirect_ref_loc (input_location, parmse->expr)
: parmse->expr);
gfc_add_modify (&else_block, pointer, tmp);
else_stmt = gfc_finish_block (&else_block);
/* And put the above into an if statement. */
@ -5300,7 +5313,11 @@ class_array_fcn:
/* else_stmt = { pointer = NULL; } . */
gfc_init_block (&else_block);
gfc_add_modify (&else_block, pointer, build_int_cst (type, 0));
if (GFC_DESCRIPTOR_TYPE_P (type))
gfc_conv_descriptor_data_set (&else_block, pointer,
null_pointer_node);
else
gfc_add_modify (&else_block, pointer, build_int_cst (type, 0));
else_stmt = gfc_finish_block (&else_block);
tmp = fold_build3_loc (input_location, COND_EXPR, void_type_node,
@ -5344,6 +5361,24 @@ class_array_fcn:
tmp = fold_build3_loc (input_location, COND_EXPR, void_type_node, post_cond,
post_stmts, build_empty_stmt (input_location));
gfc_add_expr_to_block (&se->post, tmp);
if (GFC_DESCRIPTOR_TYPE_P (type))
{
type = TREE_TYPE (parmse->expr);
if (POINTER_TYPE_P (type))
{
pointer = gfc_build_addr_expr (type, pointer);
if (pass_optional)
{
tmp = gfc_likely (present_var, PRED_FORTRAN_ABSENT_DUMMY);
pointer = fold_build3_loc (input_location, COND_EXPR, type,
tmp, pointer,
fold_convert (type,
null_pointer_node));
}
}
else
gcc_assert (!pass_optional);
}
se->expr = pointer;
}
@ -5484,168 +5519,457 @@ set_dtype_for_unallocated (gfc_se *parmse, gfc_expr *e)
static void
gfc_conv_gfc_desc_to_cfi_desc (gfc_se *parmse, gfc_expr *e, gfc_symbol *fsym)
{
tree tmp;
tree cfi_desc_ptr;
tree gfc_desc_ptr;
tree type;
tree cond;
tree desc_attr;
int attribute;
int cfi_attribute;
symbol_attribute attr = gfc_expr_attr (e);
stmtblock_t block, block2;
tree cfi, gfc, tmp, tmp2;
tree present = NULL;
tree gfc_strlen = NULL;
tree rank;
gfc_se se;
/* If this is a full array or a scalar, the allocatable and pointer
attributes can be passed. Otherwise it is 'CFI_attribute_other'*/
attribute = 2;
if (!e->rank || gfc_get_full_arrayspec_from_expr (e))
if (fsym->attr.optional
&& e->expr_type == EXPR_VARIABLE
&& e->symtree->n.sym->attr.optional)
present = gfc_conv_expr_present (e->symtree->n.sym);
gfc_init_block (&block);
/* Convert original argument to a tree. */
gfc_init_se (&se, NULL);
if (e->rank == 0)
{
if (attr.pointer)
attribute = 0;
else if (attr.allocatable)
attribute = 1;
se.want_pointer = 1;
gfc_conv_expr (&se, e);
gfc = se.expr;
/* gfc_conv_constant ignores se.want_poiner, e.g. for string_cst. */
if (!POINTER_TYPE_P (TREE_TYPE (gfc)))
gfc = gfc_build_addr_expr (NULL, gfc);
}
else
{
/* If the actual argument can be noncontiguous, copy-in/out is required,
if the dummy has either the CONTIGUOUS attribute or is an assumed-
length assumed-length/assumed-size CHARACTER array. */
se.force_no_tmp = 1;
if ((fsym->attr.contiguous
|| (fsym->ts.type == BT_CHARACTER && !fsym->ts.u.cl->length
&& (fsym->as->type == AS_ASSUMED_SIZE
|| fsym->as->type == AS_EXPLICIT)))
&& !gfc_is_simply_contiguous (e, false, true))
{
bool optional = fsym->attr.optional;
fsym->attr.optional = 0;
gfc_conv_subref_array_arg (&se, e, false, fsym->attr.intent,
fsym->attr.pointer, fsym,
fsym->ns->proc_name->name, NULL,
/* check_contiguous= */ true);
fsym->attr.optional = optional;
}
else
gfc_conv_expr_descriptor (&se, e);
gfc = se.expr;
/* For dt(:)%var the elem_len*stride != sm, hence, GFC uses
elem_len = sizeof(dt) and base_addr = dt(lb) instead.
gfc_get_dataptr_offset fixes the base_addr; for elem_len, see below.
While sm is fine as it uses span*stride and not elem_len. */
if (POINTER_TYPE_P (TREE_TYPE (gfc)))
gfc = build_fold_indirect_ref_loc (input_location, gfc);
else if (is_subref_array (e) && e->ts.type != BT_CHARACTER)
gfc_get_dataptr_offset (&se.pre, gfc, gfc, NULL, true, e);
}
if (e->ts.type == BT_CHARACTER)
{
if (se.string_length)
gfc_strlen = se.string_length;
else if (e->ts.u.cl->backend_decl)
gfc_strlen = e->ts.u.cl->backend_decl;
else
gcc_unreachable ();
}
gfc_add_block_to_block (&block, &se.pre);
/* Create array decriptor and set version, rank, attribute, type. */
cfi = gfc_create_var (gfc_get_cfi_type (e->rank < 0
? GFC_MAX_DIMENSIONS : e->rank,
false), "cfi");
/* Convert to CFI_cdesc_t, which has dim[] to avoid TBAA issues,*/
if (fsym->attr.dimension && fsym->as->type == AS_ASSUMED_RANK)
{
tmp = gfc_get_cfi_type (-1, !fsym->attr.pointer && !fsym->attr.target);
tmp = build_pointer_type (tmp);
parmse->expr = cfi = gfc_build_addr_expr (tmp, cfi);
cfi = build_fold_indirect_ref_loc (input_location, cfi);
}
else
parmse->expr = gfc_build_addr_expr (NULL, cfi);
tmp = gfc_get_cfi_desc_version (cfi);
gfc_add_modify (&block, tmp,
build_int_cst (TREE_TYPE (tmp), CFI_VERSION));
if (e->rank < 0)
rank = fold_convert (signed_char_type_node, gfc_conv_descriptor_rank (gfc));
else
rank = build_int_cst (signed_char_type_node, e->rank);
tmp = gfc_get_cfi_desc_rank (cfi);
gfc_add_modify (&block, tmp, rank);
int itype = CFI_type_other;
if (e->ts.f90_type == BT_VOID)
itype = (e->ts.u.derived->intmod_sym_id == ISOCBINDING_FUNPTR
? CFI_type_cfunptr : CFI_type_cptr);
else
switch (e->ts.type)
{
case BT_INTEGER:
case BT_LOGICAL:
case BT_REAL:
case BT_COMPLEX:
itype = CFI_type_from_type_kind (e->ts.type, e->ts.kind);
break;
case BT_CHARACTER:
itype = CFI_type_from_type_kind (CFI_type_Character, e->ts.kind);
break;
case BT_DERIVED:
itype = CFI_type_struct;
break;
case BT_VOID:
itype = (e->ts.u.derived->intmod_sym_id == ISOCBINDING_FUNPTR
? CFI_type_cfunptr : CFI_type_cptr);
break;
case BT_ASSUMED:
itype = CFI_type_other; // FIXME: Or CFI_type_cptr ?
break;
case BT_CLASS:
case BT_PROCEDURE:
case BT_HOLLERITH:
case BT_UNION:
case BT_BOZ:
case BT_UNKNOWN:
// FIXME: Really unreachable? Or reachable for type(*) ? If so, CFI_type_other?
gcc_unreachable ();
}
tmp = gfc_get_cfi_desc_type (cfi);
gfc_add_modify (&block, tmp,
build_int_cst (TREE_TYPE (tmp), itype));
int attr = CFI_attribute_other;
if (fsym->attr.pointer)
attr = CFI_attribute_pointer;
else if (fsym->attr.allocatable)
attr = CFI_attribute_allocatable;
tmp = gfc_get_cfi_desc_attribute (cfi);
gfc_add_modify (&block, tmp,
build_int_cst (TREE_TYPE (tmp), attr));
if (e->rank == 0)
{
tmp = gfc_get_cfi_desc_base_addr (cfi);
gfc_add_modify (&block, tmp, fold_convert (TREE_TYPE (tmp), gfc));
}
else
{
tmp = gfc_get_cfi_desc_base_addr (cfi);
tmp2 = gfc_conv_descriptor_data_get (gfc);
gfc_add_modify (&block, tmp, fold_convert (TREE_TYPE (tmp), tmp2));
}
if (fsym->attr.pointer)
cfi_attribute = 0;
else if (fsym->attr.allocatable)
cfi_attribute = 1;
else
cfi_attribute = 2;
/* Set elem_len if known - must be before the next if block.
Note that allocatable implies 'len=:'. */
if (e->ts.type != BT_ASSUMED && e->ts.type != BT_CHARACTER )
{
/* Length is known at compile time; use use 'block' for it. */
tmp = size_in_bytes (gfc_typenode_for_spec (&e->ts));
tmp2 = gfc_get_cfi_desc_elem_len (cfi);
gfc_add_modify (&block, tmp2, fold_convert (TREE_TYPE (tmp2), tmp));
}
/* When allocatable + intent out, free the cfi descriptor. */
if (fsym->attr.allocatable && fsym->attr.intent == INTENT_OUT)
{
tmp = gfc_get_cfi_desc_base_addr (cfi);
tree call = builtin_decl_explicit (BUILT_IN_FREE);
call = build_call_expr_loc (input_location, call, 1, tmp);
gfc_add_expr_to_block (&block, fold_convert (void_type_node, call));
gfc_add_modify (&block, tmp,
fold_convert (TREE_TYPE (tmp), null_pointer_node));
goto done;
}
/* If not unallocated/unassociated. */
gfc_init_block (&block2);
/* Set elem_len, which may be only known at run time. */
if (e->ts.type == BT_CHARACTER)
{
gcc_assert (gfc_strlen);
tmp = gfc_strlen;
if (e->ts.kind != 1)
tmp = fold_build2_loc (input_location, MULT_EXPR,
gfc_charlen_type_node, tmp,
build_int_cst (gfc_charlen_type_node,
e->ts.kind));
tmp2 = gfc_get_cfi_desc_elem_len (cfi);
gfc_add_modify (&block2, tmp2, fold_convert (TREE_TYPE (tmp2), tmp));
}
else if (e->ts.type == BT_ASSUMED)
{
tmp = gfc_conv_descriptor_elem_len (gfc);
tmp2 = gfc_get_cfi_desc_elem_len (cfi);
gfc_add_modify (&block2, tmp2, fold_convert (TREE_TYPE (tmp2), tmp));
}
if (e->ts.type == BT_ASSUMED)
{
/* Note: type(*) implies assumed-shape/assumed-rank if fsym requires
an CFI descriptor. Use the type in the descritor as it provide
mode information. (Quality of implementation feature.) */
tree cond;
tree ctype = gfc_get_cfi_desc_type (cfi);
tree type = fold_convert (TREE_TYPE (ctype),
gfc_conv_descriptor_type (gfc));
tree kind = fold_convert (TREE_TYPE (ctype),
gfc_conv_descriptor_elem_len (gfc));
kind = fold_build2_loc (input_location, LSHIFT_EXPR, TREE_TYPE (type),
kind, build_int_cst (TREE_TYPE (type),
CFI_type_kind_shift));
/* if (BT_VOID) CFI_type_cptr else CFI_type_other */
/* Note: BT_VOID is could also be CFI_type_funcptr, but assume c_ptr. */
cond = fold_build2_loc (input_location, EQ_EXPR, boolean_type_node, type,
build_int_cst (TREE_TYPE (type), BT_VOID));
tmp = fold_build2_loc (input_location, MODIFY_EXPR, void_type_node, ctype,
build_int_cst (TREE_TYPE (type), CFI_type_cptr));
tmp2 = fold_build2_loc (input_location, MODIFY_EXPR, void_type_node,
ctype,
build_int_cst (TREE_TYPE (type), CFI_type_other));
tmp2 = fold_build3_loc (input_location, COND_EXPR, void_type_node, cond,
tmp, tmp2);
/* if (BT_DERIVED) CFI_type_struct else < tmp2 > */
cond = fold_build2_loc (input_location, EQ_EXPR, boolean_type_node, type,
build_int_cst (TREE_TYPE (type), BT_DERIVED));
tmp = fold_build2_loc (input_location, MODIFY_EXPR, void_type_node, ctype,
build_int_cst (TREE_TYPE (type), CFI_type_struct));
tmp2 = fold_build3_loc (input_location, COND_EXPR, void_type_node, cond,
tmp, tmp2);
/* if (BT_CHARACTER) CFI_type_Character + kind=1 else < tmp2 > */
/* Note: could also be kind=4, with cfi->elem_len = gfc->elem_len*4. */
cond = fold_build2_loc (input_location, EQ_EXPR, boolean_type_node, type,
build_int_cst (TREE_TYPE (type), BT_CHARACTER));
tmp = build_int_cst (TREE_TYPE (type),
CFI_type_from_type_kind (CFI_type_Character, 1));
tmp = fold_build2_loc (input_location, MODIFY_EXPR, void_type_node,
ctype, tmp);
tmp2 = fold_build3_loc (input_location, COND_EXPR, void_type_node, cond,
tmp, tmp2);
/* if (BT_COMPLEX) CFI_type_Complex + kind/2 else < tmp2 > */
cond = fold_build2_loc (input_location, EQ_EXPR, boolean_type_node, type,
build_int_cst (TREE_TYPE (type), BT_COMPLEX));
tmp = fold_build2_loc (input_location, TRUNC_DIV_EXPR, TREE_TYPE (type),
kind, build_int_cst (TREE_TYPE (type), 2));
tmp = fold_build2_loc (input_location, PLUS_EXPR, TREE_TYPE (type), tmp,
build_int_cst (TREE_TYPE (type),
CFI_type_Complex));
tmp = fold_build2_loc (input_location, MODIFY_EXPR, void_type_node,
ctype, tmp);
tmp2 = fold_build3_loc (input_location, COND_EXPR, void_type_node, cond,
tmp, tmp2);
/* if (BT_INTEGER || BT_LOGICAL || BT_REAL) type + kind else <tmp2> */
cond = fold_build2_loc (input_location, EQ_EXPR, boolean_type_node, type,
build_int_cst (TREE_TYPE (type), BT_INTEGER));
tmp = fold_build2_loc (input_location, EQ_EXPR, boolean_type_node, type,
build_int_cst (TREE_TYPE (type), BT_LOGICAL));
cond = fold_build2_loc (input_location, TRUTH_OR_EXPR, boolean_type_node,
cond, tmp);
tmp = fold_build2_loc (input_location, EQ_EXPR, boolean_type_node, type,
build_int_cst (TREE_TYPE (type), BT_REAL));
cond = fold_build2_loc (input_location, TRUTH_OR_EXPR, boolean_type_node,
cond, tmp);
tmp = fold_build2_loc (input_location, PLUS_EXPR, TREE_TYPE (type),
type, kind);
tmp = fold_build2_loc (input_location, MODIFY_EXPR, void_type_node,
ctype, tmp);
tmp2 = fold_build3_loc (input_location, COND_EXPR, void_type_node, cond,
tmp, tmp2);
gfc_add_expr_to_block (&block2, tmp2);
}
if (e->rank != 0)
{
parmse->force_no_tmp = 1;
if (fsym->attr.contiguous
&& !gfc_is_simply_contiguous (e, false, true))
gfc_conv_subref_array_arg (parmse, e, false, fsym->attr.intent,
fsym->attr.pointer);
/* Loop: for (i = 0; i < rank; ++i). */
tree idx = gfc_create_var (TREE_TYPE (rank), "idx");
/* Loop body. */
stmtblock_t loop_body;
gfc_init_block (&loop_body);
/* cfi->dim[i].lower_bound = (allocatable/pointer)
? gfc->dim[i].lbound : 0 */
if (fsym->attr.pointer || fsym->attr.allocatable)
tmp = gfc_conv_descriptor_lbound_get (gfc, idx);
else
gfc_conv_expr_descriptor (parmse, e);
tmp = gfc_index_zero_node;
gfc_add_modify (&loop_body, gfc_get_cfi_dim_lbound (cfi, idx), tmp);
/* cfi->dim[i].extent = gfc->dim[i].ubound - gfc->dim[i].lbound + 1. */
tmp = fold_build2_loc (input_location, MINUS_EXPR, gfc_array_index_type,
gfc_conv_descriptor_ubound_get (gfc, idx),
gfc_conv_descriptor_lbound_get (gfc, idx));
tmp = fold_build2_loc (input_location, PLUS_EXPR, gfc_array_index_type,
tmp, gfc_index_one_node);
gfc_add_modify (&loop_body, gfc_get_cfi_dim_extent (cfi, idx), tmp);
/* d->dim[n].sm = gfc->dim[i].stride * gfc->span); */
tmp = fold_build2_loc (input_location, MULT_EXPR, gfc_array_index_type,
gfc_conv_descriptor_stride_get (gfc, idx),
gfc_conv_descriptor_span_get (gfc));
gfc_add_modify (&loop_body, gfc_get_cfi_dim_sm (cfi, idx), tmp);
if (POINTER_TYPE_P (TREE_TYPE (parmse->expr)))
parmse->expr = build_fold_indirect_ref_loc (input_location,
parmse->expr);
bool is_artificial = (INDIRECT_REF_P (parmse->expr)
? DECL_ARTIFICIAL (TREE_OPERAND (parmse->expr, 0))
: DECL_ARTIFICIAL (parmse->expr));
/* Generate loop. */
gfc_simple_for_loop (&block2, idx, build_int_cst (TREE_TYPE (idx), 0),
rank, LT_EXPR, build_int_cst (TREE_TYPE (idx), 1),
gfc_finish_block (&loop_body));
/* Unallocated allocatable arrays and unassociated pointer arrays
need their dtype setting if they are argument associated with
assumed rank dummies. */
if (fsym && fsym->as
&& (gfc_expr_attr (e).pointer
|| gfc_expr_attr (e).allocatable))
set_dtype_for_unallocated (parmse, e);
/* All the temporary descriptors are marked as DECL_ARTIFICIAL. If
the expression type is different from the descriptor type, then
the offset must be found (eg. to a component ref or substring)
and the dtype updated. Assumed type entities are only allowed
to be dummies in Fortran. They therefore lack the decl specific
appendiges and so must be treated differently from other fortran
entities passed to CFI descriptors in the interface decl. */
type = e->ts.type != BT_ASSUMED ? gfc_typenode_for_spec (&e->ts) :
NULL_TREE;
if (type && is_artificial
&& type != gfc_get_element_type (TREE_TYPE (parmse->expr)))
if (e->expr_type == EXPR_VARIABLE
&& e->ref
&& e->ref->u.ar.type == AR_FULL
&& e->symtree->n.sym->attr.dummy
&& e->symtree->n.sym->as
&& e->symtree->n.sym->as->type == AS_ASSUMED_SIZE)
{
/* Obtain the offset to the data. */
gfc_get_dataptr_offset (&parmse->pre, parmse->expr, parmse->expr,
gfc_index_zero_node, true, e);
tmp = gfc_get_cfi_dim_extent (cfi, gfc_rank_cst[e->rank-1]),
gfc_add_modify (&block2, tmp, build_int_cst (TREE_TYPE (tmp), -1));
}
}
/* Update the dtype. */
gfc_add_modify (&parmse->pre,
gfc_conv_descriptor_dtype (parmse->expr),
gfc_get_dtype_rank_type (e->rank, type));
}
else if (type == NULL_TREE
|| (!is_subref_array (e) && !is_artificial))
{
/* Make sure that the span is set for expressions where it
might not have been done already. */
tmp = gfc_conv_descriptor_elem_len (parmse->expr);
tmp = fold_convert (gfc_array_index_type, tmp);
gfc_conv_descriptor_span_set (&parmse->pre, parmse->expr, tmp);
}
if (fsym->attr.allocatable || fsym->attr.pointer)
{
tmp = gfc_get_cfi_desc_base_addr (cfi),
tmp = fold_build2_loc (input_location, NE_EXPR, boolean_type_node,
tmp, null_pointer_node);
tmp = build3_v (COND_EXPR, tmp, gfc_finish_block (&block2),
build_empty_stmt (input_location));
gfc_add_expr_to_block (&block, tmp);
}
else
gfc_add_block_to_block (&block, &block2);
done:
if (present)
{
parmse->expr = build3_loc (input_location, COND_EXPR,
TREE_TYPE (parmse->expr),
present, parmse->expr, null_pointer_node);
tmp = build3_v (COND_EXPR, present, gfc_finish_block (&block),
build_empty_stmt (input_location));
gfc_add_expr_to_block (&parmse->pre, tmp);
}
else
gfc_add_block_to_block (&parmse->pre, &block);
gfc_init_block (&block);
if ((!fsym->attr.allocatable && !fsym->attr.pointer)
|| fsym->attr.intent == INTENT_IN)
goto post_call;
gfc_init_block (&block2);
if (e->rank == 0)
{
tmp = gfc_get_cfi_desc_base_addr (cfi);
gfc_add_modify (&block, gfc, fold_convert (TREE_TYPE (gfc), tmp));
}
else
{
gfc_conv_expr (parmse, e);
tmp = gfc_get_cfi_desc_base_addr (cfi);
gfc_conv_descriptor_data_set (&block, gfc, tmp);
if (POINTER_TYPE_P (TREE_TYPE (parmse->expr)))
parmse->expr = build_fold_indirect_ref_loc (input_location,
parmse->expr);
if (fsym->attr.allocatable)
{
/* gfc->span = cfi->elem_len. */
tmp = fold_convert (gfc_array_index_type,
gfc_get_cfi_dim_sm (cfi, gfc_rank_cst[0]));
}
else
{
/* gfc->span = ((cfi->dim[0].sm % cfi->elem_len)
? cfi->dim[0].sm : cfi->elem_len). */
tmp = gfc_get_cfi_dim_sm (cfi, gfc_rank_cst[0]);
tmp2 = fold_convert (gfc_array_index_type,
gfc_get_cfi_desc_elem_len (cfi));
tmp = fold_build2_loc (input_location, TRUNC_MOD_EXPR,
gfc_array_index_type, tmp, tmp2);
tmp = fold_build2_loc (input_location, NE_EXPR, boolean_type_node,
tmp, gfc_index_zero_node);
tmp = build3_loc (input_location, COND_EXPR, gfc_array_index_type, tmp,
gfc_get_cfi_dim_sm (cfi, gfc_rank_cst[0]), tmp2);
}
gfc_conv_descriptor_span_set (&block2, gfc, tmp);
parmse->expr = gfc_conv_scalar_to_descriptor (parmse,
parmse->expr, attr);
/* Calculate offset + set lbound, ubound and stride. */
gfc_conv_descriptor_offset_set (&block2, gfc, gfc_index_zero_node);
/* Loop: for (i = 0; i < rank; ++i). */
tree idx = gfc_create_var (TREE_TYPE (rank), "idx");
/* Loop body. */
stmtblock_t loop_body;
gfc_init_block (&loop_body);
/* gfc->dim[i].lbound = ... */
tmp = gfc_get_cfi_dim_lbound (cfi, idx);
gfc_conv_descriptor_lbound_set (&loop_body, gfc, idx, tmp);
/* gfc->dim[i].ubound = gfc->dim[i].lbound + cfi->dim[i].extent - 1. */
tmp = fold_build2_loc (input_location, MINUS_EXPR, gfc_array_index_type,
gfc_conv_descriptor_lbound_get (gfc, idx),
gfc_index_one_node);
tmp = fold_build2_loc (input_location, PLUS_EXPR, gfc_array_index_type,
gfc_get_cfi_dim_extent (cfi, idx), tmp);
gfc_conv_descriptor_ubound_set (&loop_body, gfc, idx, tmp);
/* gfc->dim[i].stride = cfi->dim[i].sm / cfi>elem_len */
tmp = gfc_get_cfi_dim_sm (cfi, idx);
tmp = fold_build2_loc (input_location, TRUNC_DIV_EXPR,
gfc_array_index_type, tmp,
fold_convert (gfc_array_index_type,
gfc_get_cfi_desc_elem_len (cfi)));
gfc_conv_descriptor_stride_set (&loop_body, gfc, idx, tmp);
/* gfc->offset -= gfc->dim[i].stride * gfc->dim[i].lbound. */
tmp = fold_build2_loc (input_location, MULT_EXPR, gfc_array_index_type,
gfc_conv_descriptor_stride_get (gfc, idx),
gfc_conv_descriptor_lbound_get (gfc, idx));
tmp = fold_build2_loc (input_location, MINUS_EXPR, gfc_array_index_type,
gfc_conv_descriptor_offset_get (gfc), tmp);
gfc_conv_descriptor_offset_set (&loop_body, gfc, tmp);
/* Generate loop. */
gfc_simple_for_loop (&block2, idx, build_int_cst (TREE_TYPE (idx), 0),
rank, LT_EXPR, build_int_cst (TREE_TYPE (idx), 1),
gfc_finish_block (&loop_body));
}
/* Set the CFI attribute field through a temporary value for the
gfc attribute. */
desc_attr = gfc_conv_descriptor_attribute (parmse->expr);
tmp = fold_build2_loc (input_location, MODIFY_EXPR,
void_type_node, desc_attr,
build_int_cst (TREE_TYPE (desc_attr), cfi_attribute));
gfc_add_expr_to_block (&parmse->pre, tmp);
/* Now pass the gfc_descriptor by reference. */
parmse->expr = gfc_build_addr_expr (NULL_TREE, parmse->expr);
/* Variables to point to the gfc and CFI descriptors; cfi = NULL implies
that the CFI descriptor is allocated by the gfor_fndecl_gfc_to_cfi call. */
gfc_desc_ptr = parmse->expr;
cfi_desc_ptr = gfc_create_var (pvoid_type_node, "cfi");
gfc_add_modify (&parmse->pre, cfi_desc_ptr, null_pointer_node);
/* Allocate the CFI descriptor itself and fill the fields. */
tmp = gfc_build_addr_expr (NULL_TREE, cfi_desc_ptr);
tmp = build_call_expr_loc (input_location,
gfor_fndecl_gfc_to_cfi, 2, tmp, gfc_desc_ptr);
gfc_add_expr_to_block (&parmse->pre, tmp);
/* Now set the gfc descriptor attribute. */
tmp = fold_build2_loc (input_location, MODIFY_EXPR,
void_type_node, desc_attr,
build_int_cst (TREE_TYPE (desc_attr), attribute));
gfc_add_expr_to_block (&parmse->pre, tmp);
/* The CFI descriptor is passed to the bind_C procedure. */
parmse->expr = cfi_desc_ptr;
/* Free the CFI descriptor. */
tmp = gfc_call_free (cfi_desc_ptr);
gfc_prepend_expr_to_block (&parmse->post, tmp);
/* Transfer values back to gfc descriptor. */
if (cfi_attribute != 2 /* CFI_attribute_other. */
&& !fsym->attr.value
&& fsym->attr.intent != INTENT_IN)
if (e->ts.type == BT_CHARACTER && !e->ts.u.cl->length)
{
tmp = gfc_build_addr_expr (NULL_TREE, parmse->expr);
tmp = build_call_expr_loc (input_location,
gfor_fndecl_cfi_to_gfc, 2, gfc_desc_ptr, tmp);
gfc_prepend_expr_to_block (&parmse->post, tmp);
tmp = fold_convert (gfc_charlen_type_node,
gfc_get_cfi_desc_elem_len (cfi));
if (e->ts.kind != 1)
tmp = fold_build2_loc (input_location, TRUNC_DIV_EXPR,
gfc_charlen_type_node, tmp,
build_int_cst (gfc_charlen_type_node,
e->ts.kind));
gfc_add_modify (&block2, gfc_strlen, tmp);
}
/* Deal with an optional dummy being passed to an optional formal arg
by finishing the pre and post blocks and making their execution
conditional on the dummy being present. */
if (fsym->attr.optional && e->expr_type == EXPR_VARIABLE
&& e->symtree->n.sym->attr.optional)
tmp = gfc_get_cfi_desc_base_addr (cfi),
tmp = fold_build2_loc (input_location, NE_EXPR, boolean_type_node,
tmp, null_pointer_node);
tmp = build3_v (COND_EXPR, tmp, gfc_finish_block (&block2),
build_empty_stmt (input_location));
gfc_add_expr_to_block (&block, tmp);
post_call:
gfc_add_block_to_block (&block, &se.post);
if (present && block.head)
{
cond = gfc_conv_expr_present (e->symtree->n.sym);
tmp = fold_build2 (MODIFY_EXPR, void_type_node,
cfi_desc_ptr,
build_int_cst (pvoid_type_node, 0));
tmp = build3_v (COND_EXPR, cond,
gfc_finish_block (&parmse->pre), tmp);
gfc_add_expr_to_block (&parmse->pre, tmp);
tmp = build3_v (COND_EXPR, cond,
gfc_finish_block (&parmse->post),
tmp = build3_v (COND_EXPR, present, gfc_finish_block (&block),
build_empty_stmt (input_location));
gfc_add_expr_to_block (&parmse->post, tmp);
}
else if (block.head)
gfc_add_block_to_block (&parmse->post, &block);
}
@ -5764,17 +6088,12 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
arg = arg->next, formal = formal ? formal->next : NULL, ++argc)
{
bool finalized = false;
bool assumed_length_string = false;
tree derived_array = NULL_TREE;
e = arg->expr;
fsym = formal ? formal->sym : NULL;
parm_kind = MISSING;
if (fsym && fsym->ts.type == BT_CHARACTER
&& (!fsym->ts.u.cl || !fsym->ts.u.cl->length))
assumed_length_string = true;
/* If the procedure requires an explicit interface, the actual
argument is passed according to the corresponding formal
argument. If the corresponding formal argument is a POINTER,
@ -6005,9 +6324,7 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
parmse.expr = convert (type, tmp);
}
else if (sym->attr.is_bind_c && e
&& (is_CFI_desc (fsym, NULL)
|| assumed_length_string))
else if (sym->attr.is_bind_c && e && is_CFI_desc (fsym, NULL))
/* Implement F2018, 18.3.6, list item (5), bullet point 2. */
gfc_conv_gfc_desc_to_cfi_desc (&parmse, e, fsym);
@ -6217,7 +6534,8 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
if (fsym && fsym->attr.intent == INTENT_OUT
&& (fsym->attr.allocatable
|| (fsym->ts.type == BT_CLASS
&& CLASS_DATA (fsym)->attr.allocatable)))
&& CLASS_DATA (fsym)->attr.allocatable))
&& !is_CFI_desc (fsym, NULL))
{
stmtblock_t block;
tree ptr;
@ -6474,8 +6792,7 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
ref->u.ar.type = AR_SECTION;
}
if (sym->attr.is_bind_c && e
&& (is_CFI_desc (fsym, NULL) || assumed_length_string))
if (sym->attr.is_bind_c && e && is_CFI_desc (fsym, NULL))
/* Implement F2018, 18.3.6, list item (5), bullet point 2. */
gfc_conv_gfc_desc_to_cfi_desc (&parmse, e, fsym);
@ -6535,9 +6852,11 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
sym->name, NULL);
/* If an ALLOCATABLE dummy argument has INTENT(OUT) and is
allocated on entry, it must be deallocated. */
allocated on entry, it must be deallocated.
CFI descriptors are handled elsewhere. */
if (fsym && fsym->attr.allocatable
&& fsym->attr.intent == INTENT_OUT)
&& fsym->attr.intent == INTENT_OUT
&& !is_CFI_desc (fsym, NULL))
{
if (fsym->ts.type == BT_DERIVED
&& fsym->ts.u.derived->attr.alloc_comp)

View file

@ -72,7 +72,8 @@ gfc_omp_is_allocatable_or_ptr (const_tree decl)
static bool
gfc_omp_is_optional_argument (const_tree decl)
{
return (TREE_CODE (decl) == PARM_DECL
/* Note: VAR_DECL can occur with BIND(C) and array descriptors. */
return ((TREE_CODE (decl) == PARM_DECL || TREE_CODE (decl) == VAR_DECL)
&& DECL_LANG_SPECIFIC (decl)
&& TREE_CODE (TREE_TYPE (decl)) == POINTER_TYPE
&& !VOID_TYPE_P (TREE_TYPE (TREE_TYPE (decl)))
@ -105,8 +106,9 @@ gfc_omp_check_optional_argument (tree decl, bool for_present_check)
|| GFC_ARRAY_TYPE_P (TREE_TYPE (decl))))
decl = GFC_DECL_SAVED_DESCRIPTOR (decl);
/* Note: With BIND(C), array descriptors are converted to a VAR_DECL. */
if (decl == NULL_TREE
|| TREE_CODE (decl) != PARM_DECL
|| (TREE_CODE (decl) != PARM_DECL && TREE_CODE (decl) != VAR_DECL)
|| !DECL_LANG_SPECIFIC (decl)
|| !GFC_DECL_OPTIONAL_ARGUMENT (decl))
return NULL_TREE;

View file

@ -3670,10 +3670,7 @@ gfc_trans_select_rank_cases (gfc_code * code)
tree tmp;
tree cond;
tree low;
tree sexpr;
tree rank;
tree rank_minus_one;
tree minus_one;
gfc_se se;
gfc_se cse;
stmtblock_t block;
@ -3687,24 +3684,25 @@ gfc_trans_select_rank_cases (gfc_code * code)
gfc_conv_expr_descriptor (&se, code->expr1);
rank = gfc_conv_descriptor_rank (se.expr);
rank = gfc_evaluate_now (rank, &block);
minus_one = build_int_cst (TREE_TYPE (rank), -1);
tmp = fold_build2_loc (input_location, MINUS_EXPR,
gfc_array_index_type,
fold_convert (gfc_array_index_type, rank),
build_int_cst (gfc_array_index_type, 1));
rank_minus_one = gfc_evaluate_now (tmp, &block);
tmp = gfc_conv_descriptor_ubound_get (se.expr, rank_minus_one);
cond = fold_build2_loc (input_location, NE_EXPR, logical_type_node,
tmp, build_int_cst (TREE_TYPE (tmp), -1));
tmp = fold_build3_loc (input_location, COND_EXPR,
TREE_TYPE (rank), cond,
rank, minus_one);
cond = fold_build2_loc (input_location, EQ_EXPR, logical_type_node,
rank, build_int_cst (TREE_TYPE (rank), 0));
sexpr = fold_build3_loc (input_location, COND_EXPR,
TREE_TYPE (rank), cond,
rank, tmp);
sexpr = gfc_evaluate_now (sexpr, &block);
symbol_attribute attr = gfc_expr_attr (code->expr1);
if (!attr.pointer || !attr.allocatable)
{
/* Special case for assumed-rank ('rank(*)', internally -1):
rank = (rank == 0 || ubound[rank-1] != -1) ? rank : -1. */
cond = fold_build2_loc (input_location, EQ_EXPR, logical_type_node,
rank, build_int_cst (TREE_TYPE (rank), 0));
tmp = fold_build2_loc (input_location, MINUS_EXPR, gfc_array_index_type,
fold_convert (gfc_array_index_type, rank),
gfc_index_one_node);
tmp = gfc_conv_descriptor_ubound_get (se.expr, tmp);
tmp = fold_build2_loc (input_location, NE_EXPR, logical_type_node,
tmp, build_int_cst (TREE_TYPE (tmp), -1));
cond = fold_build2_loc (input_location, TRUTH_ORIF_EXPR,
logical_type_node, cond, tmp);
tmp = fold_build3_loc (input_location, COND_EXPR, TREE_TYPE (rank),
cond, rank, build_int_cst (TREE_TYPE (rank), -1));
rank = gfc_evaluate_now (tmp, &block);
}
TREE_USED (code->exit_label) = 0;
repeat:
@ -3748,8 +3746,8 @@ repeat:
if (low != NULL_TREE)
{
cond = fold_build2_loc (input_location, EQ_EXPR,
TREE_TYPE (sexpr), sexpr,
fold_convert (TREE_TYPE (sexpr), low));
TREE_TYPE (rank), rank,
fold_convert (TREE_TYPE (rank), low));
tmp = fold_build3_loc (input_location, COND_EXPR, void_type_node,
cond, tmp,
build_empty_stmt (input_location));

View file

@ -77,6 +77,7 @@ static GTY(()) tree gfc_desc_dim_type;
static GTY(()) tree gfc_max_array_element_size;
static GTY(()) tree gfc_array_descriptor_base[2 * (GFC_MAX_DIMENSIONS+1)];
static GTY(()) tree gfc_array_descriptor_base_caf[2 * (GFC_MAX_DIMENSIONS+1)];
static GTY(()) tree gfc_cfi_descriptor_base[2 * (CFI_MAX_RANK + 2)];
/* Arrays for all integral and real kinds. We'll fill this in at runtime
after the target has a chance to process command-line options. */
@ -1575,8 +1576,9 @@ gfc_get_dtype_rank_type (int rank, tree etype)
field = gfc_advance_chain (TYPE_FIELDS (dtype_type_node),
GFC_DTYPE_RANK);
CONSTRUCTOR_APPEND_ELT (v, field,
build_int_cst (TREE_TYPE (field), rank));
if (rank >= 0)
CONSTRUCTOR_APPEND_ELT (v, field,
build_int_cst (TREE_TYPE (field), rank));
field = gfc_advance_chain (TYPE_FIELDS (dtype_type_node),
GFC_DTYPE_TYPE);
@ -2244,7 +2246,7 @@ gfc_nonrestricted_type (tree t)
especially for character and array types. */
tree
gfc_sym_type (gfc_symbol * sym)
gfc_sym_type (gfc_symbol * sym, bool is_bind_c)
{
tree type;
int byref;
@ -2299,7 +2301,11 @@ gfc_sym_type (gfc_symbol * sym)
if (!restricted)
type = gfc_nonrestricted_type (type);
if (sym->attr.dimension || sym->attr.codimension)
/* Dummy argument to a bind(C) procedure. */
if (is_bind_c && is_CFI_desc (sym, NULL))
type = gfc_get_cfi_type (sym->attr.dimension ? sym->as->rank : 0,
/* restricted = */ false);
else if (sym->attr.dimension || sym->attr.codimension)
{
if (gfc_is_nodesc_array (sym))
{
@ -3132,7 +3138,7 @@ gfc_get_function_type (gfc_symbol * sym, gfc_actual_arglist *actual_args,
type = build_pointer_type (type);
}
else
type = gfc_sym_type (arg);
type = gfc_sym_type (arg, sym->attr.is_bind_c);
/* Parameter Passing Convention
@ -3723,4 +3729,95 @@ gfc_get_caf_reference_type ()
return reference_type;
}
static tree
gfc_get_cfi_dim_type ()
{
static tree CFI_dim_t = NULL;
if (CFI_dim_t)
return CFI_dim_t;
CFI_dim_t = make_node (RECORD_TYPE);
TYPE_NAME (CFI_dim_t) = get_identifier ("CFI_dim_t");
TYPE_NAMELESS (CFI_dim_t) = 1;
tree field;
tree *chain = NULL;
field = gfc_add_field_to_struct_1 (CFI_dim_t, get_identifier ("lower_bound"),
gfc_array_index_type, &chain);
suppress_warning (field);
field = gfc_add_field_to_struct_1 (CFI_dim_t, get_identifier ("extent"),
gfc_array_index_type, &chain);
suppress_warning (field);
field = gfc_add_field_to_struct_1 (CFI_dim_t, get_identifier ("sm"),
gfc_array_index_type, &chain);
suppress_warning (field);
gfc_finish_type (CFI_dim_t);
TYPE_DECL_SUPPRESS_DEBUG (TYPE_STUB_DECL (CFI_dim_t)) = 1;
return CFI_dim_t;
}
/* Return the CFI type; use dimen == -1 for dim[] (only for pointers);
otherwise dim[dimen] is used. */
tree
gfc_get_cfi_type (int dimen, bool restricted)
{
gcc_assert (dimen >= -1 && dimen <= CFI_MAX_RANK);
int idx = 2*(dimen + 1) + restricted;
if (gfc_cfi_descriptor_base[idx])
return gfc_cfi_descriptor_base[idx];
/* Build the type node. */
tree CFI_cdesc_t = make_node (RECORD_TYPE);
char name[GFC_MAX_SYMBOL_LEN + 1];
if (dimen != -1)
sprintf (name, "CFI_cdesc_t" GFC_RANK_PRINTF_FORMAT, dimen);
TYPE_NAME (CFI_cdesc_t) = get_identifier (dimen < 0 ? "CFI_cdesc_t" : name);
TYPE_NAMELESS (CFI_cdesc_t) = 1;
tree field;
tree *chain = NULL;
field = gfc_add_field_to_struct_1 (CFI_cdesc_t, get_identifier ("base_addr"),
(restricted ? prvoid_type_node
: ptr_type_node), &chain);
suppress_warning (field);
field = gfc_add_field_to_struct_1 (CFI_cdesc_t, get_identifier ("elem_len"),
size_type_node, &chain);
suppress_warning (field);
field = gfc_add_field_to_struct_1 (CFI_cdesc_t, get_identifier ("version"),
integer_type_node, &chain);
suppress_warning (field);
field = gfc_add_field_to_struct_1 (CFI_cdesc_t, get_identifier ("rank"),
signed_char_type_node, &chain);
suppress_warning (field);
field = gfc_add_field_to_struct_1 (CFI_cdesc_t, get_identifier ("attribute"),
signed_char_type_node, &chain);
suppress_warning (field);
field = gfc_add_field_to_struct_1 (CFI_cdesc_t, get_identifier ("type"),
get_typenode_from_name (INT16_TYPE),
&chain);
suppress_warning (field);
if (dimen != 0)
{
tree range = NULL_TREE;
if (dimen > 0)
range = gfc_rank_cst[dimen - 1];
range = build_range_type (gfc_array_index_type, gfc_index_zero_node,
range);
tree CFI_dim_t = build_array_type (gfc_get_cfi_dim_type (), range);
field = gfc_add_field_to_struct_1 (CFI_cdesc_t, get_identifier ("dim"),
CFI_dim_t, &chain);
suppress_warning (field);
}
TYPE_TYPELESS_STORAGE (CFI_cdesc_t) = 1;
gfc_finish_type (CFI_cdesc_t);
gfc_cfi_descriptor_base[idx] = CFI_cdesc_t;
return CFI_cdesc_t;
}
#include "gt-fortran-trans-types.h"

View file

@ -84,7 +84,8 @@ tree gfc_get_character_type (int, gfc_charlen *);
tree gfc_get_character_type_len (int, tree);
tree gfc_get_character_type_len_for_eltype (tree, tree);
tree gfc_sym_type (gfc_symbol *);
tree gfc_sym_type (gfc_symbol *, bool is_bind_c_arg = false);
tree gfc_get_cfi_type (int dimen, bool restricted);
tree gfc_typenode_for_spec (gfc_typespec *, int c = 0);
int gfc_copy_dt_decls_ifequal (gfc_symbol *, gfc_symbol *, bool);

View file

@ -608,9 +608,9 @@ gfc_trans_runtime_check (bool error, bool once, tree cond, stmtblock_t * pblock,
if (once)
{
tmpvar = gfc_create_var (logical_type_node, "print_warning");
tmpvar = gfc_create_var (boolean_type_node, "print_warning");
TREE_STATIC (tmpvar) = 1;
DECL_INITIAL (tmpvar) = logical_true_node;
DECL_INITIAL (tmpvar) = boolean_true_node;
gfc_add_expr_to_block (pblock, tmpvar);
}
@ -631,7 +631,7 @@ gfc_trans_runtime_check (bool error, bool once, tree cond, stmtblock_t * pblock,
va_end (ap);
if (once)
gfc_add_modify (&block, tmpvar, logical_false_node);
gfc_add_modify (&block, tmpvar, boolean_false_node);
body = gfc_finish_block (&block);
@ -643,9 +643,8 @@ gfc_trans_runtime_check (bool error, bool once, tree cond, stmtblock_t * pblock,
{
if (once)
cond = fold_build2_loc (gfc_get_location (where), TRUTH_AND_EXPR,
long_integer_type_node, tmpvar, cond);
else
cond = fold_convert (long_integer_type_node, cond);
boolean_type_node, tmpvar,
fold_convert (boolean_type_node, cond));
tmp = fold_build3_loc (gfc_get_location (where), COND_EXPR, void_type_node,
cond, body,

View file

@ -857,8 +857,6 @@ extern GTY(()) tree gfor_fndecl_ctime;
extern GTY(()) tree gfor_fndecl_fdate;
extern GTY(()) tree gfor_fndecl_in_pack;
extern GTY(()) tree gfor_fndecl_in_unpack;
extern GTY(()) tree gfor_fndecl_cfi_to_gfc;
extern GTY(()) tree gfor_fndecl_gfc_to_cfi;
extern GTY(()) tree gfor_fndecl_associated;
extern GTY(()) tree gfor_fndecl_system_clock4;
extern GTY(()) tree gfor_fndecl_system_clock8;

View file

@ -0,0 +1,28 @@
! { dg-do run }
! This testcase failed before with optimization as
! allocatef's CFI descriptor argument 'x' failed with -fstrict-alias due to
! internally alising with the GFC descriptor
!
program testit
use iso_c_binding
implicit none (external, type)
type, bind (c) :: m
integer(C_INT) :: i, j
end type
type(m), allocatable :: a(:)
call testf (a)
contains
subroutine allocatef (x) bind (c)
type(m), allocatable :: x(:)
allocate (x(5:15))
end subroutine
subroutine testf (y)
type(m), allocatable, target :: y(:)
call allocatef (y)
if (.not. allocated (y)) stop 1
end subroutine
end program

View file

@ -19,23 +19,37 @@ contains
subroutine substr(str) BIND(C)
character(*) :: str(:)
if (str(2) .ne. "ghi") stop 2
if (str(1) .ne. "bcd") stop 2
if (str(2) .ne. "ghi") stop 3
str = ['uvw','xyz']
end subroutine
subroutine substr4(str4) BIND(C)
character(*, kind=4) :: str4(:)
print *, str4(1)
print *, str4(2)
if (str4(1) .ne. 4_"bcd") stop 4
if (str4(2) .ne. 4_"ghi") stop 5
str4 = [4_'uvw', 4_'xyz']
end subroutine
end module
program p
use mod_ctg
implicit none
real :: x(6)
character(5) :: str(2) = ['abcde','fghij']
character(5) :: str(2) = ['abcde', 'fghij']
character(5, kind=4) :: str4(2) = [4_'abcde', 4_'fghij']
integer :: i
x = [ (real(i), i=1, size(x)) ]
call ctg(x(2::2))
if (any (abs (x - [1.,20.,3.,40.,5.,60.]) > 1.e-6)) stop 3
call substr(str(:)(2:4))
if (any (str .ne. ['auvwe','fxyzj'])) stop 4
!call substr(str(:)(2:4))
!if (any (str .ne. ['auvwe','fxyzj'])) stop 4
call substr4(str4(:)(2:4))
if (any (str4 .ne. [4_'auvwe', 4_'fxyzj'])) stop 4
end program

View file

@ -1,5 +1,5 @@
! Fails on x86 targets where sizeof(long double) == 16.
! { dg-do run { xfail { { x86_64*-*-* i?86*-*-* } && longdouble128 } } }
! { dg-do run }
! { dg-additional-sources PR100914.c }
! { dg-require-effective-target fortran_real_c_float128 }
! { dg-additional-options "-Wno-pedantic" }

View file

@ -67,7 +67,7 @@ check_fn (const CFI_cdesc_t *restrict auxp, const CFI_type_t type, const signed
/* */
assert (auxp->type==type);
ityp = _CFI_decode_type(auxp->type);
assert (ityp == CFI_type_cptr);
assert (ityp == CFI_type_cfunptr);
iknd = _CFI_decode_kind(auxp->type);
assert (_CFI_decode_type(type)==ityp);
assert (kind==iknd);

View file

@ -14,7 +14,7 @@ module isof_m
private
public :: &
CFI_type_cptr
CFI_type_cptr, CFI_type_cfunptr
public :: &
check_fn_as, &
@ -33,6 +33,7 @@ module isof_m
! Intrinsic types. Their kind number defines their storage size. */
integer(kind=c_signed_char), parameter :: CFI_type_cptr = 7
integer(kind=c_signed_char), parameter :: CFI_type_cfunptr = 8
interface
subroutine check_fn_as(a, t, k, e, n) &
@ -99,7 +100,7 @@ module iso_check_m
c_funptr, c_funloc, c_associated
use :: isof_m, only: &
CFI_type_cptr
CFI_type_cptr, CFI_type_cfunptr
use :: isof_m, only: &
check_fn_as, &
@ -155,7 +156,7 @@ contains
!
k = 0
e = storage_size(a)/b
t = cfi_encode_type(CFI_type_cptr, k)
t = cfi_encode_type(CFI_type_cfunptr, k)
! Assumes 64-bit target.
! if(e/=8) stop 5
do i = 1, n
@ -176,7 +177,7 @@ contains
!
k = 0
e = storage_size(a)/b
t = cfi_encode_type(CFI_type_cptr, k)
t = cfi_encode_type(CFI_type_cfunptr, k)
! Assumes 64-bit target.
! if(e/=8) stop 8
do i = 1, n
@ -198,7 +199,7 @@ contains
!
k = 0
e = storage_size(a)/b
t = cfi_encode_type(CFI_type_cptr, k)
t = cfi_encode_type(CFI_type_cfunptr, k)
! Assumes 64-bit target.
! if(e/=8) stop 11
select rank(a)
@ -229,7 +230,7 @@ contains
!
k = 0
e = storage_size(a)/b
t = cfi_encode_type(CFI_type_cptr, k)
t = cfi_encode_type(CFI_type_cfunptr, k)
! Assumes 64-bit target.
! if(e/=8) stop 16
select rank(a)

View file

@ -3,6 +3,8 @@
! Test the fix for PR93963
!
module m
contains
function rank_p(this) result(rnk) bind(c)
use, intrinsic :: iso_c_binding, only: c_int
@ -97,27 +99,60 @@ function rank_a(this) result(rnk) bind(c)
return
end function rank_a
program selr_p
function rank_o(this) result(rnk) bind(c)
use, intrinsic :: iso_c_binding, only: c_int
implicit none
integer(kind=c_int), intent(in) :: this(..)
integer(kind=c_int) :: rnk
interface
function rank_p(this) result(rnk) bind(c)
use, intrinsic :: iso_c_binding, only: c_int
integer(kind=c_int), pointer, intent(in) :: this(..)
integer(kind=c_int) :: rnk
end function rank_p
end interface
select rank(this)
rank(0)
rnk = 0
rank(1)
rnk = 1
rank(2)
rnk = 2
rank(3)
rnk = 3
rank(4)
rnk = 4
rank(5)
rnk = 5
rank(6)
rnk = 6
rank(7)
rnk = 7
rank(8)
rnk = 8
rank(9)
rnk = 9
rank(10)
rnk = 10
rank(11)
rnk = 11
rank(12)
rnk = 12
rank(13)
rnk = 13
rank(14)
rnk = 14
rank(15)
rnk = 15
rank default
rnk = -1000
end select
return
end function rank_o
interface
function rank_a(this) result(rnk) bind(c)
use, intrinsic :: iso_c_binding, only: c_int
integer(kind=c_int), allocatable, intent(in) :: this(..)
integer(kind=c_int) :: rnk
end function rank_a
end interface
end module m
program selr_p
use m
use, intrinsic :: iso_c_binding, only: c_int
implicit none
integer(kind=c_int), parameter :: siz = 7
integer(kind=c_int), parameter :: rnk = 1
@ -139,12 +174,19 @@ program selr_p
irnk = rank_p(intp)
if (irnk /= rnk) stop 5
if (irnk /= rank(intp)) stop 6
irnk = rank_o(intp)
if (irnk /= rnk) stop 7
if (irnk /= rank(intp)) stop 8
deallocate(intp)
nullify(intp)
!
allocate(inta(siz))
if (irnk /= rnk) stop 7
if (irnk /= rank(inta)) stop 8
irnk = rank_a(inta)
if (irnk /= rnk) stop 9
if (irnk /= rank(inta)) stop 10
irnk = rank_o(inta)
if (irnk /= rnk) stop 11
if (irnk /= rank(inta)) stop 12
deallocate(inta)
end program selr_p

View file

@ -0,0 +1,34 @@
! PR fortran/102086
implicit none (type, external)
contains
subroutine as(a)
type(*) :: a(:,:)
end
subroutine ar(b)
type(*) :: b(..)
end
subroutine bar(x,y)
type(*) :: x
type(*) :: y(3,*)
call as(x) ! { dg-error "Rank mismatch in argument 'a' at .1. \\(rank-2 and scalar\\)" }
call ar(x) ! { dg-error "Assumed-type actual argument at .1. corresponding to assumed-rank dummy argument 'b' must be assumed-shape or assumed-rank" }
call ar(y) ! { dg-error "Assumed-type actual argument at .1. corresponding to assumed-rank dummy argument 'b' must be assumed-shape or assumed-rank" }
call as(y(1,3)) ! { dg-error "Assumed-type variable y at .1. shall not have a subobject reference" }
call ar(y(1,3)) ! { dg-error "Assumed-type variable y at .1. shall not have a subobject reference" }
call as(y(1:1,3:3)) ! { dg-error "Assumed-type variable y at .1. shall not have a subobject reference" }
call ar(y(1:1,3:3)) ! { dg-error "Assumed-type variable y at .1. shall not have a subobject reference" }
end
subroutine okayish(x,y,z)
type(*) :: x(:)
type(*) :: y(:,:)
type(*) :: z(..)
call as(x) ! { dg-error "Rank mismatch in argument 'a' at .1. \\(rank-2 and rank-1\\)" }
call as(y)
call as(z) ! { dg-error "The assumed-rank array at .1. requires that the dummy argument 'a' has assumed-rank" }
call ar(x)
call ar(y)
call ar(z)
end
end

View file

@ -0,0 +1,26 @@
#include <ISO_Fortran_binding.h>
void
test_c (CFI_cdesc_t *x, size_t n, int num)
{
if (!x->base_addr)
__builtin_abort ();
if (x->version != CFI_VERSION)
__builtin_abort ();
if (x->rank != 1)
__builtin_abort ();
if (x->attribute != CFI_attribute_other)
__builtin_abort ();
if (x->dim[0].lower_bound != 0)
__builtin_abort ();
if (x->dim[0].extent != 3)
__builtin_abort ();
if (x->elem_len != n || x->dim[0].sm != n)
__builtin_abort ();
if (num == 1 && x->type != CFI_type_int16_t)
__builtin_abort ();
if (num == 2 && x->type != CFI_type_double_Complex)
__builtin_abort ();
}

View file

@ -0,0 +1,66 @@
! { dg-do run }
! { dg-additional-sources assumed_type_13.c }
use iso_c_binding, only: c_size_t, c_int
implicit none (type, external)
interface
subroutine test_c (x, n, num) bind (C)
import :: c_size_t, c_int
integer(c_size_t), value :: n
integer(c_int), value :: num
type(*) :: x(:)
end subroutine test_c
end interface
complex(8) :: b(3)
call test_c ([1_2, 2_2, 3_2], sizeof(1_2), num=1)
call test_c (b, sizeof(b(1)), num=2)
call outer_bc ([1_2, 2_2, 3_2], sizeof(1_2), num=1)
call outer_bc (b, sizeof(b(1)), num=2)
call outer_f ([1_2, 2_2, 3_2], sizeof(1_2), num=1)
call outer_f (b, sizeof(b(1)), num=2)
contains
subroutine outer_bc (x, n, num) bind(C)
integer(c_size_t), value :: n
integer(c_int), value :: num
type(*) :: x(:)
! print *,sizeof(x)/size(x), n
if (sizeof(x)/size(x) /= n) error stop 1
call inner_bc (x, n, num)
call inner_f (x, n, num)
call test_c (x, n, num)
end
subroutine outer_f (x, n, num)
integer(c_size_t), value :: n
integer(c_int), value :: num
type(*) :: x(:)
! print *,sizeof(x)/size(x), n
if (sizeof(x)/size(x) /= n) error stop 1
call inner_f (x, n, num)
call inner_bc (x, n, num)
call test_c (x, n, num)
end
subroutine inner_bc(x, n, num) bind(C)
integer(c_size_t), value :: n
integer(c_int), value :: num
type(*) :: x(:)
! print *,sizeof(x)/size(x), n
if (sizeof(x)/size(x) /= n) error stop 2
call test_c (x, n, num)
end
subroutine inner_f(x, n, num)
integer(c_size_t), value :: n
integer(c_int), value :: num
type(*) :: x(:)
! print *,sizeof(x)/size(x), n
if (sizeof(x)/size(x) /= n) error stop 3
call test_c (x, n, num)
end
end

View file

@ -0,0 +1,104 @@
! PR fortran/92482
!
! Contributed by José Rui Faustino de Sousa
!
! Note the xfail issue below for 'strg_print_2("abc")
program strp_p
use, intrinsic :: iso_c_binding, only: &
c_char
implicit none
integer, parameter :: l = 3
character(len=l, kind=c_char), target :: str
character(len=:, kind=c_char), pointer :: strp_1
character(len=l, kind=c_char), pointer :: strp_2
str = "abc"
nullify(strp_1, strp_2)
strp_1 => str
strp_2 => str
if (len(str) /= 3 .or. str /= "abc") stop 1
if (len(strp_1) /= 3 .or. strp_1 /= "abc") stop 2
if (len(strp_2) /= 3 .or. strp_2 /= "abc") stop 3
call strg_print_0("abc") ! Error (10.0.0) or segmentation fault (9.1.0)
call strg_print_0(str) ! Error (10.0.0) or segmentation fault (9.1.0)
call strg_print_0(strp_1) ! Error (10.0.0) or segmentation fault (9.1.0)
call strg_print_0(strp_2) ! Error (10.0.0) or segmentation fault (9.1.0)
call strg_print_1(strp_1) ! Not yet supported
call strg_print_2("abc", xfail=.true.)
call strg_print_2(str)
call strg_print_2(strp_1)
call strg_print_2(strp_2)
call strg_print_2_c("abc")
call strg_print_2_c(str)
call strg_print_2_c(strp_1)
call strg_print_2_c(strp_2)
contains
subroutine strg_print_0(this) bind(c) ! Error (10.0.0 20191106) or warning (9.1.0) issued with bind(c)
character(len=*, kind=c_char), target, intent(in) :: this
if (len (this) /= 3) stop 10
if (this /= "abc") stop 11
end subroutine strg_print_0
subroutine strg_print_1(this) bind(c) ! Not yet supported with bind(c)
character(len=:, kind=c_char), pointer, intent(in) :: this
character(len=:), pointer :: strn
if (.not. associated (this)) stop 20
if (len (this) /= 3) stop 21
if (this /= "abc") stop 22
strn => this
if (.not. associated (strn)) stop 23
if(associated(strn))then
if (len (this) /= 3) stop 24
if (this /= "abc") stop 25
end if
end subroutine strg_print_1
subroutine strg_print_2(this, xfail)
use, intrinsic :: iso_c_binding, only: &
c_loc, c_f_pointer
type(*), target, intent(in) :: this(..)
logical, optional, value :: xfail
character(len=l), pointer :: strn
call c_f_pointer(c_loc(this), strn)
if (.not. associated (strn)) stop 30
if(associated(strn))then
if (len (strn) /= 3) stop 31
if (strn /= "abc") then
if (present (xfail)) then
print *, 'INVALID STRING - EXPECTED "abc" / PR47225'
else
stop 32
end if
end if
end if
end subroutine strg_print_2
subroutine strg_print_2_c(this) bind(c)
use, intrinsic :: iso_c_binding, only: &
c_loc, c_f_pointer
type(*), target, intent(in) :: this(..)
character(len=l), pointer :: strn
call c_f_pointer(c_loc(this), strn)
if (.not. associated (strn)) stop 40
if(associated(strn))then
if (len (strn) /= 3) stop 41
if (strn /= "abc") stop 42
end if
end subroutine strg_print_2_c
end program strp_p

View file

@ -0,0 +1,345 @@
#include <ISO_Fortran_binding.h>
#include <stdbool.h>
#include <string.h>
struct loc_t {
intptr_t x, y, z;
};
typedef struct loc_t (*ftn_fn) (CFI_cdesc_t *, CFI_cdesc_t *, CFI_cdesc_t *, int, int);
struct loc_t char_assumed_size_f (CFI_cdesc_t *, CFI_cdesc_t *, CFI_cdesc_t *, int, int);
struct loc_t char_assumed_size_in_f (CFI_cdesc_t *, CFI_cdesc_t *, CFI_cdesc_t *, int, int);
struct loc_t char_expl_size_f (CFI_cdesc_t *,CFI_cdesc_t *, CFI_cdesc_t *, int, int);
struct loc_t char_expl_size_in_f (CFI_cdesc_t *,CFI_cdesc_t *, CFI_cdesc_t *, int, int);
struct loc_t char_assumed_rank_f (CFI_cdesc_t *, CFI_cdesc_t *, CFI_cdesc_t *, int, int);
struct loc_t char_assumed_rank_in_f (CFI_cdesc_t *, CFI_cdesc_t *, CFI_cdesc_t *, int, int);
struct loc_t char_assumed_rank_cont_f (CFI_cdesc_t *, CFI_cdesc_t *, CFI_cdesc_t *, int, int);
struct loc_t char_assumed_rank_cont_in_f (CFI_cdesc_t *, CFI_cdesc_t *, CFI_cdesc_t *, int, int);
struct loc_t char_assumed_shape_f (CFI_cdesc_t *, CFI_cdesc_t *, CFI_cdesc_t *, int, int);
struct loc_t char_assumed_shape_in_f (CFI_cdesc_t *, CFI_cdesc_t *, CFI_cdesc_t *, int, int);
struct loc_t char_assumed_shape_cont_f (CFI_cdesc_t *, CFI_cdesc_t *, CFI_cdesc_t *, int, int);
struct loc_t char_assumed_shape_cont_in_f (CFI_cdesc_t *, CFI_cdesc_t *, CFI_cdesc_t *, int, int);
static void
basic_check(CFI_cdesc_t *x, bool is_cont)
{
if (!x->base_addr)
__builtin_abort ();
if (x->elem_len != 3*sizeof(char))
__builtin_abort ();
if (x->version != CFI_VERSION)
__builtin_abort ();
if (x->rank != 1)
__builtin_abort ();
if (x->attribute != CFI_attribute_other)
__builtin_abort ();
if (x->type != CFI_type_char)
__builtin_abort ();
if (x->dim[0].lower_bound != 0)
__builtin_abort ();
if (x->dim[0].extent != 3)
__builtin_abort ();
if (CFI_is_contiguous (x) != (x->elem_len == x->dim[0].sm))
__builtin_abort ();
if (is_cont != CFI_is_contiguous (x))
__builtin_abort ();
}
static void
print_str (void *p, size_t len)
{
__builtin_printf ("DEBUG: >");
for (size_t i = 0; i < len; ++i)
__builtin_printf ("%c", ((const char*) p)[i]);
__builtin_printf ("<\n");
}
static void
check_str (CFI_cdesc_t *x, const char *str, const CFI_index_t subscripts[])
{
/* Avoid checking for '\0'. */
if (strncmp ((const char*) CFI_address (x, subscripts), str, strlen(str)) != 0)
__builtin_abort ();
}
static void
set_str (CFI_cdesc_t *x, const char *str, const CFI_index_t subscripts[])
{
char *p = CFI_address (x, subscripts);
size_t len = strlen (str);
if (x->elem_len != len)
__builtin_abort ();
for (size_t i = 0; i < len; ++i)
p[i] = str[i];
}
static struct loc_t
do_call (CFI_cdesc_t *x, CFI_cdesc_t *y, CFI_cdesc_t *z,
int k, int num, bool intent_in, ftn_fn fn, bool is_cont, bool fort_cont)
{
const CFI_index_t zero[1] = { 0 };
const CFI_index_t one[1] = { 1 };
const CFI_index_t two[1] = { 2 };
struct loc_t addr1, addr2;
if (k != 3)
__builtin_abort ();
basic_check (x, is_cont || num == 2);
basic_check (y, is_cont || num == 2);
basic_check (z, is_cont || num == 2);
if (!is_cont && num == 1)
{
check_str (x, "abc", zero);
check_str (x, "ghi", one);
check_str (x, "nop", two);
check_str (y, "abc", zero);
check_str (y, "ghi", one);
check_str (y, "nop", two);
check_str (z, "abc", zero);
check_str (z, "ghi", one);
check_str (z, "nop", two);
}
else if (num == 1)
{
if (strncmp ((const char*) x->base_addr, "abcghinop", 9) != 0)
__builtin_abort ();
if (strncmp ((const char*) y->base_addr, "abcghinop", 9) != 0)
__builtin_abort ();
if (strncmp ((const char*) z->base_addr, "abcghinop", 9) != 0)
__builtin_abort ();
}
else if (num == 2)
{
if (strncmp ((const char*) x->base_addr, "defghijlm", 9) != 0)
__builtin_abort ();
if (strncmp ((const char*) y->base_addr, "defghijlm", 9) != 0)
__builtin_abort ();
if (strncmp ((const char*) z->base_addr, "defghijlm", 9) != 0)
__builtin_abort ();
}
else
__builtin_abort ();
addr1.x = (intptr_t) x->base_addr;
addr1.y = (intptr_t) y->base_addr;
addr1.z = (intptr_t) z->base_addr;
addr2 = fn (x, y, z, 3, num);
if (!CFI_is_contiguous (x) && fort_cont)
{
/* Check for callee copy in/copy out. */
if (addr1.x == addr2.x || addr1.x != (intptr_t) x->base_addr)
__builtin_abort ();
if (addr1.y == addr2.y || addr1.y != (intptr_t) y->base_addr)
__builtin_abort ();
if (addr1.z == addr2.z || addr1.z != (intptr_t) z->base_addr)
__builtin_abort ();
}
else
{
if (addr1.x != addr2.x || addr1.x != (intptr_t) x->base_addr)
__builtin_abort ();
if (addr1.y != addr2.y || addr1.y != (intptr_t) y->base_addr)
__builtin_abort ();
if (addr1.z != addr2.z || addr1.z != (intptr_t) z->base_addr)
__builtin_abort ();
}
// intent_in
if (intent_in && !is_cont && num == 1)
{
check_str (x, "abc", zero);
check_str (x, "ghi", one);
check_str (x, "nop", two);
check_str (y, "abc", zero);
check_str (y, "ghi", one);
check_str (y, "nop", two);
check_str (z, "abc", zero);
check_str (z, "ghi", one);
check_str (z, "nop", two);
}
else if (intent_in && num == 1)
{
if (strncmp ((const char*) x->base_addr, "abcghinop", 9) != 0)
__builtin_abort ();
if (strncmp ((const char*) y->base_addr, "abcghinop", 9) != 0)
__builtin_abort ();
if (strncmp ((const char*) z->base_addr, "abcghinop", 9) != 0)
__builtin_abort ();
}
else if (intent_in && num == 2)
{
if (strncmp ((const char*) x->base_addr, "defghijlm", 9) != 0)
__builtin_abort ();
if (strncmp ((const char*) y->base_addr, "defghijlm", 9) != 0)
__builtin_abort ();
if (strncmp ((const char*) z->base_addr, "defghijlm", 9) != 0)
__builtin_abort ();
}
else if (intent_in)
__builtin_abort ();
if (intent_in)
{
if (is_cont && num == 1)
{
/* Copy in - set the value to check that no copy out is done. */
memcpy ((char*) x->base_addr, "123456789", 9);
memcpy ((char*) y->base_addr, "123456789", 9);
memcpy ((char*) z->base_addr, "123456789", 9);
}
return addr1;
}
// !intent_in
if (!is_cont && num == 1)
{
check_str (x, "ABC", zero);
check_str (x, "DEF", one);
check_str (x, "GHI", two);
check_str (y, "ABC", zero);
check_str (y, "DEF", one);
check_str (y, "GHI", two);
check_str (z, "ABC", zero);
check_str (z, "DEF", one);
check_str (z, "GHI", two);
}
else
{
if (strncmp ((const char*) x->base_addr, "ABCDEFGHI", 9) != 0)
__builtin_abort ();
if (strncmp ((const char*) y->base_addr, "ABCDEFGHI", 9) != 0)
__builtin_abort ();
if (strncmp ((const char*) z->base_addr, "ABCDEFGHI", 9) != 0)
__builtin_abort ();
}
return addr1;
}
struct loc_t
char_assumed_size_c (CFI_cdesc_t *x, CFI_cdesc_t *y, CFI_cdesc_t *z,
int k, int num)
{
return do_call (x, y, z, k, num, false, char_assumed_size_f, true, false);
}
struct loc_t
char_assumed_size_in_c (CFI_cdesc_t *x, CFI_cdesc_t *y, CFI_cdesc_t *z,
int k, int num)
{
return do_call (x, y, z, k, num, true, char_assumed_size_in_f, true, false);
}
struct loc_t
char_expl_size_c (CFI_cdesc_t *x, CFI_cdesc_t *y, CFI_cdesc_t *z,
int k, int num)
{
return do_call (x, y, z, k, num, false, char_expl_size_f, true, false);
}
struct loc_t
char_expl_size_in_c (CFI_cdesc_t *x, CFI_cdesc_t *y, CFI_cdesc_t *z,
int k, int num)
{
return do_call (x, y, z, k, num, true, char_expl_size_in_f, true, false);
}
struct loc_t
char_assumed_rank_c (CFI_cdesc_t *x, CFI_cdesc_t *y, CFI_cdesc_t *z,
int k, int num)
{
return do_call (x, y, z, k, num, false, char_assumed_rank_f, false, false);
}
struct loc_t
char_assumed_rank_in_c (CFI_cdesc_t *x, CFI_cdesc_t *y, CFI_cdesc_t *z,
int k, int num)
{
return do_call (x, y, z, k, num, true, char_assumed_rank_in_f, false, false);
}
struct loc_t
char_assumed_rank_cont_c (CFI_cdesc_t *x, CFI_cdesc_t *y, CFI_cdesc_t *z,
int k, int num)
{
return do_call (x, y, z, k, num, false, char_assumed_rank_cont_f, true, false);
}
struct loc_t
char_assumed_rank_cont_in_c (CFI_cdesc_t *x, CFI_cdesc_t *y, CFI_cdesc_t *z,
int k, int num)
{
return do_call (x, y, z, k, num, true, char_assumed_rank_cont_in_f, true, false);
}
static void
reset_var (CFI_cdesc_t *x, int num)
{
const CFI_index_t zero[1] = { 0 };
const CFI_index_t one[1] = { 1 };
const CFI_index_t two[1] = { 2 };
if (num == 1)
{
set_str (x, "abc", zero);
set_str (x, "ghi", one);
set_str (x, "nop", two);
}
else if (num == 2)
{
set_str (x, "def", zero);
set_str (x, "ghi", one);
set_str (x, "jlm", two);
}
else
__builtin_abort ();
}
static void
reset_vars (CFI_cdesc_t *x, CFI_cdesc_t *y, CFI_cdesc_t *z, int num)
{
reset_var (x, num);
reset_var (y, num);
reset_var (z, num);
}
struct loc_t
char_assumed_shape_c (CFI_cdesc_t *x, CFI_cdesc_t *y, CFI_cdesc_t *z,
int k, int num)
{
/* Make use of having a noncontiguous argument to check that the callee
handles noncontiguous variables. */
do_call (x, y, z, k, num, false, char_assumed_size_f, false, true);
reset_vars (x, y, z, num);
do_call (x, y, z, k, num, true, char_assumed_size_in_f, false, true);
reset_vars (x, y, z, num);
do_call (x, y, z, k, num, false, char_expl_size_f, false, true);
reset_vars (x, y, z, num);
do_call (x, y, z, k, num, true, char_expl_size_in_f, false, true);
reset_vars (x, y, z, num);
do_call (x, y, z, k, num, false, char_assumed_rank_cont_f, false, true);
reset_vars (x, y, z, num);
do_call (x, y, z, k, num, true, char_assumed_rank_cont_in_f, false, true);
reset_vars (x, y, z, num);
do_call (x, y, z, k, num, false, char_assumed_shape_cont_f, false, true);
reset_vars (x, y, z, num);
do_call (x, y, z, k, num, true, char_assumed_shape_cont_in_f, false, true);
/* Actual func call. */
reset_vars (x, y, z, num);
return do_call (x, y, z, k, num, false, char_assumed_shape_f, false, false);
}
struct loc_t
char_assumed_shape_in_c (CFI_cdesc_t *x, CFI_cdesc_t *y, CFI_cdesc_t *z,
int k, int num)
{
return do_call (x, y, z, k, num, true, char_assumed_shape_in_f, false, false);
}
struct loc_t
char_assumed_shape_cont_c (CFI_cdesc_t *x, CFI_cdesc_t *y, CFI_cdesc_t *z,
int k, int num)
{
return do_call (x, y, z, k, num, false, char_assumed_shape_cont_f, true, false);
}
struct loc_t
char_assumed_shape_cont_in_c (CFI_cdesc_t *x, CFI_cdesc_t *y, CFI_cdesc_t *z,
int k, int num)
{
return do_call (x, y, z, k, num, true, char_assumed_shape_cont_in_f, true, false);
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,82 @@
! { dg-additional-options "-fdump-tree-original" }
integer function f(xx) bind(c) result(ii)
implicit none
integer, contiguous :: xx(..)
ii = rank(xx)
end
integer function h(yy) bind(c) result(jj)
implicit none
character(len=*), contiguous :: yy(:)
jj = rank(yy)
end
integer function g(zz) bind(c) result(kk)
implicit none
character(len=*) :: zz(*)
kk = rank(zz)
end
integer function f2(aa) bind(c) result(ii)
implicit none
integer, contiguous :: aa(..)
intent(in) :: aa
ii = rank(aa)
end
integer function h2(bb) bind(c) result(jj)
implicit none
character(len=*), contiguous :: bb(:)
intent(in) :: bb
jj = rank(bb)
end
integer function g2(cc) bind(c) result(kk)
implicit none
character(len=*) :: cc(*)
intent(in) :: cc
kk = rank(cc)
end
!
! Copy-in/out variable:
!
! { dg-final { scan-tree-dump-times "xx->data =\[^;\]+ __builtin_malloc \\(_xx->elem_len \\* size.\[0-9\]+\\);" 1 "original" } }
! { dg-final { scan-tree-dump-times "yy->data =\[^;\]+ __builtin_malloc \\(_yy->elem_len \\* size.\[0-9\]+\\);" 1 "original" } }
! { dg-final { scan-tree-dump-times "zz =\[^;\]+ __builtin_malloc \\(_zz->elem_len \\* size.\[0-9\]+\\);" 1 "original" } }
! { dg-final { scan-tree-dump-times "aa->data =\[^;\]+ __builtin_malloc \\(_aa->elem_len \\* size.\[0-9\]+\\);" 1 "original" } }
! { dg-final { scan-tree-dump-times "bb->data =\[^;\]+ __builtin_malloc \\(_bb->elem_len \\* size.\[0-9\]+\\);" 1 "original" } }
! { dg-final { scan-tree-dump-times "cc =\[^;\]+ __builtin_malloc \\(_cc->elem_len \\* size.\[0-9\]+\\);" 1 "original" } }
! { dg-final { scan-tree-dump-times "__builtin_free \\(\[^;\]+ xx->data\\);" 1 "original" } }
! { dg-final { scan-tree-dump-times "__builtin_free \\(\[^;\]+ yy->data\\);" 1 "original" } }
! { dg-final { scan-tree-dump-times "__builtin_free \\(zz\\);" 1 "original" } }
! { dg-final { scan-tree-dump-times "__builtin_free \\(\[^;\]+ aa->data\\);" 1 "original" } }
! { dg-final { scan-tree-dump-times "__builtin_free \\(\[^;\]+ bb->data\\);" 1 "original" } }
! { dg-final { scan-tree-dump-times "__builtin_free \\(cc\\);" 1 "original" } }
! Copy in + out
! { dg-final { scan-tree-dump-times "__builtin_memcpy \\(\\(void \\*\\) xx->data \\+ xx->dtype.elem_len \\* arrayidx.\[0-9\]+, _xx->base_addr \\+ shift.\[0-9\]+, xx->dtype.elem_len\\);" 1 "original" } }
! { dg-final { scan-tree-dump-times "xx->data = \\(void \\* restrict\\) _xx->base_addr;" 1 "original" } }
! { dg-final { scan-tree-dump-times "__builtin_memcpy \\(\\(void \\*\\) xx->data \\+ xx->dtype.elem_len \\* arrayidx.\[0-9\]+, _xx->base_addr \\+ shift.\[0-9\]+, xx->dtype.elem_len\\);" 1 "original" } }
! { dg-final { scan-tree-dump-times "__builtin_memcpy \\(\\(void \\*\\) yy->data \\+ yy->dtype.elem_len \\* arrayidx.\[0-9\]+, _yy->base_addr \\+ shift.\[0-9\]+, yy->dtype.elem_len\\);" 1 "original" } }
! { dg-final { scan-tree-dump-times "yy->data = \\(void \\* restrict\\) _yy->base_addr;" 1 "original" } }
! { dg-final { scan-tree-dump-times "__builtin_memcpy \\(_yy->base_addr \\+ shift.\[0-9\]+, \\(void \\*\\) yy->data \\+ yy->dtype.elem_len \\* arrayidx.\[0-9\]+, yy->dtype.elem_len\\);" 1 "original" } }
! { dg-final { scan-tree-dump-times "zz = \\(character\\(kind=1\\)\\\[0:\\\]\\\[1:zz.\[0-9\]+\\\] \\* restrict\\) _zz->base_addr;" 1 "original" } }
! { dg-final { scan-tree-dump-times "__builtin_memcpy \\(\\(void \\*\\) zz \\+ _zz->elem_len \\* arrayidx.\[0-9\]+, _zz->base_addr \\+ shift.\[0-9\]+, _zz->elem_len\\);" 1 "original" } }
! { dg-final { scan-tree-dump-times "__builtin_memcpy \\(_zz->base_addr \\+ shift.\[0-9\]+, \\(void \\*\\) zz \\+ _zz->elem_len \\* arrayidx.\[0-9\]+, _zz->elem_len\\);" 1 "original" } }
! Copy in only
! { dg-final { scan-tree-dump-times "__builtin_memcpy \\(\\(void \\*\\) aa->data \\+ aa->dtype.elem_len \\* arrayidx.\[0-9\]+, _aa->base_addr \\+ shift.\[0-9\]+, aa->dtype.elem_len\\);" 1 "original" } }
! { dg-final { scan-tree-dump-times "aa->data = \\(void \\* restrict\\) _aa->base_addr;" 1 "original" } }
! { dg-final { scan-tree-dump-times "__builtin_memcpy \\(\\(void \\*\\) bb->data \\+ bb->dtype.elem_len \\* arrayidx.\[0-9\]+, _bb->base_addr \\+ shift.\[0-9\]+, bb->dtype.elem_len\\);" 1 "original" } }
! { dg-final { scan-tree-dump-times "bb->data = \\(void \\* restrict\\) _bb->base_addr;" 1 "original" } }
! { dg-final { scan-tree-dump-times "cc = \\(character\\(kind=1\\)\\\[0:\\\]\\\[1:cc.\[0-9\]+\\\] \\* restrict\\) _cc->base_addr;" 1 "original" } }
! { dg-final { scan-tree-dump-times "__builtin_memcpy \\(\\(void \\*\\) cc \\+ _cc->elem_len \\* arrayidx.\[0-9\]+, _cc->base_addr \\+ shift.\[0-9\]+, _cc->elem_len\\);" 1 "original" } }

View file

@ -0,0 +1,180 @@
#include <ISO_Fortran_binding.h>
intptr_t assumed_rank_alloc_f (CFI_cdesc_t *);
intptr_t assumed_rank_pointer_f (CFI_cdesc_t *);
intptr_t assumed_rank_f (CFI_cdesc_t *);
intptr_t assumed_rank_cont_f (CFI_cdesc_t *);
intptr_t assumed_shape_f (CFI_cdesc_t *);
intptr_t assumed_shape_cont_f (CFI_cdesc_t *);
intptr_t deferred_shape_alloc_f (CFI_cdesc_t *);
intptr_t deferred_shape_pointer_f (CFI_cdesc_t *);
static void
basic_check(CFI_cdesc_t *x)
{
if (!x->base_addr)
__builtin_abort ();
if (x->elem_len != sizeof(int32_t))
__builtin_abort ();
if (x->version != CFI_VERSION)
__builtin_abort ();
if (x->rank != 4)
__builtin_abort ();
if (x->type != CFI_type_int32_t)
__builtin_abort ();
if (x->attribute == CFI_attribute_other)
{
if (x->dim[0].lower_bound != 0)
__builtin_abort ();
if (x->dim[1].lower_bound != 0)
__builtin_abort ();
if (x->dim[2].lower_bound != 0)
__builtin_abort ();
if (x->dim[3].lower_bound != 0)
__builtin_abort ();
}
}
intptr_t
assumed_rank_alloc_c (CFI_cdesc_t *x)
{
basic_check (x);
if (!CFI_is_contiguous (x))
__builtin_abort ();
if (x->attribute != CFI_attribute_allocatable)
__builtin_abort ();
intptr_t addr = (intptr_t) x->base_addr;
intptr_t addr2 = assumed_rank_alloc_f (x);
if (addr != addr2 || addr != (intptr_t) x->base_addr)
__builtin_abort ();
return addr;
}
intptr_t
assumed_rank_pointer_c (CFI_cdesc_t *x)
{
basic_check (x);
if (x->attribute != CFI_attribute_pointer)
__builtin_abort ();
intptr_t addr = (intptr_t) x->base_addr;
intptr_t addr2 = assumed_rank_pointer_f (x);
if (addr != addr2 || addr != (intptr_t) x->base_addr)
__builtin_abort ();
return addr;
}
intptr_t
assumed_rank_c (CFI_cdesc_t *x)
{
basic_check (x);
if (x->attribute != CFI_attribute_other)
__builtin_abort ();
intptr_t addr = (intptr_t) x->base_addr;
intptr_t addr2 = assumed_rank_f (x);
if (addr != addr2 || addr != (intptr_t) x->base_addr)
__builtin_abort ();
return addr;
}
intptr_t
assumed_rank_cont_c (CFI_cdesc_t *x)
{
basic_check (x);
if (!CFI_is_contiguous (x))
__builtin_abort ();
if (x->attribute != CFI_attribute_other)
__builtin_abort ();
intptr_t addr = (intptr_t) x->base_addr;
intptr_t addr2 = assumed_rank_cont_f (x);
if (addr != addr2 || addr != (intptr_t) x->base_addr)
__builtin_abort ();
return addr;
}
intptr_t
assumed_shape_c (CFI_cdesc_t *x, int num)
{
basic_check (x);
if (x->attribute != CFI_attribute_other)
__builtin_abort ();
intptr_t addr = (intptr_t) x->base_addr;
intptr_t addr2;
if (num == 1 || num == 2 || num == 3)
{
if (!CFI_is_contiguous (x))
__builtin_abort ();
}
else
{
if (CFI_is_contiguous (x))
__builtin_abort ();
}
if (num == 1 || num == 4)
addr2 = assumed_shape_f (x);
else if (num == 2 || num == 5)
addr2 = assumed_shape_cont_f (x);
else if (num == 3 || num == 6)
addr2 = assumed_rank_cont_f (x);
else
__builtin_abort ();
if (num == 1 || num == 2 || num == 3)
{
if (addr != addr2)
__builtin_abort ();
}
else
{
if (CFI_is_contiguous (x))
__builtin_abort ();
}
if (addr != (intptr_t) x->base_addr)
__builtin_abort ();
return addr2;
}
intptr_t
assumed_shape_cont_c (CFI_cdesc_t *x)
{
basic_check (x);
if (!CFI_is_contiguous (x))
__builtin_abort ();
if (x->attribute != CFI_attribute_other)
__builtin_abort ();
intptr_t addr = (intptr_t) x->base_addr;
intptr_t addr2 = assumed_shape_cont_f (x);
if (addr != addr2 || addr != (intptr_t) x->base_addr)
__builtin_abort ();
return addr;
}
intptr_t
deferred_shape_alloc_c (CFI_cdesc_t *x)
{
basic_check (x);
if (!CFI_is_contiguous (x))
__builtin_abort ();
if (x->attribute != CFI_attribute_allocatable)
__builtin_abort ();
intptr_t addr = (intptr_t) x->base_addr;
intptr_t addr2 = deferred_shape_alloc_f (x);
if (addr != addr2 || addr != (intptr_t) x->base_addr)
__builtin_abort ();
return addr;
}
intptr_t
deferred_shape_pointer_c (CFI_cdesc_t *x)
{
basic_check (x);
if (x->attribute != CFI_attribute_pointer)
__builtin_abort ();
intptr_t addr = (intptr_t) x->base_addr;
intptr_t addr2 = deferred_shape_pointer_f (x);
if (addr != addr2 || addr != (intptr_t) x->base_addr)
__builtin_abort ();
return addr;
}

View file

@ -0,0 +1,656 @@
! { dg-do run }
! { dg-additional-sources bind-c-contiguous-3.c }
! Test that multi-dim contiguous is properly handled.
module m
use iso_c_binding, only: c_intptr_t, c_int
implicit none (type, external)
interface
integer(c_intptr_t) function assumed_rank_alloc_c (xx) bind(c)
import :: c_intptr_t
integer, allocatable :: xx(..)
end function
integer(c_intptr_t) function assumed_rank_pointer_c (xx) bind(c)
import :: c_intptr_t
integer, pointer :: xx(..)
end function
integer(c_intptr_t) function assumed_rank_c (xx) bind(c)
import :: c_intptr_t
integer :: xx(..)
end function
integer(c_intptr_t) function assumed_rank_cont_c (xx) bind(c)
import :: c_intptr_t
integer, contiguous :: xx(..)
end function
integer(c_intptr_t) function assumed_shape_c (xx, num) bind(c)
import :: c_intptr_t, c_int
integer :: xx(:,:,:,:)
integer(c_int), value :: num
end function
integer(c_intptr_t) function assumed_shape_cont_c (xx) bind(c)
import :: c_intptr_t
integer, contiguous :: xx(:,:,:,:)
end function
integer(c_intptr_t) function deferred_shape_alloc_c (xx) bind(c)
import :: c_intptr_t
integer, allocatable :: xx(:,:,:,:)
end function
integer(c_intptr_t) function deferred_shape_pointer_c (xx) bind(c)
import :: c_intptr_t
integer, pointer :: xx(:,:,:,:)
end function
end interface
contains
integer function get_n (idx, lbound, extent) result(res)
integer, contiguous :: idx(:), lbound(:), extent(:)
integer :: i
if (size(idx) /= size(lbound) .or. size(idx) /= size(extent)) &
error stop 20
res = idx(1) - lbound(1) + 1
do i = 2, size(idx)
res = res + product(extent(:i-1)) * (idx(i)-lbound(i))
end do
end
integer(c_intptr_t) function assumed_rank_alloc_f (xx) bind(c) result(res)
integer, allocatable :: xx(..)
integer :: i, j, k, l, lb(4)
select rank (xx)
rank (4)
do l = lbound(xx, dim=4), ubound(xx, dim=4)
do k = lbound(xx, dim=3), ubound(xx, dim=3)
do j = lbound(xx, dim=2), ubound(xx, dim=2)
do i = lbound(xx, dim=1), ubound(xx, dim=1)
xx(i,j,k,l) = -get_n([i,j,k,l], lbound(xx), shape(xx))
end do
end do
end do
end do
lb = lbound(xx)
res = %loc(xx(lb(1),lb(2),lb(3),lb(4))) ! { dg-warning "Legacy Extension" }
rank default
error stop 99
end select
end
integer(c_intptr_t) function assumed_rank_pointer_f (xx) bind(c) result(res)
integer, pointer :: xx(..)
integer :: i, j, k, l, lb(4)
select rank (xx)
rank (4)
do l = lbound(xx, dim=4), ubound(xx, dim=4)
do k = lbound(xx, dim=3), ubound(xx, dim=3)
do j = lbound(xx, dim=2), ubound(xx, dim=2)
do i = lbound(xx, dim=1), ubound(xx, dim=1)
xx(i,j,k,l) = -get_n([i,j,k,l], lbound(xx), shape(xx))
end do
end do
end do
end do
lb = lbound(xx)
res = %loc(xx(lb(1),lb(2),lb(3),lb(4))) ! { dg-warning "Legacy Extension" }
rank default
error stop 99
end select
end
integer(c_intptr_t) function assumed_rank_f (xx) bind(c) result(res)
integer :: xx(..)
integer :: i, j, k, l
select rank (xx)
rank (4)
do l = 1, size(xx, dim=4)
do k = 1, size(xx, dim=3)
do j = 1, size(xx, dim=2)
do i = 1, size(xx, dim=1)
xx(i,j,k,l) = -get_n([i,j,k,l], lbound(xx), shape(xx))
end do
end do
end do
end do
res = %loc(xx(1,1,1,1)) ! { dg-warning "Legacy Extension" }
rank default
error stop 99
end select
end
integer(c_intptr_t) function assumed_rank_cont_f (xx) bind(c) result(res)
integer, contiguous :: xx(..)
integer :: i, j, k, l
select rank (xx)
rank (4)
do l = 1, size(xx, dim=4)
do k = 1, size(xx, dim=3)
do j = 1, size(xx, dim=2)
do i = 1, size(xx, dim=1)
xx(i,j,k,l) = -get_n([i,j,k,l], lbound(xx), shape(xx))
end do
end do
end do
end do
res = %loc(xx(1,1,1,1)) ! { dg-warning "Legacy Extension" }
rank default
error stop 99
end select
end
integer(c_intptr_t) function assumed_shape_f (xx) bind(c) result(res)
integer :: xx(:,:,:,:)
integer :: i, j, k, l
do l = 1, ubound(xx, dim=4)
do k = 1, ubound(xx, dim=3)
do j = 1, ubound(xx, dim=2)
do i = 1, ubound(xx, dim=1)
xx(i,j,k,l) = -get_n([i,j,k,l], lbound(xx), shape(xx))
end do
end do
end do
end do
res = %loc(xx(1,1,1,1)) ! { dg-warning "Legacy Extension" }
end
integer(c_intptr_t) function assumed_shape2_f (xx, n) bind(c) result(res)
integer, value :: n
integer :: xx(-n:, -n:, -n:, -n:)
integer :: i, j, k, l
do l = -n, ubound(xx, dim=4)
do k = -n, ubound(xx, dim=3)
do j = -n, ubound(xx, dim=2)
do i = -n, ubound(xx, dim=1)
xx(i,j,k,l) = -get_n([i,j,k,l], lbound(xx), shape(xx))
end do
end do
end do
end do
res = %loc(xx(-n,-n,-n,-n)) ! { dg-warning "Legacy Extension" }
end
integer(c_intptr_t) function assumed_shape_cont_f (xx) bind(c) result(res)
integer, contiguous :: xx(:,:,:,:)
integer :: i, j, k, l
do l = 1, ubound(xx, dim=4)
do k = 1, ubound(xx, dim=3)
do j = 1, ubound(xx, dim=2)
do i = 1, ubound(xx, dim=1)
xx(i,j,k,l) = -get_n([i,j,k,l], lbound(xx), shape(xx))
end do
end do
end do
end do
res = %loc(xx(1,1,1,1)) ! { dg-warning "Legacy Extension" }
end
integer(c_intptr_t) function assumed_shape2_cont_f (xx, n) bind(c) result(res)
integer, value :: n
integer, contiguous :: xx(-n:, -n:, -n:, -n:)
integer :: i, j, k, l
do l = -n, ubound(xx, dim=4)
do k = -n, ubound(xx, dim=3)
do j = -n, ubound(xx, dim=2)
do i = -n, ubound(xx, dim=1)
xx(i,j,k,l) = -get_n([i,j,k,l], lbound(xx), shape(xx))
end do
end do
end do
end do
res = %loc(xx(-n,-n,-n,-n)) ! { dg-warning "Legacy Extension" }
end
integer(c_intptr_t) function deferred_shape_alloc_f (xx) bind(c) result(res)
integer, allocatable :: xx(:,:,:,:)
integer :: i, j, k, l, lb(4)
do l = lbound(xx, dim=4), ubound(xx, dim=4)
do k = lbound(xx, dim=3), ubound(xx, dim=3)
do j = lbound(xx, dim=2), ubound(xx, dim=2)
do i = lbound(xx, dim=1), ubound(xx, dim=1)
xx(i,j,k,l) = -get_n([i,j,k,l], lbound(xx), shape(xx))
end do
end do
end do
end do
lb = lbound(xx)
res = %loc(xx(lb(1),lb(2),lb(3),lb(4))) ! { dg-warning "Legacy Extension" }
end
integer(c_intptr_t) function deferred_shape_pointer_f (xx) bind(c) result(res)
integer, pointer :: xx(:,:,:,:)
integer :: i, j, k, l, lb(4)
do l = lbound(xx, dim=4), ubound(xx, dim=4)
do k = lbound(xx, dim=3), ubound(xx, dim=3)
do j = lbound(xx, dim=2), ubound(xx, dim=2)
do i = lbound(xx, dim=1), ubound(xx, dim=1)
xx(i,j,k,l) = -get_n([i,j,k,l], lbound(xx), shape(xx))
end do
end do
end do
end do
lb = lbound(xx)
res = %loc(xx(lb(1),lb(2),lb(3),lb(4))) ! { dg-warning "Legacy Extension" }
end
end module
use m
implicit none (type, external)
integer, dimension(10,10,10,10) :: var_init, var
target :: var
integer, allocatable, dimension(:,:,:,:) :: a1, a2
integer, pointer, dimension(:,:,:,:) :: p1, p2
integer(c_intptr_t) :: loc4
integer :: i, k, j, l, cnt
do l = 1, ubound(var_init, dim=4)
do k = 1, ubound(var_init, dim=3)
do j = 1, ubound(var_init, dim=2)
do i = 1, ubound(var_init, dim=1)
var_init(i,j,k,l) = get_n([i,j,k,l], lbound(var_init), shape(var_init))
end do
end do
end do
end do
! Fortran calls
! ----- allocatable + pointer dummies -------
allocate(a1, mold=var_init)
allocate(p1, mold=var_init)
allocate(a2(-5:4,-10:-1,1:10,11:20))
allocate(p2(-5:4,-10:-1,1:10,11:20))
a1(:,:,:,:) = var_init
loc4 = assumed_rank_alloc_f (a1)
cnt = size(a1) - check_unmod (a1)
call check (a1, loc4, .true., cnt)
call check2 (a1)
a2(:,:,:,:) = var_init
loc4 = assumed_rank_alloc_f (a2)
cnt = size(a2) - check_unmod (a2)
call check (a2, loc4, .true., cnt)
call check2 (a2)
a1(:,:,:,:) = var_init
loc4 = deferred_shape_alloc_f (a1)
cnt = size(a1) - check_unmod (a1)
call check (a1, loc4, .true., cnt)
call check2 (a1)
a2(:,:,:,:) = var_init
loc4 = deferred_shape_alloc_f (a2)
cnt = size(a2) - check_unmod (a2)
call check (a2, loc4, .true., cnt)
call check2 (a2)
deallocate(a1, a2)
p1(:,:,:,:) = var_init
loc4 = assumed_rank_pointer_f (p1)
cnt = size(p1) - check_unmod (p1)
call check (p1, loc4, .true., cnt)
call check2 (p1)
p2(:,:,:,:) = var_init
loc4 = assumed_rank_pointer_f (p2)
cnt = size(p2) - check_unmod (p2)
call check (p2, loc4, .true., cnt)
call check2 (p2)
p1(:,:,:,:) = var_init
loc4 = deferred_shape_pointer_f (p1)
cnt = size(p1) - check_unmod (p1)
call check (p1, loc4, .true., cnt)
call check2 (p1)
p2(:,:,:,:) = var_init
loc4 = deferred_shape_pointer_f (p2)
cnt = size(p2) - check_unmod (p2)
call check (p2, loc4, .true., cnt)
call check2 (p2)
deallocate(p1, p2)
! --- p => var(4:7,::3,::2,:)
var = var_init
p1 => var(4:7,::3,::2,:)
loc4 = assumed_rank_pointer_f (p1)
cnt = size(p1) - check_unmod (p1)
call check (p1, loc4, .false., cnt)
call check2 (p1)
var = var_init
p2(-5:,-10:,1:,11:) => var(4:7,::3,::2,:)
loc4 = assumed_rank_pointer_f (p2)
cnt = size(p2) - check_unmod (p2)
call check (p2, loc4, .false., cnt)
call check2 (p2)
var = var_init
p1 => var(4:7,::3,::2,:)
loc4 = deferred_shape_pointer_f (p1)
cnt = size(p1) - check_unmod (p1)
call check (p1, loc4, .false., cnt)
call check2 (p1)
var = var_init
p2(-5:,-10:,1:,11:) => var(4:7,::3,::2,:)
loc4 = deferred_shape_pointer_f (p2)
cnt = size(p2) - check_unmod (p2)
call check (p2, loc4, .false., cnt)
call check2 (p2)
! ----- nonallocatable + nonpointer dummies -------
var = var_init
loc4 = assumed_rank_f (var)
cnt = size(var) - check_unmod (var)
call check (var, loc4, .false., cnt)
call check2 (var)
var = var_init
loc4 = assumed_shape_f (var)
cnt = size(var) - check_unmod (var)
call check (var, loc4, .false., cnt)
call check2 (var)
var = var_init
loc4 = assumed_shape2_f (var, 99)
cnt = size(var) - check_unmod (var)
call check (var, loc4, .false., cnt)
call check2 (var)
var = var_init
loc4 = assumed_rank_cont_f (var)
cnt = size(var) - check_unmod (var)
call check (var, loc4, .true., cnt)
call check2 (var)
var = var_init
loc4 = assumed_shape_cont_f (var)
cnt = size(var) - check_unmod (var)
call check (var, loc4, .true., cnt)
call check2 (var)
var = var_init
loc4 = assumed_shape2_cont_f (var, 99)
cnt = size(var) - check_unmod (var)
call check (var, loc4, .true., cnt)
call check2 (var)
! --- var(4:7,::3,::2,:)
var = var_init
loc4 = assumed_rank_f (var(4:7,::3,::2,:))
cnt = size(var) - check_unmod (var)
call check (var(4:7,::3,::2,:), loc4, .false., cnt)
call check2 (var(4:7,::3,::2,:))
var = var_init
loc4 = assumed_shape_f (var(4:7,::3,::2,:))
cnt = size(var) - check_unmod (var)
call check (var(4:7,::3,::2,:), loc4, .false., cnt)
call check2 (var(4:7,::3,::2,:))
var = var_init
loc4 = assumed_shape2_f (var(4:7,::3,::2,:), 99)
cnt = size(var) - check_unmod (var)
call check (var(4:7,::3,::2,:), loc4, .false., cnt)
call check2 (var(4:7,::3,::2,:))
var = var_init
loc4 = assumed_rank_cont_f (var(4:7,::3,::2,:))
cnt = size(var) - check_unmod (var)
call check (var(4:7,::3,::2,:), loc4, .true., cnt)
call check2 (var(4:7,::3,::2,:))
var = var_init
loc4 = assumed_shape_cont_f (var(4:7,::3,::2,:))
cnt = size(var) - check_unmod (var)
call check (var(4:7,::3,::2,:), loc4, .true., cnt)
call check2 (var(4:7,::3,::2,:))
var = var_init
loc4 = assumed_shape2_cont_f (var(4:7,::3,::2,:), 99)
cnt = size(var) - check_unmod (var)
call check (var(4:7,::3,::2,:), loc4, .true., cnt)
call check2 (var(4:7,::3,::2,:))
! C calls
! ----- allocatable + pointer dummies -------
allocate(a1, mold=var_init)
allocate(p1, mold=var_init)
allocate(a2(-5:4,-10:-1,1:10,11:20))
allocate(p2(-5:4,-10:-1,1:10,11:20))
a1(:,:,:,:) = var_init
loc4 = assumed_rank_alloc_c (a1)
cnt = size(a1) - check_unmod (a1)
call check (a1, loc4, .true., cnt)
call check2 (a1)
a2(:,:,:,:) = var_init
loc4 = assumed_rank_alloc_c (a2)
cnt = size(a2) - check_unmod (a2)
call check (a2, loc4, .true., cnt)
call check2 (a2)
a1(:,:,:,:) = var_init
loc4 = deferred_shape_alloc_c (a1)
cnt = size(a1) - check_unmod (a1)
call check (a1, loc4, .true., cnt)
call check2 (a1)
a2(:,:,:,:) = var_init
loc4 = deferred_shape_alloc_c (a2)
cnt = size(a2) - check_unmod (a2)
call check (a2, loc4, .true., cnt)
call check2 (a2)
deallocate(a1, a2)
p1(:,:,:,:) = var_init
loc4 = assumed_rank_pointer_c (p1)
cnt = size(p1) - check_unmod (p1)
call check (p1, loc4, .true., cnt)
call check2 (p1)
p2(:,:,:,:) = var_init
loc4 = assumed_rank_pointer_c (p2)
cnt = size(p2) - check_unmod (p2)
call check (p2, loc4, .true., cnt)
call check2 (p2)
p1(:,:,:,:) = var_init
loc4 = deferred_shape_pointer_c (p1)
cnt = size(p1) - check_unmod (p1)
call check (p1, loc4, .true., cnt)
call check2 (p1)
p2(:,:,:,:) = var_init
loc4 = deferred_shape_pointer_c (p2)
cnt = size(p2) - check_unmod (p2)
call check (p2, loc4, .true., cnt)
call check2 (p2)
deallocate(p1, p2)
! --- p => var(4:7,::3,::2,:)
var = var_init
p1 => var(4:7,::3,::2,:)
loc4 = assumed_rank_pointer_c (p1)
cnt = size(p1) - check_unmod (p1)
call check (p1, loc4, .false., cnt)
call check2 (p1)
var = var_init
p2(-5:,-10:,1:,11:) => var(4:7,::3,::2,:)
loc4 = assumed_rank_pointer_c (p2)
cnt = size(p2) - check_unmod (p2)
call check (p2, loc4, .false., cnt)
call check2 (p2)
var = var_init
p1 => var(4:7,::3,::2,:)
loc4 = deferred_shape_pointer_c (p1)
cnt = size(p1) - check_unmod (p1)
call check (p1, loc4, .false., cnt)
call check2 (p1)
var = var_init
p2(-5:,-10:,1:,11:) => var(4:7,::3,::2,:)
loc4 = deferred_shape_pointer_c (p2)
cnt = size(p2) - check_unmod (p2)
call check (p2, loc4, .false., cnt)
call check2 (p2)
! ----- nonallocatable + nonpointer dummies -------
var = var_init
loc4 = assumed_rank_c (var)
cnt = size(var) - check_unmod (var)
call check (var, loc4, .false., cnt)
call check2 (var)
var = var_init
! calls assumed_shape_f
loc4 = assumed_shape_c (var, num=1)
cnt = size(var) - check_unmod (var)
call check (var, loc4, .false., cnt)
call check2 (var)
var = var_init
! calls assumed_shape_cont_f
loc4 = assumed_shape_c (var, num=2)
cnt = size(var) - check_unmod (var)
call check (var, loc4, .true., cnt)
call check2 (var)
var = var_init
! calls assumed_rank_cont_f
loc4 = assumed_shape_c (var, num=3)
cnt = size(var) - check_unmod (var)
call check (var, loc4, .true., cnt)
call check2 (var)
var = var_init
loc4 = assumed_rank_cont_c (var)
cnt = size(var) - check_unmod (var)
call check (var, loc4, .true., cnt)
call check2 (var)
var = var_init
loc4 = assumed_shape_cont_c (var)
cnt = size(var) - check_unmod (var)
call check (var, loc4, .true., cnt)
call check2 (var)
! --- var(4:7,::3,::2,:)
var = var_init
loc4 = assumed_rank_c (var(4:7,::3,::2,:))
cnt = size(var) - check_unmod (var)
call check (var(4:7,::3,::2,:), loc4, .false., cnt)
call check2 (var(4:7,::3,::2,:))
var = var_init
! calls assumed_shape_f
loc4 = assumed_shape_c (var(4:7,::3,::2,:), num=4)
cnt = size(var) - check_unmod (var)
call check (var(4:7,::3,::2,:), loc4, .false., cnt)
call check2 (var(4:7,::3,::2,:))
var = var_init
! calls assumed_shape_cont_f
loc4 = assumed_shape_c (var(4:7,::3,::2,:), num=5)
cnt = size(var) - check_unmod (var)
call check (var(4:7,::3,::2,:), loc4, .true., cnt)
call check2 (var(4:7,::3,::2,:))
var = var_init
! calls assumed_rank_cont_f
loc4 = assumed_shape_c (var(4:7,::3,::2,:), num=6)
cnt = size(var) - check_unmod (var)
call check (var(4:7,::3,::2,:), loc4, .true., cnt)
call check2 (var(4:7,::3,::2,:))
var = var_init
loc4 = assumed_rank_cont_c (var(4:7,::3,::2,:))
cnt = size(var) - check_unmod (var)
call check (var(4:7,::3,::2,:), loc4, .true., cnt)
call check2 (var(4:7,::3,::2,:))
var = var_init
loc4 = assumed_shape_cont_c (var(4:7,::3,::2,:))
cnt = size(var) - check_unmod (var)
call check (var(4:7,::3,::2,:), loc4, .true., cnt)
call check2 (var(4:7,::3,::2,:))
contains
! Ensure that the rest is still okay
! Returns the number of elements >= 0
integer function check_unmod (x) result(cnt)
integer, contiguous, intent(in) :: x(:,:,:,:)
integer :: i, k, j, l
cnt = 0
do l = 1, ubound(x, dim=4)
do k = 1, ubound(x, dim=3)
do j = 1, ubound(x, dim=2)
do i = 1, ubound(x, dim=1)
if (x(i,j,k,l) >= 0) then
cnt = cnt + 1
if (x(i,j,k,l) /= get_n([i,j,k,l], lbound(x), shape(x))) &
error stop 5
endif
end do
end do
end do
end do
end
subroutine check(x, loc1, cont, cnt)
integer, intent(in) :: x(:,:,:,:)
integer(c_intptr_t), intent(in), optional :: loc1
logical, intent(in), optional :: cont ! dummy has CONTIGUOUS attr
integer, intent(in), optional :: cnt
integer(c_intptr_t) :: loc2
integer :: i, k, j, l
if (present (loc1)) then
loc2 = %loc(x(1,1,1,1)) ! { dg-warning "Legacy Extension" }
if (is_contiguous (x) .or. .not.cont) then
if (loc1 /= loc2) error stop 1
else
if (loc1 == loc2) error stop 2
end if
if (cnt /= size(x)) error stop 3
end if
do l = 1, ubound(x, dim=4)
do k = 1, ubound(x, dim=3)
do j = 1, ubound(x, dim=2)
do i = 1, ubound(x, dim=1)
if (x(i,j,k,l) /= -get_n([i,j,k,l], lbound(x), shape(x))) &
error stop 4
end do
end do
end do
end do
end
subroutine check2(x)
integer, contiguous, intent(in) :: x(:,:,:,:)
call check(x)
end subroutine
end

View file

@ -0,0 +1,370 @@
#include <ISO_Fortran_binding.h>
#include <stdbool.h>
#include <string.h>
struct loc_t {
intptr_t x, y, z;
};
typedef struct loc_t (*ftn_fn) (CFI_cdesc_t *, CFI_cdesc_t *, CFI_cdesc_t *, int, int);
struct loc_t char_assumed_size_f (CFI_cdesc_t *, CFI_cdesc_t *, CFI_cdesc_t *, int, int);
struct loc_t char_assumed_size_in_f (CFI_cdesc_t *, CFI_cdesc_t *, CFI_cdesc_t *, int, int);
struct loc_t char_expl_size_f (CFI_cdesc_t *,CFI_cdesc_t *, CFI_cdesc_t *, int, int);
struct loc_t char_expl_size_in_f (CFI_cdesc_t *,CFI_cdesc_t *, CFI_cdesc_t *, int, int);
struct loc_t char_assumed_rank_f (CFI_cdesc_t *, CFI_cdesc_t *, CFI_cdesc_t *, int, int);
struct loc_t char_assumed_rank_in_f (CFI_cdesc_t *, CFI_cdesc_t *, CFI_cdesc_t *, int, int);
struct loc_t char_assumed_rank_cont_f (CFI_cdesc_t *, CFI_cdesc_t *, CFI_cdesc_t *, int, int);
struct loc_t char_assumed_rank_cont_in_f (CFI_cdesc_t *, CFI_cdesc_t *, CFI_cdesc_t *, int, int);
struct loc_t char_assumed_shape_f (CFI_cdesc_t *, CFI_cdesc_t *, CFI_cdesc_t *, int, int);
struct loc_t char_assumed_shape_in_f (CFI_cdesc_t *, CFI_cdesc_t *, CFI_cdesc_t *, int, int);
struct loc_t char_assumed_shape_cont_f (CFI_cdesc_t *, CFI_cdesc_t *, CFI_cdesc_t *, int, int);
struct loc_t char_assumed_shape_cont_in_f (CFI_cdesc_t *, CFI_cdesc_t *, CFI_cdesc_t *, int, int);
static void
basic_check(CFI_cdesc_t *x, bool is_cont)
{
if (!x->base_addr)
__builtin_abort ();
if (x->elem_len != 3*sizeof(char))
__builtin_abort ();
if (x->version != CFI_VERSION)
__builtin_abort ();
if (x->rank != 1)
__builtin_abort ();
if (x->attribute != CFI_attribute_other)
__builtin_abort ();
if (x->type != CFI_type_char)
__builtin_abort ();
if (x->dim[0].lower_bound != 0)
__builtin_abort ();
if (x->dim[0].extent != 3)
__builtin_abort ();
if (CFI_is_contiguous (x) != (x->elem_len == x->dim[0].sm))
__builtin_abort ();
if (is_cont != CFI_is_contiguous (x))
__builtin_abort ();
}
static void
print_str (void *p, size_t len)
{
__builtin_printf ("DEBUG: >");
for (size_t i = 0; i < len; ++i)
__builtin_printf ("%c", ((const char*) p)[i]);
__builtin_printf ("<\n");
}
static void
check_str (CFI_cdesc_t *x, const char *str, const CFI_index_t subscripts[])
{
/* Avoid checking for '\0'. */
if (strncmp ((const char*) CFI_address (x, subscripts), str, strlen(str)) != 0)
__builtin_abort ();
}
static void
set_str (CFI_cdesc_t *x, const char *str, const CFI_index_t subscripts[])
{
char *p = CFI_address (x, subscripts);
size_t len = strlen (str);
if (x->elem_len != len)
__builtin_abort ();
for (size_t i = 0; i < len; ++i)
p[i] = str[i];
}
static struct loc_t
do_call (CFI_cdesc_t *x, CFI_cdesc_t *y, CFI_cdesc_t *z,
int k, int num, bool intent_in, ftn_fn fn, bool is_cont, bool fort_cont)
{
const CFI_index_t zero[1] = { 0 };
const CFI_index_t one[1] = { 1 };
const CFI_index_t two[1] = { 2 };
struct loc_t addr1, addr2;
if (k != 3)
__builtin_abort ();
if (num == 3)
{
if (x != NULL)
__builtin_abort ();
if (y != NULL)
__builtin_abort ();
if (z != NULL)
__builtin_abort ();
addr2 = fn (x, y, z, 3, num);
if (addr2.x != -1 || addr2.y != -1 || addr2.z != -1)
__builtin_abort ();
return addr2;
}
if (x == NULL)
__builtin_abort ();
if (y == NULL)
__builtin_abort ();
if (z == NULL)
__builtin_abort ();
basic_check (x, is_cont || num == 2);
basic_check (y, is_cont || num == 2);
basic_check (z, is_cont || num == 2);
if (!is_cont && num == 1)
{
check_str (x, "abc", zero);
check_str (x, "ghi", one);
check_str (x, "nop", two);
check_str (y, "abc", zero);
check_str (y, "ghi", one);
check_str (y, "nop", two);
check_str (z, "abc", zero);
check_str (z, "ghi", one);
check_str (z, "nop", two);
}
else if (num == 1)
{
if (strncmp ((const char*) x->base_addr, "abcghinop", 9) != 0)
__builtin_abort ();
if (strncmp ((const char*) y->base_addr, "abcghinop", 9) != 0)
__builtin_abort ();
if (strncmp ((const char*) z->base_addr, "abcghinop", 9) != 0)
__builtin_abort ();
}
else if (num == 2)
{
if (strncmp ((const char*) x->base_addr, "defghijlm", 9) != 0)
__builtin_abort ();
if (strncmp ((const char*) y->base_addr, "defghijlm", 9) != 0)
__builtin_abort ();
if (strncmp ((const char*) z->base_addr, "defghijlm", 9) != 0)
__builtin_abort ();
}
else
__builtin_abort ();
addr1.x = (intptr_t) x->base_addr;
addr1.y = (intptr_t) y->base_addr;
addr1.z = (intptr_t) z->base_addr;
addr2 = fn (x, y, z, 3, num);
if (!CFI_is_contiguous (x) && fort_cont)
{
/* Check for callee copy in/copy out. */
if (addr1.x == addr2.x || addr1.x != (intptr_t) x->base_addr)
__builtin_abort ();
if (addr1.y == addr2.y || addr1.y != (intptr_t) y->base_addr)
__builtin_abort ();
if (addr1.z == addr2.z || addr1.z != (intptr_t) z->base_addr)
__builtin_abort ();
}
else
{
if (addr1.x != addr2.x || addr1.x != (intptr_t) x->base_addr)
__builtin_abort ();
if (addr1.y != addr2.y || addr1.y != (intptr_t) y->base_addr)
__builtin_abort ();
if (addr1.z != addr2.z || addr1.z != (intptr_t) z->base_addr)
__builtin_abort ();
}
// intent_in
if (intent_in && !is_cont && num == 1)
{
check_str (x, "abc", zero);
check_str (x, "ghi", one);
check_str (x, "nop", two);
check_str (y, "abc", zero);
check_str (y, "ghi", one);
check_str (y, "nop", two);
check_str (z, "abc", zero);
check_str (z, "ghi", one);
check_str (z, "nop", two);
}
else if (intent_in && num == 1)
{
if (strncmp ((const char*) x->base_addr, "abcghinop", 9) != 0)
__builtin_abort ();
if (strncmp ((const char*) y->base_addr, "abcghinop", 9) != 0)
__builtin_abort ();
if (strncmp ((const char*) z->base_addr, "abcghinop", 9) != 0)
__builtin_abort ();
}
else if (intent_in && num == 2)
{
if (strncmp ((const char*) x->base_addr, "defghijlm", 9) != 0)
__builtin_abort ();
if (strncmp ((const char*) y->base_addr, "defghijlm", 9) != 0)
__builtin_abort ();
if (strncmp ((const char*) z->base_addr, "defghijlm", 9) != 0)
__builtin_abort ();
}
else if (intent_in)
__builtin_abort ();
if (intent_in)
{
if (is_cont && num == 1)
{
/* Copy in - set the value to check that no copy out is done. */
memcpy ((char*) x->base_addr, "123456789", 9);
memcpy ((char*) y->base_addr, "123456789", 9);
memcpy ((char*) z->base_addr, "123456789", 9);
}
return addr1;
}
// !intent_in
if (!is_cont && num == 1)
{
check_str (x, "ABC", zero);
check_str (x, "DEF", one);
check_str (x, "GHI", two);
check_str (y, "ABC", zero);
check_str (y, "DEF", one);
check_str (y, "GHI", two);
check_str (z, "ABC", zero);
check_str (z, "DEF", one);
check_str (z, "GHI", two);
}
else
{
if (strncmp ((const char*) x->base_addr, "ABCDEFGHI", 9) != 0)
__builtin_abort ();
if (strncmp ((const char*) y->base_addr, "ABCDEFGHI", 9) != 0)
__builtin_abort ();
if (strncmp ((const char*) z->base_addr, "ABCDEFGHI", 9) != 0)
__builtin_abort ();
}
return addr1;
}
struct loc_t
char_assumed_size_c (CFI_cdesc_t *x, CFI_cdesc_t *y, CFI_cdesc_t *z,
int k, int num)
{
return do_call (x, y, z, k, num, false, char_assumed_size_f, true, false);
}
struct loc_t
char_assumed_size_in_c (CFI_cdesc_t *x, CFI_cdesc_t *y, CFI_cdesc_t *z,
int k, int num)
{
return do_call (x, y, z, k, num, true, char_assumed_size_in_f, true, false);
}
struct loc_t
char_expl_size_c (CFI_cdesc_t *x, CFI_cdesc_t *y, CFI_cdesc_t *z,
int k, int num)
{
return do_call (x, y, z, k, num, false, char_expl_size_f, true, false);
}
struct loc_t
char_expl_size_in_c (CFI_cdesc_t *x, CFI_cdesc_t *y, CFI_cdesc_t *z,
int k, int num)
{
return do_call (x, y, z, k, num, true, char_expl_size_in_f, true, false);
}
struct loc_t
char_assumed_rank_c (CFI_cdesc_t *x, CFI_cdesc_t *y, CFI_cdesc_t *z,
int k, int num)
{
return do_call (x, y, z, k, num, false, char_assumed_rank_f, false, false);
}
struct loc_t
char_assumed_rank_in_c (CFI_cdesc_t *x, CFI_cdesc_t *y, CFI_cdesc_t *z,
int k, int num)
{
return do_call (x, y, z, k, num, true, char_assumed_rank_in_f, false, false);
}
struct loc_t
char_assumed_rank_cont_c (CFI_cdesc_t *x, CFI_cdesc_t *y, CFI_cdesc_t *z,
int k, int num)
{
return do_call (x, y, z, k, num, false, char_assumed_rank_cont_f, true, false);
}
struct loc_t
char_assumed_rank_cont_in_c (CFI_cdesc_t *x, CFI_cdesc_t *y, CFI_cdesc_t *z,
int k, int num)
{
return do_call (x, y, z, k, num, true, char_assumed_rank_cont_in_f, true, false);
}
static void
reset_var (CFI_cdesc_t *x, int num)
{
const CFI_index_t zero[1] = { 0 };
const CFI_index_t one[1] = { 1 };
const CFI_index_t two[1] = { 2 };
if (num == 1)
{
set_str (x, "abc", zero);
set_str (x, "ghi", one);
set_str (x, "nop", two);
}
else if (num == 2)
{
set_str (x, "def", zero);
set_str (x, "ghi", one);
set_str (x, "jlm", two);
}
else if (num == 3)
{
if (x != NULL)
__builtin_abort ();
}
else
__builtin_abort ();
}
static void
reset_vars (CFI_cdesc_t *x, CFI_cdesc_t *y, CFI_cdesc_t *z, int num)
{
reset_var (x, num);
reset_var (y, num);
reset_var (z, num);
}
struct loc_t
char_assumed_shape_c (CFI_cdesc_t *x, CFI_cdesc_t *y, CFI_cdesc_t *z,
int k, int num)
{
/* Make use of having a noncontiguous argument to check that the callee
handles noncontiguous variables. */
do_call (x, y, z, k, num, false, char_assumed_size_f, false, true);
reset_vars (x, y, z, num);
do_call (x, y, z, k, num, true, char_assumed_size_in_f, false, true);
reset_vars (x, y, z, num);
do_call (x, y, z, k, num, false, char_expl_size_f, false, true);
reset_vars (x, y, z, num);
do_call (x, y, z, k, num, true, char_expl_size_in_f, false, true);
reset_vars (x, y, z, num);
do_call (x, y, z, k, num, false, char_assumed_rank_cont_f, false, true);
reset_vars (x, y, z, num);
do_call (x, y, z, k, num, true, char_assumed_rank_cont_in_f, false, true);
reset_vars (x, y, z, num);
do_call (x, y, z, k, num, false, char_assumed_shape_cont_f, false, true);
reset_vars (x, y, z, num);
do_call (x, y, z, k, num, true, char_assumed_shape_cont_in_f, false, true);
/* Actual func call. */
reset_vars (x, y, z, num);
return do_call (x, y, z, k, num, false, char_assumed_shape_f, false, false);
}
struct loc_t
char_assumed_shape_in_c (CFI_cdesc_t *x, CFI_cdesc_t *y, CFI_cdesc_t *z,
int k, int num)
{
return do_call (x, y, z, k, num, true, char_assumed_shape_in_f, false, false);
}
struct loc_t
char_assumed_shape_cont_c (CFI_cdesc_t *x, CFI_cdesc_t *y, CFI_cdesc_t *z,
int k, int num)
{
return do_call (x, y, z, k, num, false, char_assumed_shape_cont_f, true, false);
}
struct loc_t
char_assumed_shape_cont_in_c (CFI_cdesc_t *x, CFI_cdesc_t *y, CFI_cdesc_t *z,
int k, int num)
{
return do_call (x, y, z, k, num, true, char_assumed_shape_cont_in_f, true, false);
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,345 @@
#include <ISO_Fortran_binding.h>
#include <stdbool.h>
#include <string.h>
struct loc_t {
intptr_t x, y, z;
};
typedef struct loc_t (*ftn_fn) (CFI_cdesc_t *, CFI_cdesc_t *, CFI_cdesc_t *, int, int);
struct loc_t char_assumed_size_f (CFI_cdesc_t *, CFI_cdesc_t *, CFI_cdesc_t *, int, int);
struct loc_t char_assumed_size_in_f (CFI_cdesc_t *, CFI_cdesc_t *, CFI_cdesc_t *, int, int);
struct loc_t char_expl_size_f (CFI_cdesc_t *,CFI_cdesc_t *, CFI_cdesc_t *, int, int);
struct loc_t char_expl_size_in_f (CFI_cdesc_t *,CFI_cdesc_t *, CFI_cdesc_t *, int, int);
struct loc_t char_assumed_rank_f (CFI_cdesc_t *, CFI_cdesc_t *, CFI_cdesc_t *, int, int);
struct loc_t char_assumed_rank_in_f (CFI_cdesc_t *, CFI_cdesc_t *, CFI_cdesc_t *, int, int);
struct loc_t char_assumed_rank_cont_f (CFI_cdesc_t *, CFI_cdesc_t *, CFI_cdesc_t *, int, int);
struct loc_t char_assumed_rank_cont_in_f (CFI_cdesc_t *, CFI_cdesc_t *, CFI_cdesc_t *, int, int);
struct loc_t char_assumed_shape_f (CFI_cdesc_t *, CFI_cdesc_t *, CFI_cdesc_t *, int, int);
struct loc_t char_assumed_shape_in_f (CFI_cdesc_t *, CFI_cdesc_t *, CFI_cdesc_t *, int, int);
struct loc_t char_assumed_shape_cont_f (CFI_cdesc_t *, CFI_cdesc_t *, CFI_cdesc_t *, int, int);
struct loc_t char_assumed_shape_cont_in_f (CFI_cdesc_t *, CFI_cdesc_t *, CFI_cdesc_t *, int, int);
static void
basic_check(CFI_cdesc_t *x, bool is_cont)
{
if (!x->base_addr)
__builtin_abort ();
if (x->elem_len != 3*(4*sizeof(char))) /* ucs4_char */
__builtin_abort ();
if (x->version != CFI_VERSION)
__builtin_abort ();
if (x->rank != 1)
__builtin_abort ();
if (x->attribute != CFI_attribute_other)
__builtin_abort ();
if (x->type != CFI_type_ucs4_char)
__builtin_abort ();
if (x->dim[0].lower_bound != 0)
__builtin_abort ();
if (x->dim[0].extent != 3)
__builtin_abort ();
if (CFI_is_contiguous (x) != (x->elem_len == x->dim[0].sm))
__builtin_abort ();
if (is_cont != CFI_is_contiguous (x))
__builtin_abort ();
}
static void
print_str (void *p, size_t len)
{
__builtin_printf ("DEBUG: >");
/* Use ' ' for '\0' */
for (size_t i = 0; i < len*4; ++i)
__builtin_printf ("%c", ((const char*) p)[i] ? ((const char*) p)[i] : ' ');
__builtin_printf ("<\n");
}
static void
check_str (CFI_cdesc_t *x, const char *str, size_t n, const CFI_index_t subscripts[])
{
/* Avoid checking for '\0'. */
if (memcmp ((const char*) CFI_address (x, subscripts), str, n) != 0)
__builtin_abort ();
}
static void
set_str (CFI_cdesc_t *x, const char *str, size_t n, const CFI_index_t subscripts[])
{
char *p = CFI_address (x, subscripts);
if (x->elem_len != n)
__builtin_abort ();
for (size_t i = 0; i < n; ++i)
p[i] = str[i];
}
static struct loc_t
do_call (CFI_cdesc_t *x, CFI_cdesc_t *y, CFI_cdesc_t *z,
int k, int num, bool intent_in, ftn_fn fn, bool is_cont, bool fort_cont)
{
const CFI_index_t zero[1] = { 0 };
const CFI_index_t one[1] = { 1 };
const CFI_index_t two[1] = { 2 };
struct loc_t addr1, addr2;
if (k != 3)
__builtin_abort ();
basic_check (x, is_cont || num == 2);
basic_check (y, is_cont || num == 2);
basic_check (z, is_cont || num == 2);
if (!is_cont && num == 1)
{
check_str (x, "a\0\0\0b\0\0\0c\0\0\0", 3*4, zero);
check_str (x, "g\0\0\0h\0\0\0i\0\0\0", 3*4, one);
check_str (x, "n\0\0\0o\0\0\0p\0\0\0", 3*4, two);
check_str (y, "a\0\0\0b\0\0\0c\0\0\0", 3*4, zero);
check_str (y, "g\0\0\0h\0\0\0i\0\0\0", 3*4, one);
check_str (y, "n\0\0\0o\0\0\0p\0\0\0", 3*4, two);
check_str (z, "a\0\0\0b\0\0\0c\0\0\0", 3*4, zero);
check_str (z, "g\0\0\0h\0\0\0i\0\0\0", 3*4, one);
check_str (z, "n\0\0\0o\0\0\0p\0\0\0", 3*4, two);
}
else if (num == 1)
{
if (memcmp ((const char*) x->base_addr, "a\0\0\0b\0\0\0c\0\0\0g\0\0\0h\0\0\0i\0\0\0n\0\0\0o\0\0\0p\0\0\0", 9*4) != 0)
__builtin_abort ();
if (memcmp ((const char*) y->base_addr, "a\0\0\0b\0\0\0c\0\0\0g\0\0\0h\0\0\0i\0\0\0n\0\0\0o\0\0\0p\0\0\0", 9*4) != 0)
__builtin_abort ();
if (memcmp ((const char*) z->base_addr, "a\0\0\0b\0\0\0c\0\0\0g\0\0\0h\0\0\0i\0\0\0n\0\0\0o\0\0\0p\0\0\0", 9*4) != 0)
__builtin_abort ();
}
else if (num == 2)
{
if (memcmp ((const char*) x->base_addr, "d\0\0\0e\0\0\0f\0\0\0g\0\0\0h\0\0\0i\0\0\0j\0\0\0l\0\0\0m\0\0\0", 9*4) != 0)
__builtin_abort ();
if (memcmp ((const char*) y->base_addr, "d\0\0\0e\0\0\0f\0\0\0g\0\0\0h\0\0\0i\0\0\0j\0\0\0l\0\0\0m\0\0\0", 9*4) != 0)
__builtin_abort ();
if (memcmp ((const char*) z->base_addr, "d\0\0\0e\0\0\0f\0\0\0g\0\0\0h\0\0\0i\0\0\0j\0\0\0l\0\0\0m\0\0\0", 9*4) != 0)
__builtin_abort ();
}
else
__builtin_abort ();
addr1.x = (intptr_t) x->base_addr;
addr1.y = (intptr_t) y->base_addr;
addr1.z = (intptr_t) z->base_addr;
addr2 = fn (x, y, z, 3, num);
if (!CFI_is_contiguous (x) && fort_cont)
{
/* Check for callee copy in/copy out. */
if (addr1.x == addr2.x || addr1.x != (intptr_t) x->base_addr)
__builtin_abort ();
if (addr1.y == addr2.y || addr1.y != (intptr_t) y->base_addr)
__builtin_abort ();
if (addr1.z == addr2.z || addr1.z != (intptr_t) z->base_addr)
__builtin_abort ();
}
else
{
if (addr1.x != addr2.x || addr1.x != (intptr_t) x->base_addr)
__builtin_abort ();
if (addr1.y != addr2.y || addr1.y != (intptr_t) y->base_addr)
__builtin_abort ();
if (addr1.z != addr2.z || addr1.z != (intptr_t) z->base_addr)
__builtin_abort ();
}
// intent_in
if (intent_in && !is_cont && num == 1)
{
check_str (x, "a\0\0\0b\0\0\0c\0\0\0", 3*4, zero);
check_str (x, "g\0\0\0h\0\0\0i\0\0\0", 3*4, one);
check_str (x, "n\0\0\0o\0\0\0p\0\0\0", 3*4, two);
check_str (y, "a\0\0\0b\0\0\0c\0\0\0", 3*4, zero);
check_str (y, "g\0\0\0h\0\0\0i\0\0\0", 3*4, one);
check_str (y, "n\0\0\0o\0\0\0p\0\0\0", 3*4, two);
check_str (z, "a\0\0\0b\0\0\0c\0\0\0", 3*4, zero);
check_str (z, "g\0\0\0h\0\0\0i\0\0\0", 3*4, one);
check_str (z, "n\0\0\0o\0\0\0p\0\0\0", 3*4, two);
}
else if (intent_in && num == 1)
{
if (memcmp ((const char*) x->base_addr, "a\0\0\0b\0\0\0c\0\0\0g\0\0\0h\0\0\0i\0\0\0n\0\0\0o\0\0\0p\0\0\0", 9*4) != 0)
__builtin_abort ();
if (memcmp ((const char*) y->base_addr, "a\0\0\0b\0\0\0c\0\0\0g\0\0\0h\0\0\0i\0\0\0n\0\0\0o\0\0\0p\0\0\0", 9*4) != 0)
__builtin_abort ();
if (memcmp ((const char*) z->base_addr, "a\0\0\0b\0\0\0c\0\0\0g\0\0\0h\0\0\0i\0\0\0n\0\0\0o\0\0\0p\0\0\0", 9*4) != 0)
__builtin_abort ();
}
else if (intent_in && num == 2)
{
if (memcmp ((const char*) x->base_addr, "d\0\0\0e\0\0\0f\0\0\0g\0\0\0h\0\0\0i\0\0\0j\0\0\0l\0\0\0m\0\0\0", 9) != 0)
__builtin_abort ();
if (memcmp ((const char*) y->base_addr, "d\0\0\0e\0\0\0f\0\0\0g\0\0\0h\0\0\0i\0\0\0j\0\0\0l\0\0\0m\0\0\0", 9) != 0)
__builtin_abort ();
if (memcmp ((const char*) z->base_addr, "d\0\0\0e\0\0\0f\0\0\0g\0\0\0h\0\0\0i\0\0\0j\0\0\0l\0\0\0m\0\0\0", 9) != 0)
__builtin_abort ();
}
else if (intent_in)
__builtin_abort ();
if (intent_in)
{
if (is_cont && num == 1)
{
/* Copy in - set the value to check that no copy out is done. */
memcpy ((char*) x->base_addr, "1\0\0\0""2\0\0\0""3\0\0\0""4\0\0\0""5\0\0\0""6\0\0\0""7\0\0\0""8\0\0\0""9\0\0\0", 9*4);
memcpy ((char*) y->base_addr, "1\0\0\0""2\0\0\0""3\0\0\0""4\0\0\0""5\0\0\0""6\0\0\0""7\0\0\0""8\0\0\0""9\0\0\0", 9*4);
memcpy ((char*) z->base_addr, "1\0\0\0""2\0\0\0""3\0\0\0""4\0\0\0""5\0\0\0""6\0\0\0""7\0\0\0""8\0\0\0""9\0\0\0", 9*4);
}
return addr1;
}
// !intent_in
if (!is_cont && num == 1)
{
check_str (x, "A\0\0\0B\0\0\0C\0\0\0", 3*4, zero);
check_str (x, "D\0\0\0E\0\0\0F\0\0\0", 3*4, one);
check_str (x, "G\0\0\0H\0\0\0I\0\0\0", 3*4, two);
check_str (y, "A\0\0\0B\0\0\0C\0\0\0", 3*4, zero);
check_str (y, "D\0\0\0E\0\0\0F\0\0\0", 3*4, one);
check_str (y, "G\0\0\0H\0\0\0I\0\0\0", 3*4, two);
check_str (z, "A\0\0\0B\0\0\0C\0\0\0", 3*4, zero);
check_str (z, "D\0\0\0E\0\0\0F\0\0\0", 3*4, one);
check_str (z, "G\0\0\0H\0\0\0I\0\0\0", 3*4, two);
}
else
{
if (memcmp ((const char*) x->base_addr, "A\0\0\0B\0\0\0C\0\0\0D\0\0\0E\0\0\0F\0\0\0G\0\0\0H\0\0\0I\0\0\0", 9*4) != 0)
__builtin_abort ();
if (memcmp ((const char*) y->base_addr, "A\0\0\0B\0\0\0C\0\0\0D\0\0\0E\0\0\0F\0\0\0G\0\0\0H\0\0\0I\0\0\0", 9*4) != 0)
__builtin_abort ();
if (memcmp ((const char*) z->base_addr, "A\0\0\0B\0\0\0C\0\0\0D\0\0\0E\0\0\0F\0\0\0G\0\0\0H\0\0\0I\0\0\0", 9*4) != 0)
__builtin_abort ();
}
return addr1;
}
struct loc_t
char_assumed_size_c (CFI_cdesc_t *x, CFI_cdesc_t *y, CFI_cdesc_t *z,
int k, int num)
{
return do_call (x, y, z, k, num, false, char_assumed_size_f, true, false);
}
struct loc_t
char_assumed_size_in_c (CFI_cdesc_t *x, CFI_cdesc_t *y, CFI_cdesc_t *z,
int k, int num)
{
return do_call (x, y, z, k, num, true, char_assumed_size_in_f, true, false);
}
struct loc_t
char_expl_size_c (CFI_cdesc_t *x, CFI_cdesc_t *y, CFI_cdesc_t *z,
int k, int num)
{
return do_call (x, y, z, k, num, false, char_expl_size_f, true, false);
}
struct loc_t
char_expl_size_in_c (CFI_cdesc_t *x, CFI_cdesc_t *y, CFI_cdesc_t *z,
int k, int num)
{
return do_call (x, y, z, k, num, true, char_expl_size_in_f, true, false);
}
struct loc_t
char_assumed_rank_c (CFI_cdesc_t *x, CFI_cdesc_t *y, CFI_cdesc_t *z,
int k, int num)
{
return do_call (x, y, z, k, num, false, char_assumed_rank_f, false, false);
}
struct loc_t
char_assumed_rank_in_c (CFI_cdesc_t *x, CFI_cdesc_t *y, CFI_cdesc_t *z,
int k, int num)
{
return do_call (x, y, z, k, num, true, char_assumed_rank_in_f, false, false);
}
struct loc_t
char_assumed_rank_cont_c (CFI_cdesc_t *x, CFI_cdesc_t *y, CFI_cdesc_t *z,
int k, int num)
{
return do_call (x, y, z, k, num, false, char_assumed_rank_cont_f, true, false);
}
struct loc_t
char_assumed_rank_cont_in_c (CFI_cdesc_t *x, CFI_cdesc_t *y, CFI_cdesc_t *z,
int k, int num)
{
return do_call (x, y, z, k, num, true, char_assumed_rank_cont_in_f, true, false);
}
static void
reset_var (CFI_cdesc_t *x, int num)
{
const CFI_index_t zero[1] = { 0 };
const CFI_index_t one[1] = { 1 };
const CFI_index_t two[1] = { 2 };
if (num == 1)
{
set_str (x, "a\0\0\0b\0\0\0c\0\0\0", 3*4, zero);
set_str (x, "g\0\0\0h\0\0\0i\0\0\0", 3*4, one);
set_str (x, "n\0\0\0o\0\0\0p\0\0\0", 3*4, two);
}
else if (num == 2)
{
set_str (x, "d\0\0\0e\0\0\0f\0\0\0", 3*4, zero);
set_str (x, "g\0\0\0h\0\0\0i\0\0\0", 3*4, one);
set_str (x, "j\0\0\0l\0\0\0m\0\0\0", 3*4, two);
}
else
__builtin_abort ();
}
static void
reset_vars (CFI_cdesc_t *x, CFI_cdesc_t *y, CFI_cdesc_t *z, int num)
{
reset_var (x, num);
reset_var (y, num);
reset_var (z, num);
}
struct loc_t
char_assumed_shape_c (CFI_cdesc_t *x, CFI_cdesc_t *y, CFI_cdesc_t *z,
int k, int num)
{
/* Make use of having a noncontiguous argument to check that the callee
handles noncontiguous variables. */
do_call (x, y, z, k, num, false, char_assumed_size_f, false, true);
reset_vars (x, y, z, num);
do_call (x, y, z, k, num, true, char_assumed_size_in_f, false, true);
reset_vars (x, y, z, num);
do_call (x, y, z, k, num, false, char_expl_size_f, false, true);
reset_vars (x, y, z, num);
do_call (x, y, z, k, num, true, char_expl_size_in_f, false, true);
reset_vars (x, y, z, num);
do_call (x, y, z, k, num, false, char_assumed_rank_cont_f, false, true);
reset_vars (x, y, z, num);
do_call (x, y, z, k, num, true, char_assumed_rank_cont_in_f, false, true);
reset_vars (x, y, z, num);
do_call (x, y, z, k, num, false, char_assumed_shape_cont_f, false, true);
reset_vars (x, y, z, num);
do_call (x, y, z, k, num, true, char_assumed_shape_cont_in_f, false, true);
/* Actual func call. */
reset_vars (x, y, z, num);
return do_call (x, y, z, k, num, false, char_assumed_shape_f, false, false);
}
struct loc_t
char_assumed_shape_in_c (CFI_cdesc_t *x, CFI_cdesc_t *y, CFI_cdesc_t *z,
int k, int num)
{
return do_call (x, y, z, k, num, true, char_assumed_shape_in_f, false, false);
}
struct loc_t
char_assumed_shape_cont_c (CFI_cdesc_t *x, CFI_cdesc_t *y, CFI_cdesc_t *z,
int k, int num)
{
return do_call (x, y, z, k, num, false, char_assumed_shape_cont_f, true, false);
}
struct loc_t
char_assumed_shape_cont_in_c (CFI_cdesc_t *x, CFI_cdesc_t *y, CFI_cdesc_t *z,
int k, int num)
{
return do_call (x, y, z, k, num, true, char_assumed_shape_cont_in_f, true, false);
}

File diff suppressed because it is too large Load diff

View file

@ -1,4 +1,4 @@
! { dg-do compile }
! { dg-do run }
! { dg-options "-fdump-tree-original" }
!
! PR fortran/91863
@ -28,15 +28,20 @@ program p
if (.not.allocated(a)) stop 1
if (any(shape(a) /= [3])) stop 2
if (lbound(a,1) /= 3 .or. ubound(a,1) /= 5) stop 3
print *, a(0), a(1), a(2), a(3), a(4)
print *, a
if (any(a /= [1, 2, 3])) stop 4
end program p
! "cfi" only appears in context of "a" -> bind-C descriptor
! the intent(out) implies freeing in the callee (!), hence the "free"
! the intent(out) implies freeing in the callee (!) (when implemented in Fortran), hence the "free"
! and also in the caller (when implemented in Fortran)
! It is the only 'free' as 'a' is part of the main program and, hence, implicitly has the SAVE attribute.
! The 'cfi = 0' appears before the call due to the deallocate and when preparing the C descriptor
! As cfi (i.e. the descriptor itself) is allocated in libgomp, it has to be freed after the call.
! { dg-final { scan-tree-dump-times "__builtin_free" 2 "original" } }
! { dg-final { scan-tree-dump-times "__builtin_free \\(cfi\\.\[0-9\]+\\);" 2 "original" } }
! { dg-final { scan-tree-dump-times "cfi\\.\[0-9\]+ = 0B;" 2 "original" } }
! { dg-final { scan-tree-dump-times "__builtin_free \\(_x->base_addr\\);" 1 "original" } }
! { dg-final { scan-tree-dump-times "_x->base_addr = 0B;" 1 "original" } }
! { dg-final { scan-tree-dump-times "__builtin_free \\(cfi\\.\[0-9\]+\\.base_addr\\);" 1 "original" } }
! { dg-final { scan-tree-dump-times "cfi\\.\[0-9\]+\\.base_addr = 0B;" 1 "original" } }

View file

@ -22,4 +22,32 @@ end
! { dg-final { scan-assembler-times "brasl\t%r\[0-9\]*,myBindC" 1 { target { s390*-*-* } } } }
! { dg-final { scan-assembler-times "bl \.myBindC" 1 { target { powerpc-ibm-aix* } } } }
! { dg-final { scan-assembler-times "add_u32\t\[sv\]\[0-9\]*, \[sv\]\[0-9\]*, myBindC@rel32@lo" 1 { target { amdgcn*-*-* } } } }
! { dg-final { scan-tree-dump-times "gfc_desc_to_cfi_desc \\\(&cfi\\." 1 "original" } }
! { dg-final { scan-tree-dump "parm...span = 4;" "original" } }
! { dg-final { scan-tree-dump "parm...dtype = {.elem_len=4, .rank=2, .type=1};" "original" } }
! { dg-final { scan-tree-dump "parm...dim\\\[0\\\].lbound = 1;" "original" } }
! { dg-final { scan-tree-dump "parm...dim\\\[0\\\].ubound = 4;" "original" } }
! { dg-final { scan-tree-dump "parm...dim\\\[0\\\].stride = 1;" "original" } }
! { dg-final { scan-tree-dump "parm...dim\\\[1\\\].lbound = 1;" "original" } }
! { dg-final { scan-tree-dump "parm...dim\\\[1\\\].ubound = 4;" "original" } }
! { dg-final { scan-tree-dump "parm...dim\\\[1\\\].stride = 4;" "original" } }
! { dg-final { scan-tree-dump "parm...data = \\(void \\*\\) &aa\\\[0\\\];" "original" } }
! { dg-final { scan-tree-dump "parm...offset = -5;" "original" } }
! { dg-final { scan-tree-dump "cfi...version = 1;" "original" } }
! { dg-final { scan-tree-dump "cfi...rank = 2;" "original" } }
! { dg-final { scan-tree-dump "cfi...type = 1025;" "original" } }
! { dg-final { scan-tree-dump "cfi...attribute = 2;" "original" } }
! { dg-final { scan-tree-dump "cfi...base_addr = parm.0.data;" "original" } }
! { dg-final { scan-tree-dump "cfi...elem_len = 4;" "original" } }
! { dg-final { scan-tree-dump "idx.2 = 0;" "original" } }
! { dg-final { scan-tree-dump "if \\(idx.. <= 1\\) goto L..;" "original" } }
! { dg-final { scan-tree-dump "cfi...dim\\\[idx..\\\].lower_bound = 0;" "original" } }
! { dg-final { scan-tree-dump "cfi...dim\\\[idx..\\\].extent = \\(parm...dim\\\[idx..\\\].ubound - parm...dim\\\[idx..\\\].lbound\\) \\+ 1;" "original" } }
! { dg-final { scan-tree-dump "cfi...dim\\\[idx..\\\].sm = parm...dim\\\[idx..\\\].stride \\* parm...span;" "original" } }
! { dg-final { scan-tree-dump "idx.. = idx.. \\+ 1;" "original" } }
! { dg-final { scan-tree-dump "test \\(&cfi..\\);" "original" } }

View file

@ -466,15 +466,16 @@ program main
end
! All arguments shall use array descriptors
! { dg-final { scan-tree-dump-times "void as1 \\(struct array01_character\\(kind=1\\) & restrict x1\\)" 1 "original" } }
! { dg-final { scan-tree-dump-times "void as2 \\(struct array01_character\\(kind=1\\) & restrict x2\\)" 1 "original" } }
! { dg-final { scan-tree-dump-times "void as4 \\(struct array01_character\\(kind=1\\) & restrict xstar\\)" 1 "original" } }
! { dg-final { scan-tree-dump-times "void as3 \\(struct array01_character\\(kind=1\\) & restrict xn, integer(kind=4) & restrict n)
! { dg-final { scan-tree-dump-times "void ar1 \\(struct array15_character\\(kind=1\\) & restrict x1\\)" 1 "original" } }
! { dg-final { scan-tree-dump-times "void ar2 \\(struct array15_character\\(kind=1\\) & restrict x2\\)" 1 "original" } }
! { dg-final { scan-tree-dump-times "void ar3 \\(struct array15_character\\(kind=1\\) & restrict xn, integer(kind=4) & restrict n)
! { dg-final { scan-tree-dump-times "void ar4 \\(struct array15_character\\(kind=1\\) & restrict xstar\\)" 1 "original" } }
! { dg-final { scan-tree-dump-times "void a5a \\(struct array01_character\\(kind=1\\) & restrict xcolon\\)" 1 "original" } }
! { dg-final { scan-tree-dump-times "void a5ar \\(struct array15_character\\(kind=1\\) & restrict xcolon\\)" 1 "original" } }
! { dg-final { scan-tree-dump-times "void a5p \\(struct array01_character\\(kind=1\\) & xcolon\\)" 1 "original" } }
! { dg-final { scan-tree-dump-times "void a5pr \\(struct array15_character\\(kind=1\\) & xcolon\\)" 1 "original" } }
! { dg-final { scan-tree-dump-times "void as1 \\(struct CFI_cdesc_t01 & restrict _x1\\)" 1 "original" } }
! { dg-final { scan-tree-dump-times "void as2 \\(struct CFI_cdesc_t01 & restrict _x2\\)" 1 "original" } }
! { dg-final { scan-tree-dump-times "void as3 \\(struct CFI_cdesc_t01 & restrict _xn, integer\\(kind=4\\) & restrict n\\)" 1 "original" } }
! { dg-final { scan-tree-dump-times "void as4 \\(struct CFI_cdesc_t01 & restrict _xstar\\)" 1 "original" } }
! { dg-final { scan-tree-dump-times "void ar1 \\(struct CFI_cdesc_t & restrict _x1\\)" 1 "original" } }
! { dg-final { scan-tree-dump-times "void ar2 \\(struct CFI_cdesc_t & restrict _x2\\)" 1 "original" } }
! { dg-final { scan-tree-dump-times "void ar3 \\(struct CFI_cdesc_t & restrict _xn, integer\\(kind=4\\) & restrict n\\)" 1 "original" } }
! { dg-final { scan-tree-dump-times "void ar4 \\(struct CFI_cdesc_t & restrict _xstar\\)" 1 "original" } }
! { dg-final { scan-tree-dump-times "void a5ar \\(struct CFI_cdesc_t & restrict _xcolon\\)" 1 "original" } }
! { dg-final { scan-tree-dump-times "void a5a \\(struct CFI_cdesc_t01 & restrict _xcolon\\)" 1 "original" } }
! { dg-final { scan-tree-dump-times "void a5pr \\(struct CFI_cdesc_t & _xcolon\\)" 1 "original" } }
! { dg-final { scan-tree-dump-times "void a5p \\(struct CFI_cdesc_t01 & _xcolon\\)" 1 "original" } }

View file

@ -28,7 +28,7 @@ subroutine s3 (xn, n) bind(C) ! { dg-error "Character dummy argument 'xn' at .1.
character(len=n) :: xn
end
subroutine s4 (xstar) bind(C) ! { dg-error "Sorry, character dummy argument 'xstar' at .1. with assumed length is not yet supported for procedure 's4' with BIND\\(C\\) attribute" }
subroutine s4 (xstar) bind(C)
character(len=*) :: xstar
end
@ -85,7 +85,7 @@ subroutine az3 (xn, n) bind(C) ! { dg-error "Character dummy argument 'xn' at .1
character(len=n) :: xn(*)
end
subroutine az4 (xstar) bind(C) ! { dg-error "Sorry, character dummy argument 'xstar' at .1. with assumed length is not yet supported for procedure 'az4' with BIND\\(C\\) attribute" }
subroutine az4 (xstar) bind(C)
character(len=*) :: xstar(*)
end
@ -104,7 +104,7 @@ subroutine ae3 (xn, n) bind(C) ! { dg-error "Character dummy argument 'xn' at .1
character(len=n) :: xn(9)
end
subroutine ae4 (xstar) bind(C) ! { dg-error "Sorry, character dummy argument 'xstar' at .1. with assumed length is not yet supported for procedure 'ae4' with BIND\\(C\\) attribute" }
subroutine ae4 (xstar) bind(C)
character(len=*) :: xstar(3)
end
@ -128,7 +128,7 @@ subroutine s4a (xstar) bind(C) ! { dg-error "Allocatable character dummy argumen
character(len=*), allocatable :: xstar
end
subroutine s5a (xcolon) bind(C) ! { dg-error "Sorry, deferred-length scalar character dummy argument 'xcolon' at .1. of procedure 's5a' with BIND\\(C\\) not yet supported" }
subroutine s5a (xcolon) bind(C)
character(len=:), allocatable :: xcolon
end
@ -198,7 +198,7 @@ subroutine s4p (xstar) bind(C) ! { dg-error "Pointer character dummy argument 'x
character(len=*), pointer :: xstar
end
subroutine s5p (xcolon) bind(C) ! { dg-error "Sorry, deferred-length scalar character dummy argument 'xcolon' at .1. of procedure 's5p' with BIND\\(C\\) not yet supported" }
subroutine s5p (xcolon) bind(C)
character(len=:), pointer :: xcolon
end

View file

@ -1,6 +1,6 @@
! PR 101308
! PR 92621(?)
! { dg-do run { xfail *-*-* } }
! { dg-do run }
! { dg-additional-sources "allocatable-dummy-c.c dump-descriptors.c" }
! { dg-additional-options "-g" }
!

View file

@ -56,7 +56,7 @@ module m
end subroutine
! dummy is assumed length character variable
subroutine s6 (x) bind (c) ! { dg-bogus "Sorry" "pr92482" { xfail *-*-* } }
subroutine s6 (x) bind (c)
use ISO_C_BINDING
implicit none
character(len=*) :: x

View file

@ -44,7 +44,7 @@ subroutine s2 (x)
implicit none
type(*) :: x(*)
call g (x, 1) ! { dg-error "Assumed.type" }
call g (x, 1) ! { dg-error "Assumed-type actual argument at .1. corresponding to assumed-rank dummy argument 'a' must be assumed-shape or assumed-rank" }
end subroutine
! Check that a scalar gives an error.

View file

@ -7,7 +7,7 @@
! in C works and that you can use it to call back into a Fortran function
! with an assumed-length dummy that is declared with C binding.
subroutine ftest (a, n) bind (c, name="ftest") ! { dg-bogus "Sorry" "pr92482" { xfail *-*-* } }
subroutine ftest (a, n) bind (c, name="ftest")
use iso_c_binding
character(kind=C_CHAR, len=*) :: a
integer(C_INT), value :: n

View file

@ -1,5 +1,5 @@
! PR 92621 (?)
! { dg-do run { xfail *-*-* } }
! { dg-do run }
! { dg-additional-sources "cf-out-descriptor-3-c.c dump-descriptors.c" }
! { dg-additional-options "-g" }
!

View file

@ -1,5 +1,5 @@
! PR 92621 (?)
! { dg-do run { xfail *-*-* } }
! { dg-do run }
! { dg-additional-sources "cf-out-descriptor-4-c.c dump-descriptors.c" }
! { dg-additional-options "-g" }
!

View file

@ -6,7 +6,7 @@
! This program checks use of an assumed-length character dummy argument
! as an intent(out) parameter in subroutines with C binding.
subroutine ftest (a, n) bind (c, name="ftest") ! { dg-bogus "Sorry" "pr92482" { xfail *-*-* } }
subroutine ftest (a, n) bind (c, name="ftest")
use iso_c_binding
character(kind=C_CHAR, len=*), intent(out) :: a
integer(C_INT), value :: n
@ -20,13 +20,13 @@ program testit
implicit none
interface
subroutine ctest (a, n) bind (c) ! { dg-bogus "Sorry" "pr92482" { xfail *-*-* } }
subroutine ctest (a, n) bind (c)
use iso_c_binding
character(kind=C_CHAR, len=*), intent(out) :: a
integer(C_INT), value :: n
end subroutine
subroutine ftest (a, n) bind (c) ! { dg-bogus "Sorry" "pr92482" { xfail *-*-* } }
subroutine ftest (a, n) bind (c)
use iso_c_binding
character(kind=C_CHAR, len=*), intent(out) :: a
integer(C_INT), value :: n

View file

@ -1,5 +1,5 @@
! PR 101304
! { dg-do run { xfail *-*-* } }
! { dg-do run }
! { dg-additional-sources "contiguous-2-c.c dump-descriptors.c" }
! { dg-additional-options "-g" }
!

View file

@ -1,5 +1,5 @@
! PR 101304
! { dg-do run { xfail *-*-* } }
! { dg-do run }
! { dg-additional-sources "contiguous-3-c.c dump-descriptors.c" }
! { dg-additional-options "-g" }
!

View file

@ -16,12 +16,12 @@ module m
interface
! These are supposed to be OK
subroutine good1 (x, n) bind (c) ! { dg-bogus "Sorry" "pr92482" { xfail *-*-* } }
subroutine good1 (x, n) bind (c)
use iso_c_binding
character (kind=C_CHAR, len=:), allocatable :: x
integer(C_INT), value :: n
end subroutine
subroutine good2 (x, n) bind (c) ! { dg-bogus "Sorry" "pr92482" { xfail *-*-* } }
subroutine good2 (x, n) bind (c)
use iso_c_binding
character (kind=C_CHAR, len=:), pointer :: x
integer(C_INT), value :: n

View file

@ -43,7 +43,7 @@ program testit
p = 'bar'
end subroutine
subroutine frobc (a, p) bind (c) ! { dg-bogus "Sorry" "pr92482" { xfail *-*-* } }
subroutine frobc (a, p) bind (c)
use iso_c_binding
character (kind=C_CHAR, len=:), allocatable :: a
character (kind=C_CHAR, len=:), pointer :: p

View file

@ -1,5 +1,5 @@
! PR 101308
! { dg-do run { xfail *-*-* } }
! { dg-do run }
! { dg-additional-sources "fc-descriptor-3-c.c dump-descriptors.c" }
! { dg-additional-options "-g" }
!

View file

@ -11,7 +11,7 @@ program testit
implicit none
interface
subroutine ctest (a) bind (c) ! { dg-bogus "Sorry" "pr92482" { xfail *-*-* } }
subroutine ctest (a) bind (c)
use iso_c_binding
character(len=*,kind=C_CHAR) :: a
end subroutine

View file

@ -1,5 +1,5 @@
! Reported as pr94070.
! { dg-do run { xfail *-*-* } }
! { dg-do run }
! { dg-additional-sources "fc-descriptor-6-c.c dump-descriptors.c" }
! { dg-additional-options "-g" }
!

View file

@ -3,14 +3,18 @@
#include <ISO_Fortran_binding.h>
#include "dump-descriptors.h"
extern void ctest (CFI_cdesc_t *a);
extern void ctest (CFI_cdesc_t *, _Bool);
void
ctest (CFI_cdesc_t *a)
ctest (CFI_cdesc_t *a, _Bool is_cont)
{
CFI_index_t subscripts[2];
/* Dump the descriptor contents to test that we can access the fields
correctly, etc. */
#if DEBUG
dump_CFI_cdesc_t (a);
#endif
/* We expect to get an array of shape (5,10) that may not be
contiguous. */
@ -33,14 +37,17 @@ ctest (CFI_cdesc_t *a)
if (a->dim[1].extent != 10)
abort ();
/* There shall be an ordering of the dimensions such that the absolute
value of the sm member of the first dimension is not less than the
elem_len member of the C descriptor and the absolute value of the sm
member of each subsequent dimension is not less than the absolute
value of the sm member of the previous dimension multiplied
by the extent of the previous dimension. */
if (is_cont != CFI_is_contiguous (a))
abort ();
if (abs (a->dim[0].sm) < a->elem_len)
abort ();
if (abs (a->dim[1].sm) < abs (a->dim[0].sm) * a->dim[0].extent)
abort ();
for (int j = 0; j < 5; ++j)
for (int i = 0; i < 10; ++i)
{
subscripts[0] = j; subscripts[1] = i;
if (*(int *) CFI_address (a, subscripts) != (i+1) + 100*(j+1))
abort ();
}
}

View file

@ -1,5 +1,5 @@
! PR 101309
! { dg-do run { xfail *-*-* } }
! { dg-do run }
! { dg-additional-sources "fc-descriptor-7-c.c dump-descriptors.c" }
! { dg-additional-options "-g" }
!
@ -8,30 +8,140 @@
program testit
use iso_c_binding
implicit none
implicit none (type, external)
interface
subroutine ctest (a) bind (c)
subroutine ctest (a, is_cont) bind (c)
use iso_c_binding
integer(C_INT), intent (in) :: a(:,:)
integer(C_INT) :: a(:,:)
logical(C_Bool), value :: is_cont
end subroutine
subroutine ctest_cont (a, is_cont) bind (c, name="ctest")
use iso_c_binding
integer(C_INT), contiguous :: a(:,:)
logical(C_Bool), value :: is_cont
end subroutine
subroutine ctest_ar (a, is_cont) bind (c, name="ctest")
use iso_c_binding
integer(C_INT) :: a(..)
logical(C_Bool), value :: is_cont
end subroutine
subroutine ctest_ar_cont (a, is_cont) bind (c, name="ctest")
use iso_c_binding
integer(C_INT), contiguous :: a(..)
logical(C_Bool), value :: is_cont
end subroutine
end interface
integer :: i , j
integer(C_INT), target :: aa(10,5)
integer(C_INT), target :: bb(10,10)
! Original array
do j = 1, 5
do i = 1, 10
aa(i,j) = i + 100*j
end do
end do
! Transposed array
do j = 2, 10, 2
do i = 1, 10
bb(j, i) = i + 100*((j-2)/2 + 1)
end do
end do
if (any (transpose (aa) /= bb(2:10:2, :))) error stop 1
! Test both calling the C function directly, and via another function
! that takes an assumed-shape argument.
call ctest (transpose (aa))
call ftest (transpose (aa))
call ctest (bb(2:10:2, :))
call ftest (bb(2:10:2, :))
! that takes an assumed-shape/assumed-rank argument.
call ftest (transpose (aa), is_cont=.true._c_bool) ! Implementation choice: copy in; hence, contiguous
if (any (transpose (aa) /= bb(2:10:2, :))) error stop 1
call ctest (transpose (aa), is_cont=.false._c_bool) ! Implementation choice: noncontigous / sm inversed
if (any (transpose (aa) /= bb(2:10:2, :))) error stop 1
call ctest_cont (transpose (aa), is_cont=.true._c_bool)
if (any (transpose (aa) /= bb(2:10:2, :))) error stop 1
call ctest_ar (transpose (aa), is_cont=.false._c_bool) ! Implementation choice: noncontigous / sm inversed
if (any (transpose (aa) /= bb(2:10:2, :))) error stop 1
call ctest_ar_cont (transpose (aa), is_cont=.true._c_bool)
if (any (transpose (aa) /= bb(2:10:2, :))) error stop 1
call ftest (bb(2:10:2, :), is_cont=.false._c_bool)
if (any (transpose (aa) /= bb(2:10:2, :))) error stop 1
call ctest (bb(2:10:2, :), is_cont=.false._c_bool)
if (any (transpose (aa) /= bb(2:10:2, :))) error stop 1
call ctest_cont (bb(2:10:2, :), is_cont=.true._c_bool)
if (any (transpose (aa) /= bb(2:10:2, :))) error stop 1
call ctest_ar (bb(2:10:2, :), is_cont=.false._c_bool)
if (any (transpose (aa) /= bb(2:10:2, :))) error stop 1
call ctest_ar_cont (bb(2:10:2, :), is_cont=.true._c_bool)
if (any (transpose (aa) /= bb(2:10:2, :))) error stop 1
contains
subroutine ftest (a)
subroutine ftest (a, is_cont)
use iso_c_binding
integer(C_INT), intent(in) :: a(:,:)
call ctest (a)
integer(C_INT) :: a(:,:)
logical(c_bool), value, intent(in) :: is_cont
if (is_cont .NEQV. is_contiguous (a)) error stop 2
if (any (shape (a) /= [5, 10])) error stop 3
do j = 1, 5
do i = 1, 10
if (a(j, i) /= i + 100*j) error stop 4
if (a(j, i) /= aa(i,j)) error stop
end do
end do
call ctest (a, is_cont)
call ctest_cont (a, is_cont=.true._c_bool)
call ctest_ar (a, is_cont)
call ctest_ar_cont (a, is_cont=.true._c_bool)
end subroutine
subroutine ftest_ar (a, is_cont)
use iso_c_binding
integer(C_INT) :: a(..)
logical(c_bool), value, intent(in) :: is_cont
if (is_cont .NEQV. is_contiguous (a)) error stop 2
if (any (shape (a) /= [5, 10])) error stop 3
select rank (a)
rank(2)
do j = 1, 5
do i = 1, 10
if (a(j, i) /= i + 100*j) error stop 4
if (a(j, i) /= aa(i,j)) error stop
end do
end do
call ctest (a, is_cont)
call ctest_cont (a, is_cont=.true._c_bool)
call ftest_ar_con (a, is_cont=.true._c_bool)
end select
call ctest_ar (a, is_cont)
! call ctest_ar_cont (a, is_cont=.true._c_bool) ! TODO/FIXME: ICE, cf. PR fortran/102729
! call ftest_ar_con (a, is_cont=.true._c_bool) ! TODO/FIXME: ICE, cf. PR fortran/102729
end subroutine
subroutine ftest_ar_con (a, is_cont)
use iso_c_binding
integer(C_INT), contiguous :: a(..)
logical(c_bool), value, intent(in) :: is_cont
if (is_cont .NEQV. is_contiguous (a)) error stop 2
if (any (shape (a) /= [5, 10])) error stop 3
select rank (a)
rank(2)
do j = 1, 5
do i = 1, 10
if (a(j, i) /= i + 100*j) error stop 4
if (a(j, i) /= aa(i,j)) error stop
end do
end do
call ctest (a, is_cont)
call ctest_cont (a, is_cont=.true._c_bool)
end select
call ctest_ar (a, is_cont)
call ctest_ar_cont (a, is_cont=.true._c_bool)
end subroutine
end program

View file

@ -1,5 +1,5 @@
! PR 101308
! { dg-do run { xfail *-*-* } }
! { dg-do run }
! { dg-additional-sources "fc-out-descriptor-3-c.c dump-descriptors.c" }
! { dg-additional-options "-g" }
!

View file

@ -1,5 +1,5 @@
! PR 92621 (?)
! { dg-do run { xfail *-*-* } }
! { dg-do run }
! { dg-additional-sources "fc-out-descriptor-4-c.c dump-descriptors.c" }
! { dg-additional-options "-g" }
!

View file

@ -10,7 +10,7 @@ program testit
implicit none
interface
subroutine ctest (a) bind (c) ! { dg-bogus "Sorry" "pr92482" { xfail *-*-* } }
subroutine ctest (a) bind (c)
use iso_c_binding
character(len=*,kind=C_CHAR), intent(out) :: a
end subroutine
@ -26,7 +26,7 @@ program testit
call ftest (aa)
contains
subroutine ftest (a) bind (c) ! { dg-bogus "Sorry" "pr92482" { xfail *-*-* } }
subroutine ftest (a) bind (c)
use iso_c_binding
character(len=*,kind=C_CHAR), intent(out) :: a
call ctest (a)

View file

@ -1,5 +1,5 @@
! Reported as pr94070.
! { dg-do run { xfail *-*-* } }
! { dg-do run }
! { dg-additional-sources "fc-out-descriptor-6-c.c dump-descriptors.c" }
! { dg-additional-options "-g" }
!

View file

@ -17,7 +17,7 @@ contains
! C binding version
subroutine checkc (a) bind (c) ! { dg-bogus "Sorry" "pr92482" { xfail *-*-* } }
subroutine checkc (a) bind (c)
use iso_c_binding
character(len=*,kind=C_CHAR) :: a
@ -37,7 +37,7 @@ contains
end subroutine
! C binding version
subroutine testc (a) bind (c) ! { dg-bogus "Sorry" "pr92482" { xfail *-*-* } }
subroutine testc (a) bind (c)
use iso_c_binding
character(len=*,kind=C_CHAR) :: a

View file

@ -1,5 +1,5 @@
! Reported as pr94070.
! { dg-do run { xfail *-*-* } }
! { dg-do run }
!
! This program checks that passing assumed-size arrays to
! and from Fortran functions with C binding works.

View file

@ -15,7 +15,7 @@
! subroutine with an assumed-rank dummy.
program test
implicit none
! Define some arrays for testing.
integer, target :: x1(5)
integer :: y1(0:9)
@ -51,7 +51,7 @@ contains
r = rank(a)
block
integer :: s(r)
integer :: s(r), i
s = shape(a)
do i = 1, r
if (s(i) .ne. size(a,i)) stop 101

View file

@ -33,3 +33,9 @@ ctest_1 (CFI_cdesc_t *arg_char, CFI_cdesc_t *arg_ucs4)
check (arg_ucs4, 4, CFI_type_ucs4_char);
}
void
ctest_5 (CFI_cdesc_t *arg_char, CFI_cdesc_t *arg_ucs4)
{
check (arg_char, 5*1, CFI_type_char);
check (arg_ucs4, 5*4, CFI_type_ucs4_char);
}

View file

@ -27,11 +27,21 @@ program testit
character(kind=ucs4) :: arg_ucs4(:)
end subroutine
subroutine ctest_5 (arg_cchar, arg_ucs4) bind (c)
use iso_c_binding
integer, parameter :: ucs4 = selected_char_kind ('ISO_10646')
character(kind=C_CHAR,len=*) :: arg_cchar(:)
character(kind=ucs4,len=*) :: arg_ucs4(:)
end subroutine
end interface
character(kind=C_CHAR) :: var_cchar(4)
character(kind=ucs4) :: var_ucs4(4)
character(kind=C_CHAR,len=5) :: var_cchar_5(4)
character(kind=ucs4,len=5) :: var_ucs4_5(4)
call ctest_1 (var_cchar, var_ucs4)
call ctest_5 (var_cchar_5, var_ucs4_5)
end program

View file

@ -2,7 +2,7 @@
! PR 100914
! PR 100917
! Fails on x86 targets where sizeof(long double) == 16 (PR100917).
! { dg-do run { xfail { { x86_64*-*-* i?86*-*-* } && longdouble128 } } }
! { dg-do run }
! { dg-require-effective-target fortran_real_c_float128 }
! { dg-additional-sources "typecodes-array-float128-c.c dump-descriptors.c" }
! { dg-additional-options "-g" }

View file

@ -1,7 +1,7 @@
! PR 101305
! PR 100917
! xfailed due to PR 101308
! { dg-do run { xfail *-*-* } }
! { dg-do run }
! { dg-additional-sources "typecodes-scalar-basic-c.c dump-descriptors.c" }
! { dg-additional-options "-g" }
!

View file

@ -1,7 +1,7 @@
! xfailed due to PR 101308
! PR 101305
! PR 100914
! { dg-do run { xfail *-*-* } }
! { dg-do run }
! { dg-require-effective-target fortran_real_c_float128 }
! { dg-additional-sources "typecodes-scalar-float128-c.c dump-descriptors.c" }
! { dg-additional-options "-g" }

View file

@ -1,6 +1,6 @@
! PR 101305
! xfailed due to PR 101308
! { dg-do run { xfail *-*-* } }
! { dg-do run }
! { dg-require-effective-target fortran_integer_16 }
! { dg-additional-sources "typecodes-scalar-int128-c.c dump-descriptors.c" }
! { dg-additional-options "-g" }

View file

@ -1,7 +1,7 @@
! xfailed due to PR 101308
! PR 101305
! PR 100917
! { dg-do run { xfail *-*-* } }
! { dg-do run }
! { dg-additional-sources "typecodes-scalar-longdouble-c.c dump-descriptors.c" }
! { dg-additional-options "-g" }
!

View file

@ -4,8 +4,7 @@
!
! Contributed by Thomas Koenig <tkoenig@gcc.gnu.org>
!
subroutine bar(c,d) BIND(C) ! { dg-error "character dummy argument 'c' at .1. with assumed length is not yet supported for procedure 'bar' with BIND\\(C\\) attribute" }
! { dg-error "Character dummy argument 'd' at .1. must be of constant length of one or assumed length, unless it has assumed shape or assumed rank, as procedure 'bar' has the BIND\\(C\\) attribute" "" { target *-*-* } .-1 }
subroutine bar(c,d) BIND(C) ! { dg-error "Character dummy argument 'd' at .1. must be of constant length of one or assumed length, unless it has assumed shape or assumed rank, as procedure 'bar' has the BIND\\(C\\) attribute" }
character (len=*) c
character (len=2) d
end

View file

@ -14,4 +14,4 @@ end
! { dg-error "Parameterized type 't' does not have a component" " " { target *-*-* } 5 }
! { dg-error "BOZ literal constant at .1. cannot appear" " " { target *-*-* } 6 }
! { dg-error "Cannot open module file" " " { target *-*-* } 10 }
! { dg-excess-errors "compilation terminated" }
! { dg-prune-output "compilation terminated" }

View file

@ -152,14 +152,10 @@ extern int CFI_setpointer (CFI_cdesc_t *, CFI_cdesc_t *, const CFI_index_t []);
#define CFI_type_Complex 4
#define CFI_type_Character 5
/* Types with no kind. FIXME: GFC descriptors currently use BT_VOID for
both C_PTR and C_FUNPTR, so we have no choice but to make them
identical here too. That can potentially break on targets where
function and data pointers have different sizes/representations.
See PR 100915. */
/* Types with no kind. */
#define CFI_type_struct 6
#define CFI_type_cptr 7
#define CFI_type_cfunptr CFI_type_cptr
#define CFI_type_cfunptr 8
#define CFI_type_other -1
/* Types with kind parameter.

View file

@ -34,6 +34,8 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
extern void cfi_desc_to_gfc_desc (gfc_array_void *, CFI_cdesc_t **);
export_proto(cfi_desc_to_gfc_desc);
/* NOTE: Since GCC 12, the FE generates code to do the conversion
directly without calling this function. */
void
cfi_desc_to_gfc_desc (gfc_array_void *d, CFI_cdesc_t **s_ptr)
{
@ -122,6 +124,8 @@ cfi_desc_to_gfc_desc (gfc_array_void *d, CFI_cdesc_t **s_ptr)
extern void gfc_desc_to_cfi_desc (CFI_cdesc_t **, const gfc_array_void *);
export_proto(gfc_desc_to_cfi_desc);
/* NOTE: Since GCC 12, the FE generates code to do the conversion
directly without calling this function. */
void
gfc_desc_to_cfi_desc (CFI_cdesc_t **d_ptr, const gfc_array_void *s)
{

View file

@ -0,0 +1,18 @@
! With bind(C), the C (CFI) array descriptor is converted to
! a Fortran array descriptor - thus, internally a PARM_DECL is
! converted to a VAR_DECL - check that the optional check still works
module m
contains
subroutine foo(x, y) bind(C)
integer, optional :: x,y(:)
!$omp target map(tofrom:x)
if (present (x)) x = 5
if (present (y)) y(1) = 5
!$omp end target
end
end
use m
call foo()
end