aboutsummaryrefslogtreecommitdiff
path: root/gcc/fortran/check.c
diff options
context:
space:
mode:
authorTobias Burnus <burnus@net-b.de>2013-03-25 16:40:26 +0100
committerTobias Burnus <burnus@gcc.gnu.org>2013-03-25 16:40:26 +0100
commitcadddfdda2c4a16e7fdd5f0d8d02b465caad2ad5 (patch)
tree8a59184d212dad5695956782c588f54b5ed68b53 /gcc/fortran/check.c
parenta5a4c20a5c922f2faa66b9326b336b5d7eb5065e (diff)
downloadgcc-cadddfdda2c4a16e7fdd5f0d8d02b465caad2ad5.zip
gcc-cadddfdda2c4a16e7fdd5f0d8d02b465caad2ad5.tar.gz
gcc-cadddfdda2c4a16e7fdd5f0d8d02b465caad2ad5.tar.bz2
re PR fortran/38536 (ICE with C_LOC in resolve.c due to not properly going through expr->ref)
2013-03-25 Tobias Burnus <burnus@net-b.de> PR fortran/38536 PR fortran/38813 PR fortran/38894 PR fortran/39288 PR fortran/40963 PR fortran/45824 PR fortran/47023 PR fortran/47034 PR fortran/49023 PR fortran/50269 PR fortran/50612 PR fortran/52426 PR fortran/54263 PR fortran/55343 PR fortran/55444 PR fortran/55574 PR fortran/56079 PR fortran/56378 * check.c (gfc_var_strlen): Properly handle 0-sized string. (gfc_check_c_sizeof): Use is_c_interoperable, add checks. (is_c_interoperable, gfc_check_c_associated, gfc_check_c_f_pointer, gfc_check_c_f_procpointer, gfc_check_c_funloc, gfc_check_c_loc): New functions. * expr.c (check_inquiry): Add c_sizeof, compiler_version and compiler_options. (gfc_check_pointer_assign): Refine function result check. gfortran.h (gfc_isym_id): Add GFC_ISYM_C_ASSOCIATED, GFC_ISYM_C_F_POINTER, GFC_ISYM_C_F_PROCPOINTER, GFC_ISYM_C_FUNLOC, GFC_ISYM_C_LOC. (iso_fortran_env_symbol, iso_c_binding_symbol): Handle NAMED_SUBROUTINE. (generate_isocbinding_symbol): Update prototype. (get_iso_c_sym): Remove. (gfc_isym_id_by_intmod, gfc_isym_id_by_intmod_sym): New prototypes. * intrinsic.c (gfc_intrinsic_subroutine_by_id): New function. (gfc_intrinsic_sub_interface): Use it. (add_functions, add_subroutines): Add missing C-binding intrinsics. (gfc_intrinsic_func_interface): Add special case for c_loc. gfc_isym_id_by_intmod, gfc_isym_id_by_intmod_sym): New functions. (gfc_intrinsic_func_interface, gfc_intrinsic_sub_interface): Use them. * intrinsic.h (gfc_check_c_associated, gfc_check_c_f_pointer, gfc_check_c_f_procpointer, gfc_check_c_funloc, gfc_check_c_loc, gfc_resolve_c_loc, gfc_resolve_c_funloc): New prototypes. * iresolve.c (gfc_resolve_c_loc, gfc_resolve_c_funloc): New functions. * iso-c-binding.def: Split PROCEDURE into NAMED_SUBROUTINE and NAMED_FUNCTION. * iso-fortran-env.def: Add NAMED_SUBROUTINE for completeness. * module.c (create_intrinsic_function): Support subroutines and derived-type results. (use_iso_fortran_env_module): Update calls. (import_iso_c_binding_module): Ditto; update calls to generate_isocbinding_symbol. * resolve.c (find_arglists): Skip for intrinsic symbols. (gfc_resolve_intrinsic): Find intrinsic subs via id. (is_scalar_expr_ptr, gfc_iso_c_func_interface, set_name_and_label, gfc_iso_c_sub_interface): Remove. (resolve_function, resolve_specific_s0): Remove calls to those. (resolve_structure_cons): Fix handling. * symbol.c (gen_special_c_interop_ptr): Update c_ptr/c_funptr generation. (gen_cptr_param, gen_fptr_param, gen_shape_param, build_formal_args, get_iso_c_sym): Remove. (std_for_isocbinding_symbol): Handle NAMED_SUBROUTINE. (generate_isocbinding_symbol): Support hidden symbols and using c_ptr/c_funptr symtrees for nullptr defs. * target-memory.c (gfc_target_encode_expr): Fix handling of c_ptr/c_funptr. * trans-expr.c (conv_isocbinding_procedure): Remove. (gfc_conv_procedure_call): Remove call to it. (gfc_trans_subcomponent_assign, gfc_conv_expr): Update handling of c_ptr/c_funptr. * trans-intrinsic.c (conv_isocbinding_function, conv_isocbinding_subroutine): New. (gfc_conv_intrinsic_function, gfc_conv_intrinsic_subroutine): Call them. * trans-io.c (transfer_expr): Fix handling of c_ptr/c_funptr. * trans-types.c (gfc_typenode_for_spec, gfc_get_derived_type): Ditto. (gfc_init_c_interop_kinds): Handle NAMED_SUBROUTINE. 2013-03-25 Tobias Burnus <burnus@net-b.de> PR fortran/38536 PR fortran/38813 PR fortran/38894 PR fortran/39288 PR fortran/40963 PR fortran/45824 PR fortran/47023 PR fortran/47034 PR fortran/49023 PR fortran/50269 PR fortran/50612 PR fortran/52426 PR fortran/54263 PR fortran/55343 PR fortran/55444 PR fortran/55574 PR fortran/56079 PR fortran/56378 * gfortran.dg/c_assoc_2.f03: Update dg-error wording. * gfortran.dg/c_f_pointer_shape_test.f90: Ditto. * gfortran.dg/c_f_pointer_shape_tests_3.f03: Ditto. * gfortran.dg/c_f_pointer_tests_5.f90: Ditto. * gfortran.dg/c_funloc_tests_2.f03: Ditto. * gfortran.dg/c_funloc_tests_5.f03: Ditto. * gfortran.dg/c_funloc_tests_6.f90: Ditto. * gfortran.dg/c_loc_tests_10.f03: Add -std=f2008. * gfortran.dg/c_loc_tests_11.f03: Ditto, update dg-error. * gfortran.dg/c_loc_tests_16.f90: Ditto. * gfortran.dg/c_loc_tests_4.f03: Ditto. * gfortran.dg/c_loc_tests_15.f90: Update dg-error wording. * gfortran.dg/c_loc_tests_3.f03: Valid since F2003 TC5. * gfortran.dg/c_loc_tests_8.f03: Ditto. * gfortran.dg/c_ptr_tests_14.f90: Update scan-tree-dump-times. * gfortran.dg/c_ptr_tests_15.f90: Ditto. * gfortran.dg/c_sizeof_1.f90: Fix invalid code. * gfortran.dg/iso_c_binding_init_expr.f03: Update dg-error wording. * gfortran.dg/pr32601_1.f03: Ditto. * gfortran.dg/storage_size_2.f08: Remove dg-error. * gfortran.dg/blockdata_7.f90: New. * gfortran.dg/c_assoc_4.f90: New. * gfortran.dg/c_f_pointer_tests_6.f90: New. * gfortran.dg/c_f_pointer_tests_7.f90: New. * gfortran.dg/c_funloc_tests_8.f90: New. * gfortran.dg/c_loc_test_17.f90: New. * gfortran.dg/c_loc_test_18.f90: New. * gfortran.dg/c_loc_test_19.f90: New. * gfortran.dg/c_loc_test_20.f90: New. * gfortran.dg/c_sizeof_5.f90: New. * gfortran.dg/iso_c_binding_rename_3.f90: New. * gfortran.dg/transfer_resolve_2.f90: New. * gfortran.dg/transfer_resolve_3.f90: New. * gfortran.dg/transfer_resolve_4.f90: New. * gfortran.dg/pr32601.f03: Update dg-error. * gfortran.dg/c_ptr_tests_13.f03: Update dg-error. * gfortran.dg/c_ptr_tests_9.f03: Fix test case. From-SVN: r197053
Diffstat (limited to 'gcc/fortran/check.c')
-rw-r--r--gcc/fortran/check.c397
1 files changed, 390 insertions, 7 deletions
diff --git a/gcc/fortran/check.c b/gcc/fortran/check.c
index 0e71b95..0460bf2 100644
--- a/gcc/fortran/check.c
+++ b/gcc/fortran/check.c
@@ -693,14 +693,19 @@ gfc_var_strlen (const gfc_expr *a)
{
long start_a, end_a;
- if (ra->u.ss.start->expr_type == EXPR_CONSTANT
+ if (!ra->u.ss.end)
+ return -1;
+
+ if ((!ra->u.ss.start || ra->u.ss.start->expr_type == EXPR_CONSTANT)
&& ra->u.ss.end->expr_type == EXPR_CONSTANT)
{
- start_a = mpz_get_si (ra->u.ss.start->value.integer);
+ start_a = ra->u.ss.start ? mpz_get_si (ra->u.ss.start->value.integer)
+ : 1;
end_a = mpz_get_si (ra->u.ss.end->value.integer);
- return end_a - start_a + 1;
+ return (end_a < start_a) ? 0 : end_a - start_a + 1;
}
- else if (gfc_dep_compare_expr (ra->u.ss.start, ra->u.ss.end) == 0)
+ else if (ra->u.ss.start
+ && gfc_dep_compare_expr (ra->u.ss.start, ra->u.ss.end) == 0)
return 1;
else
return -1;
@@ -3621,17 +3626,395 @@ gfc_check_sizeof (gfc_expr *arg)
}
+/* Check whether an expression is interoperable. When returning false,
+ msg is set to a string telling why the expression is not interoperable,
+ otherwise, it is set to NULL. The msg string can be used in diagnostics.
+ If all_len_okay is true, all length-type parameters (for character) are
+ allowed. Required for C_LOC (cf. Fortran 2003corr5 or Fortran 2008). */
+
+static bool
+is_c_interoperable (gfc_expr *expr, const char **msg, bool all_len_okay)
+{
+ *msg = NULL;
+
+ if (expr->ts.type == BT_CLASS)
+ {
+ *msg = "Expression is polymorphic";
+ return false;
+ }
+
+ if (expr->ts.type == BT_DERIVED && !expr->ts.u.derived->attr.is_bind_c
+ && !expr->ts.u.derived->ts.is_iso_c)
+ {
+ *msg = "Expression is a noninteroperable derived type";
+ return false;
+ }
+
+ if (expr->ts.type == BT_PROCEDURE)
+ {
+ *msg = "Procedure unexpected as argument";
+ return false;
+ }
+
+ if (gfc_notification_std (GFC_STD_GNU) && expr->ts.type == BT_LOGICAL)
+ {
+ int i;
+ for (i = 0; gfc_logical_kinds[i].kind; i++)
+ if (gfc_logical_kinds[i].kind == expr->ts.kind)
+ return true;
+ *msg = "Extension to use a non-C_Bool-kind LOGICAL";
+ return false;
+ }
+
+ if (gfc_notification_std (GFC_STD_GNU) && expr->ts.type == BT_CHARACTER
+ && expr->ts.kind != 1)
+ {
+ *msg = "Extension to use a non-C_CHAR-kind CHARACTER";
+ return false;
+ }
+
+ if (expr->ts.type == BT_CHARACTER) {
+ if (expr->ts.deferred)
+ {
+ /* TS 29113 allows deferred-length strings as dummy arguments,
+ but it is not an interoperable type. */
+ *msg = "Expression shall not be a deferred-length string";
+ return false;
+ }
+
+ if (expr->ts.u.cl && expr->ts.u.cl->length
+ && gfc_simplify_expr (expr, 0) == FAILURE)
+ gfc_internal_error ("is_c_interoperable(): gfc_simplify_expr failed");
+
+ if (!all_len_okay && expr->ts.u.cl
+ && (!expr->ts.u.cl->length
+ || expr->ts.u.cl->length->expr_type != EXPR_CONSTANT
+ || mpz_cmp_si (expr->ts.u.cl->length->value.integer, 1) != 0))
+ {
+ *msg = "Type shall have a character length of 1";
+ return false;
+ }
+ }
+
+ /* Note: The following checks are about interoperatable variables, Fortran
+ 15.3.5/15.3.6. In intrinsics like C_LOC or in procedure interface, more
+ is allowed, e.g. assumed-shape arrays with TS 29113. */
+
+ if (gfc_is_coarray (expr))
+ {
+ *msg = "Coarrays are not interoperable";
+ return false;
+ }
+
+ if (expr->rank > 0 && expr->expr_type != EXPR_ARRAY)
+ {
+ gfc_array_ref *ar = gfc_find_array_ref (expr);
+ if (ar->type != AR_FULL)
+ {
+ *msg = "Only whole-arrays are interoperable";
+ return false;
+ }
+ if (ar->as->type != AS_EXPLICIT && ar->as->type != AS_ASSUMED_SIZE)
+ {
+ *msg = "Only explicit-size and assumed-size arrays are interoperable";
+ return false;
+ }
+ }
+
+ return true;
+}
+
+
gfc_try
gfc_check_c_sizeof (gfc_expr *arg)
{
- if (gfc_verify_c_interop (&arg->ts) != SUCCESS)
+ const char *msg;
+
+ if (is_c_interoperable (arg, &msg, false) != SUCCESS)
{
gfc_error ("'%s' argument of '%s' intrinsic at %L must be an "
- "interoperable data entity",
+ "interoperable data entity: %s",
gfc_current_intrinsic_arg[0]->name, gfc_current_intrinsic,
- &arg->where);
+ &arg->where, msg);
+ return FAILURE;
+ }
+
+ if (arg->rank && arg->expr_type == EXPR_VARIABLE
+ && arg->symtree->n.sym->as != NULL
+ && arg->symtree->n.sym->as->type == AS_ASSUMED_SIZE && arg->ref
+ && arg->ref->type == REF_ARRAY && arg->ref->u.ar.type == AR_FULL)
+ {
+ gfc_error ("'%s' argument of '%s' intrinsic at %L shall not be an "
+ "assumed-size array", gfc_current_intrinsic_arg[0]->name,
+ gfc_current_intrinsic, &arg->where);
+ return FAILURE;
+ }
+
+ return SUCCESS;
+}
+
+
+gfc_try
+gfc_check_c_associated (gfc_expr *c_ptr_1, gfc_expr *c_ptr_2)
+{
+ if (c_ptr_1->ts.type != BT_DERIVED
+ || c_ptr_1->ts.u.derived->from_intmod != INTMOD_ISO_C_BINDING
+ || (c_ptr_1->ts.u.derived->intmod_sym_id != ISOCBINDING_PTR
+ && c_ptr_1->ts.u.derived->intmod_sym_id != ISOCBINDING_FUNPTR))
+ {
+ gfc_error ("Argument C_PTR_1 at %L to C_ASSOCIATED shall have the "
+ "type TYPE(C_PTR) or TYPE(C_FUNPTR)", &c_ptr_1->where);
+ return FAILURE;
+ }
+
+ if (scalar_check (c_ptr_1, 0) == FAILURE)
+ return FAILURE;
+
+ if (c_ptr_2
+ && (c_ptr_2->ts.type != BT_DERIVED
+ || c_ptr_2->ts.u.derived->from_intmod != INTMOD_ISO_C_BINDING
+ || (c_ptr_1->ts.u.derived->intmod_sym_id
+ != c_ptr_2->ts.u.derived->intmod_sym_id)))
+ {
+ gfc_error ("Argument C_PTR_2 at %L to C_ASSOCIATED shall have the "
+ "same type as C_PTR_1: %s instead of %s", &c_ptr_1->where,
+ gfc_typename (&c_ptr_1->ts),
+ gfc_typename (&c_ptr_2->ts));
+ return FAILURE;
+ }
+
+ if (c_ptr_2 && scalar_check (c_ptr_2, 1) == FAILURE)
+ return FAILURE;
+
+ return SUCCESS;
+}
+
+
+gfc_try
+gfc_check_c_f_pointer (gfc_expr *cptr, gfc_expr *fptr, gfc_expr *shape)
+{
+ symbol_attribute attr;
+ const char *msg;
+
+ if (cptr->ts.type != BT_DERIVED
+ || cptr->ts.u.derived->from_intmod != INTMOD_ISO_C_BINDING
+ || cptr->ts.u.derived->intmod_sym_id != ISOCBINDING_PTR)
+ {
+ gfc_error ("Argument CPTR at %L to C_F_POINTER shall have the "
+ "type TYPE(C_PTR)", &cptr->where);
+ return FAILURE;
+ }
+
+ if (scalar_check (cptr, 0) == FAILURE)
+ return FAILURE;
+
+ attr = gfc_expr_attr (fptr);
+
+ if (!attr.pointer)
+ {
+ gfc_error ("Argument FPTR at %L to C_F_POINTER must be a pointer",
+ &fptr->where);
+ return FAILURE;
+ }
+
+ if (fptr->ts.type == BT_CLASS)
+ {
+ gfc_error ("FPTR argument at %L to C_F_POINTER shall not be polymorphic",
+ &fptr->where);
+ return FAILURE;
+ }
+
+ if (gfc_is_coindexed (fptr))
+ {
+ gfc_error ("Argument FPTR at %L to C_F_POINTER shall not be "
+ "coindexed", &fptr->where);
+ return FAILURE;
+ }
+
+ if (fptr->rank == 0 && shape)
+ {
+ gfc_error ("Unexpected SHAPE argument at %L to C_F_POINTER with scalar "
+ "FPTR", &fptr->where);
+ return FAILURE;
+ }
+ else if (fptr->rank && !shape)
+ {
+ gfc_error ("Expected SHAPE argument to C_F_POINTER with array "
+ "FPTR at %L", &fptr->where);
+ return FAILURE;
+ }
+
+ if (shape && rank_check (shape, 2, 1) == FAILURE)
+ return FAILURE;
+
+ if (shape && type_check (shape, 2, BT_INTEGER) == FAILURE)
+ return FAILURE;
+
+ if (shape)
+ {
+ mpz_t size;
+
+ if (gfc_array_size (shape, &size) == SUCCESS
+ && mpz_cmp_ui (size, fptr->rank) != 0)
+ {
+ mpz_clear (size);
+ gfc_error ("SHAPE argument at %L to C_F_POINTER must have the same "
+ "size as the RANK of FPTR", &shape->where);
+ return FAILURE;
+ }
+ mpz_clear (size);
+ }
+
+ if (fptr->ts.type == BT_CLASS)
+ {
+ gfc_error ("Polymorphic FPTR at %L to C_F_POINTER", &fptr->where);
+ return FAILURE;
+ }
+
+ if (!is_c_interoperable (fptr, &msg, false) && fptr->rank)
+ return gfc_notify_std (GFC_STD_F2008_TS, "Noninteroperable array FPTR "
+ "at %L to C_F_POINTER: %s", &fptr->where, msg);
+
+ return SUCCESS;
+}
+
+
+gfc_try
+gfc_check_c_f_procpointer (gfc_expr *cptr, gfc_expr *fptr)
+{
+ symbol_attribute attr;
+
+ if (cptr->ts.type != BT_DERIVED
+ || cptr->ts.u.derived->from_intmod != INTMOD_ISO_C_BINDING
+ || cptr->ts.u.derived->intmod_sym_id != ISOCBINDING_FUNPTR)
+ {
+ gfc_error ("Argument CPTR at %L to C_F_PROCPOINTER shall have the "
+ "type TYPE(C_FUNPTR)", &cptr->where);
+ return FAILURE;
+ }
+
+ if (scalar_check (cptr, 0) == FAILURE)
+ return FAILURE;
+
+ attr = gfc_expr_attr (fptr);
+
+ if (!attr.proc_pointer)
+ {
+ gfc_error ("Argument FPTR at %L to C_F_PROCPOINTER shall be a procedure "
+ "pointer", &fptr->where);
+ return FAILURE;
+ }
+
+ if (gfc_is_coindexed (fptr))
+ {
+ gfc_error ("Argument FPTR at %L to C_F_PROCPOINTER shall not be "
+ "coindexed", &fptr->where);
+ return FAILURE;
+ }
+
+ if (!attr.is_bind_c)
+ return gfc_notify_std (GFC_STD_F2008_TS, "Noninteroperable procedure "
+ "pointer at %L to C_F_PROCPOINTER", &fptr->where);
+
+ return SUCCESS;
+}
+
+
+gfc_try
+gfc_check_c_funloc (gfc_expr *x)
+{
+ symbol_attribute attr;
+
+ if (gfc_is_coindexed (x))
+ {
+ gfc_error ("Argument X at %L to C_FUNLOC shall not be "
+ "coindexed", &x->where);
return FAILURE;
}
+
+ attr = gfc_expr_attr (x);
+
+ if (attr.function && !attr.proc_pointer && x->expr_type == EXPR_VARIABLE
+ && x->symtree->n.sym == x->symtree->n.sym->result)
+ {
+ gfc_namespace *ns = gfc_current_ns;
+
+ for (ns = gfc_current_ns; ns; ns = ns->parent)
+ if (x->symtree->n.sym == ns->proc_name)
+ {
+ gfc_error ("Function result '%s' at %L is invalid as X argument "
+ "to C_FUNLOC", x->symtree->n.sym->name, &x->where);
+ return FAILURE;
+ }
+ }
+
+ if (attr.flavor != FL_PROCEDURE)
+ {
+ gfc_error ("Argument X at %L to C_FUNLOC shall be a procedure "
+ "or a procedure pointer", &x->where);
+ return FAILURE;
+ }
+
+ if (!attr.is_bind_c)
+ return gfc_notify_std (GFC_STD_F2008_TS, "Noninteroperable procedure "
+ "at %L to C_FUNLOC", &x->where);
+ return SUCCESS;
+}
+
+
+gfc_try
+gfc_check_c_loc (gfc_expr *x)
+{
+ symbol_attribute attr;
+ const char *msg;
+
+ if (gfc_is_coindexed (x))
+ {
+ gfc_error ("Argument X at %L to C_LOC shall not be coindexed", &x->where);
+ return FAILURE;
+ }
+
+ if (x->ts.type == BT_CLASS)
+ {
+ gfc_error ("X argument at %L to C_LOC shall not be polymorphic",
+ &x->where);
+ return FAILURE;
+ }
+
+ attr = gfc_expr_attr (x);
+
+ if (!attr.pointer
+ && (x->expr_type != EXPR_VARIABLE || !attr.target
+ || attr.flavor == FL_PARAMETER))
+ {
+ gfc_error ("Argument X at %L to C_LOC shall have either "
+ "the POINTER or the TARGET attribute", &x->where);
+ return FAILURE;
+ }
+
+ if (x->ts.type == BT_CHARACTER
+ && gfc_var_strlen (x) == 0)
+ {
+ gfc_error ("Argument X at %L to C_LOC shall be not be a zero-sized "
+ "string", &x->where);
+ return FAILURE;
+ }
+
+ if (!is_c_interoperable (x, &msg, true))
+ {
+ if (x->ts.type == BT_CLASS)
+ {
+ gfc_error ("Argument at %L to C_LOC shall not be polymorphic",
+ &x->where);
+ return FAILURE;
+ }
+
+ if (x->rank
+ && gfc_notify_std (GFC_STD_F2008_TS, "Noninteroperable array at %L as"
+ " argument to C_LOC: %s", &x->where, msg) == FAILURE)
+ return FAILURE;
+ }
+
return SUCCESS;
}