aboutsummaryrefslogtreecommitdiff
path: root/gcc/fortran/intrinsic.c
diff options
context:
space:
mode:
authorFrancois-Xavier Coudert <fxcoudert@gcc.gnu.org>2008-05-18 22:45:05 +0000
committerFrançois-Xavier Coudert <fxcoudert@gcc.gnu.org>2008-05-18 22:45:05 +0000
commitd393bbd73754dfe54fac24d350c789316f17428f (patch)
tree8a592f8dffb59a80d1cbd5fbc829a670104539c2 /gcc/fortran/intrinsic.c
parent45a7844faf66271c1b2491d2931aa761c80c2f90 (diff)
downloadgcc-d393bbd73754dfe54fac24d350c789316f17428f.zip
gcc-d393bbd73754dfe54fac24d350c789316f17428f.tar.gz
gcc-d393bbd73754dfe54fac24d350c789316f17428f.tar.bz2
intrinsic.c (char_conversions, ncharconv): New static variables.
* intrinsic.c (char_conversions, ncharconv): New static variables. (find_char_conv): New function. (add_functions): Add simplification functions for ADJUSTL and ADJUSTR. Don't check the kind of their argument. Add checking for LGE, LLE, LGT and LLT. (add_subroutines): Fix argument type for SLEEP. Fix argument name for SYSTEM. (add_char_conversions): New function. (gfc_intrinsic_init_1): Call add_char_conversions. (gfc_intrinsic_done_1): Free char_conversions. (check_arglist): Use kind == 0 as a signal that we don't want the kind value to be checked. (do_simplify): Also simplify character functions. (gfc_convert_chartype): New function * trans-array.c (gfc_trans_array_ctor_element): Don't force the use of default character type. (gfc_trans_array_constructor_value): Likewise. (get_array_ctor_var_strlen): Use integer kind to build an integer instead of a character kind! (gfc_build_constant_array_constructor): Don't force the use of default character type. (gfc_conv_loop_setup): Likewise. * trans-expr.c (gfc_conv_string_tmp): Don't force the use of default character type. Allocate enough memory for wide strings. (gfc_conv_concat_op): Make sure operand kind are the same. (string_to_single_character): Remove gfc_ prefix. Reindent. Don't force the use of default character type. (gfc_conv_scalar_char_value): Likewise. (gfc_build_compare_string): Call string_to_single_character. (fill_with_spaces): New function (gfc_trans_string_copy): Add kind arguments. Use them to deal with wide character kinds. (gfc_conv_statement_function): Whitespace fix. Call gfc_trans_string_copy with new kind arguments. (gfc_conv_substring_expr): Call gfc_build_wide_string_const instead of using gfc_widechar_to_char. (gfc_conv_string_parameter): Don't force the use of default character type. (gfc_trans_scalar_assign): Pass kind args to gfc_trans_string_copy. * intrinsic.h (gfc_check_lge_lgt_lle_llt, gfc_convert_char_constant, gfc_resolve_adjustl, gfc_resolve_adjustr): New prototypes. * decl.c (gfc_set_constant_character_len): Don't assert the existence of a single character kind. * trans-array.h (gfc_trans_string_copy): New prototype. * gfortran.h (gfc_check_character_range, gfc_convert_chartype): New prototypes. * error.c (print_wide_char_into_buffer): New function lifting code from gfc_print_wide_char. Fix order to output '\x??' instead of 'x\??'. (gfc_print_wide_char): Call print_wide_char_into_buffer. (show_locus): Call print_wide_char_into_buffer with buffer local to this function. * trans-const.c (gfc_build_wide_string_const): New function. (gfc_conv_string_init): Deal with wide characters strings constructors. (gfc_conv_constant_to_tree): Call gfc_build_wide_string_const. * trans-stmt.c (gfc_trans_label_assign): Likewise. (gfc_trans_character_select): Deal with wide strings. * expr.c (gfc_check_assign): Allow conversion between character kinds on assignment. * trans-const.h (gfc_build_wide_string_const): New prototype. * trans-types.c (gfc_get_character_type_len_for_eltype, gfc_get_character_type_len): Create too variants of the old gfc_get_character_type_len, one getting kind argument and the other one directly taking a type tree. * trans.h (gfor_fndecl_select_string_char4, gfor_fndecl_convert_char1_to_char4, gfor_fndecl_convert_char4_to_char1): New prototypes. * trans-types.h (gfc_get_character_type_len_for_eltype): New prototype. * resolve.c (resolve_operator): Exit early when kind mismatches are detected, because that makes us issue an error message later. (validate_case_label_expr): Fix wording of error message. * iresolve.c (gfc_resolve_adjustl, gfc_resolve_adjustr): New functions. (gfc_resolve_pack): Call _char4 variants of library function when dealing with wide characters. (gfc_resolve_reshape): Likewise. (gfc_resolve_spread): Likewise. (gfc_resolve_transpose): Likewise. (gfc_resolve_unpack): Likewise. * target-memory.c (size_character): Take character kind bit size correctly into account (not that it changes anything for now, but it's more generic). (gfc_encode_character): Added gfc_ prefix. Encoding each character of a string by calling native_encode_expr for the corresponding unsigned integer. (gfc_target_encode_expr): Add gfc_ prefix to encode_character. * trans-decl.c (gfc_build_intrinsic_function_decls): Build gfor_fndecl_select_string_char4, gfor_fndecl_convert_char1_to_char4 and gfor_fndecl_convert_char4_to_char1. * target-memory.h (gfc_encode_character): New prototype. * arith.c (gfc_check_character_range): New function. (eval_intrinsic): Allow non-default character kinds. * check.c (gfc_check_access_func): Only allow default character kind arguments. (gfc_check_chdir): Likewise. (gfc_check_chdir_sub): Likewise. (gfc_check_chmod): Likewise. (gfc_check_chmod_sub): Likewise. (gfc_check_lge_lgt_lle_llt): New function. (gfc_check_link): Likewise. (gfc_check_link_sub): Likewise. (gfc_check_symlnk): Likewise. (gfc_check_symlnk_sub): Likewise. (gfc_check_rename): Likewise. (gfc_check_rename_sub): Likewise. (gfc_check_fgetputc_sub): Likewise. (gfc_check_fgetput_sub): Likewise. (gfc_check_stat): Likewise. (gfc_check_stat_sub): Likewise. (gfc_check_date_and_time): Likewise. (gfc_check_ctime_sub): Likewise. (gfc_check_fdate_sub): Likewise. (gfc_check_gerror): Likewise. (gfc_check_getcwd_sub): Likewise. (gfc_check_getarg): Likewise. (gfc_check_getlog): Likewise. (gfc_check_hostnm): Likewise. (gfc_check_hostnm_sub): Likewise. (gfc_check_ttynam_sub): Likewise. (gfc_check_perror): Likewise. (gfc_check_unlink): Likewise. (gfc_check_unlink_sub): Likewise. (gfc_check_system_sub): Likewise. * primary.c (got_delim): Perform correct character range checking for all kinds. * trans-intrinsic.c (gfc_conv_intrinsic_conversion): Generate calls to library functions convert_char4_to_char1 and convert_char1_to_char4 for character conversions. (gfc_conv_intrinsic_char): Allow all character kings. (gfc_conv_intrinsic_strcmp): Fix whitespace. (gfc_conv_intrinsic_repeat): Take care of all character kinds. * intrinsic.texi: For all GNU intrinsics accepting character arguments, mention that they're restricted to the default kind. * simplify.c (simplify_achar_char): New function. (gfc_simplify_achar, gfc_simplify_char): Call simplify_achar_char. gfc_simplify_ichar): Don't error out for wide characters. (gfc_convert_char_constant): New function. * gfortran.dg/achar_3.f90: Adjust error messages. * gfortran.dg/achar_5.f90: New test. * gfortran.dg/achar_6.F90: New test. * gfortran.dg/widechar_1.f90: New test. * gfortran.dg/widechar_2.f90: New test. * gfortran.dg/widechar_3.f90: New test. * gfortran.dg/widechar_4.f90: New test. * gfortran.dg/widechar_intrinsics_1.f90: New test. * gfortran.dg/widechar_intrinsics_2.f90: New test. * gfortran.dg/widechar_intrinsics_3.f90: New test. * gfortran.dg/widechar_intrinsics_4.f90: New test. * gfortran.dg/widechar_intrinsics_5.f90: New test. * gfortran.dg/widechar_select_1.f90: New test. * gfortran.dg/widechar_select_2.f90: New test. From-SVN: r135515
Diffstat (limited to 'gcc/fortran/intrinsic.c')
-rw-r--r--gcc/fortran/intrinsic.c179
1 files changed, 159 insertions, 20 deletions
diff --git a/gcc/fortran/intrinsic.c b/gcc/fortran/intrinsic.c
index 6def478..e902f69 100644
--- a/gcc/fortran/intrinsic.c
+++ b/gcc/fortran/intrinsic.c
@@ -39,9 +39,10 @@ const char *gfc_current_intrinsic_arg[MAX_INTRINSIC_ARGS];
locus *gfc_current_intrinsic_where;
static gfc_intrinsic_sym *functions, *subroutines, *conversion, *next_sym;
+static gfc_intrinsic_sym *char_conversions;
static gfc_intrinsic_arg *next_arg;
-static int nfunc, nsub, nargs, nconv;
+static int nfunc, nsub, nargs, nconv, ncharconv;
static enum
{ SZ_NOTHING = 0, SZ_SUBS, SZ_FUNCS, SZ_CONVS }
@@ -148,6 +149,28 @@ find_conv (gfc_typespec *from, gfc_typespec *to)
}
+/* Given a pair of CHARACTER typespecs, find the gfc_intrinsic_sym node
+ that corresponds to the conversion. Returns NULL if the conversion
+ isn't found. */
+
+static gfc_intrinsic_sym *
+find_char_conv (gfc_typespec *from, gfc_typespec *to)
+{
+ gfc_intrinsic_sym *sym;
+ const char *target;
+ int i;
+
+ target = conv_name (from, to);
+ sym = char_conversions;
+
+ for (i = 0; i < ncharconv; i++, sym++)
+ if (target == sym->name)
+ return sym;
+
+ return NULL;
+}
+
+
/* Interface to the check functions. We break apart an argument list
and call the proper check function rather than forcing each
function to manipulate the argument list. */
@@ -974,15 +997,15 @@ add_functions (void)
make_generic ("acosh", GFC_ISYM_ACOSH, GFC_STD_F2008);
- add_sym_1 ("adjustl", GFC_ISYM_ADJUSTL, CLASS_ELEMENTAL, ACTUAL_NO, BT_CHARACTER, dc, GFC_STD_F95,
- NULL, gfc_simplify_adjustl, NULL,
- stg, BT_CHARACTER, dc, REQUIRED);
+ add_sym_1 ("adjustl", GFC_ISYM_ADJUSTL, CLASS_ELEMENTAL, ACTUAL_NO,
+ BT_CHARACTER, dc, GFC_STD_F95, NULL, gfc_simplify_adjustl,
+ gfc_resolve_adjustl, stg, BT_CHARACTER, 0, REQUIRED);
make_generic ("adjustl", GFC_ISYM_ADJUSTL, GFC_STD_F95);
- add_sym_1 ("adjustr", GFC_ISYM_ADJUSTR, CLASS_ELEMENTAL, ACTUAL_NO, BT_CHARACTER, dc, GFC_STD_F95,
- NULL, gfc_simplify_adjustr, NULL,
- stg, BT_CHARACTER, dc, REQUIRED);
+ add_sym_1 ("adjustr", GFC_ISYM_ADJUSTR, CLASS_ELEMENTAL, ACTUAL_NO,
+ BT_CHARACTER, dc, GFC_STD_F95, NULL, gfc_simplify_adjustr,
+ gfc_resolve_adjustr, stg, BT_CHARACTER, 0, REQUIRED);
make_generic ("adjustr", GFC_ISYM_ADJUSTR, GFC_STD_F95);
@@ -1760,26 +1783,26 @@ add_functions (void)
make_generic ("log_gamma", GFC_ISYM_LGAMMA, GFC_STD_F2008);
- add_sym_2 ("lge", GFC_ISYM_LGE, CLASS_ELEMENTAL, ACTUAL_NO, BT_LOGICAL, dl, GFC_STD_F77,
- NULL, gfc_simplify_lge, NULL,
+ add_sym_2 ("lge", GFC_ISYM_LGE, CLASS_ELEMENTAL, ACTUAL_NO, BT_LOGICAL, dl,
+ GFC_STD_F77, gfc_check_lge_lgt_lle_llt, gfc_simplify_lge, NULL,
sta, BT_CHARACTER, dc, REQUIRED, stb, BT_CHARACTER, dc, REQUIRED);
make_generic ("lge", GFC_ISYM_LGE, GFC_STD_F77);
- add_sym_2 ("lgt", GFC_ISYM_LGT, CLASS_ELEMENTAL, ACTUAL_NO, BT_LOGICAL, dl, GFC_STD_F77,
- NULL, gfc_simplify_lgt, NULL,
+ add_sym_2 ("lgt", GFC_ISYM_LGT, CLASS_ELEMENTAL, ACTUAL_NO, BT_LOGICAL, dl,
+ GFC_STD_F77, gfc_check_lge_lgt_lle_llt, gfc_simplify_lgt, NULL,
sta, BT_CHARACTER, dc, REQUIRED, stb, BT_CHARACTER, dc, REQUIRED);
make_generic ("lgt", GFC_ISYM_LGT, GFC_STD_F77);
- add_sym_2 ("lle",GFC_ISYM_LLE, CLASS_ELEMENTAL, ACTUAL_NO, BT_LOGICAL, dl, GFC_STD_F77,
- NULL, gfc_simplify_lle, NULL,
+ add_sym_2 ("lle",GFC_ISYM_LLE, CLASS_ELEMENTAL, ACTUAL_NO, BT_LOGICAL, dl,
+ GFC_STD_F77, gfc_check_lge_lgt_lle_llt, gfc_simplify_lle, NULL,
sta, BT_CHARACTER, dc, REQUIRED, stb, BT_CHARACTER, dc, REQUIRED);
make_generic ("lle", GFC_ISYM_LLE, GFC_STD_F77);
- add_sym_2 ("llt", GFC_ISYM_LLT, CLASS_ELEMENTAL, ACTUAL_NO, BT_LOGICAL, dl, GFC_STD_F77,
- NULL, gfc_simplify_llt, NULL,
+ add_sym_2 ("llt", GFC_ISYM_LLT, CLASS_ELEMENTAL, ACTUAL_NO, BT_LOGICAL, dl,
+ GFC_STD_F77, gfc_check_lge_lgt_lle_llt, gfc_simplify_llt, NULL,
sta, BT_CHARACTER, dc, REQUIRED, stb, BT_CHARACTER, dc, REQUIRED);
make_generic ("llt", GFC_ISYM_LLT, GFC_STD_F77);
@@ -2625,7 +2648,7 @@ add_subroutines (void)
add_sym_1s ("sleep", GFC_ISYM_SLEEP, NO_CLASS, BT_UNKNOWN, 0, GFC_STD_GNU,
gfc_check_sleep_sub, NULL, gfc_resolve_sleep_sub,
- val, BT_CHARACTER, dc, REQUIRED);
+ val, BT_INTEGER, di, REQUIRED);
add_sym_3s ("fstat", GFC_ISYM_FSTAT, NO_CLASS, BT_UNKNOWN, 0, GFC_STD_GNU,
gfc_check_fstat_sub, NULL, gfc_resolve_fstat_sub,
@@ -2654,7 +2677,7 @@ add_subroutines (void)
add_sym_2s ("system", GFC_ISYM_SYSTEM, NO_CLASS, BT_UNKNOWN, 0, GFC_STD_GNU,
NULL, NULL, gfc_resolve_system_sub,
- c, BT_CHARACTER, dc, REQUIRED, st, BT_INTEGER, di, OPTIONAL);
+ com, BT_CHARACTER, dc, REQUIRED, st, BT_INTEGER, di, OPTIONAL);
add_sym_3s ("system_clock", GFC_ISYM_SYSTEM_CLOCK, NO_CLASS, BT_UNKNOWN, 0, GFC_STD_F95,
gfc_check_system_clock, NULL, gfc_resolve_system_clock,
@@ -2817,6 +2840,52 @@ add_conversions (void)
}
+static void
+add_char_conversions (void)
+{
+ int n, i, j;
+
+ /* Count possible conversions. */
+ for (i = 0; gfc_character_kinds[i].kind != 0; i++)
+ for (j = 0; gfc_character_kinds[j].kind != 0; j++)
+ if (i != j)
+ ncharconv++;
+
+ /* Allocate memory. */
+ char_conversions = gfc_getmem (sizeof (gfc_intrinsic_sym) * ncharconv);
+
+ /* Add the conversions themselves. */
+ n = 0;
+ for (i = 0; gfc_character_kinds[i].kind != 0; i++)
+ for (j = 0; gfc_character_kinds[j].kind != 0; j++)
+ {
+ gfc_typespec from, to;
+
+ if (i == j)
+ continue;
+
+ gfc_clear_ts (&from);
+ from.type = BT_CHARACTER;
+ from.kind = gfc_character_kinds[i].kind;
+
+ gfc_clear_ts (&to);
+ to.type = BT_CHARACTER;
+ to.kind = gfc_character_kinds[j].kind;
+
+ char_conversions[n].name = conv_name (&from, &to);
+ char_conversions[n].lib_name = char_conversions[n].name;
+ char_conversions[n].simplify.cc = gfc_convert_char_constant;
+ char_conversions[n].standard = GFC_STD_F2003;
+ char_conversions[n].elemental = 1;
+ char_conversions[n].conversion = 0;
+ char_conversions[n].ts = to;
+ char_conversions[n].id = GFC_ISYM_CONVERSION;
+
+ n++;
+ }
+}
+
+
/* Initialize the table of intrinsics. */
void
gfc_intrinsic_init_1 (void)
@@ -2852,6 +2921,9 @@ gfc_intrinsic_init_1 (void)
add_subroutines ();
add_conversions ();
+ /* Character conversion intrinsics need to be treated separately. */
+ add_char_conversions ();
+
/* Set the pure flag. All intrinsic functions are pure, and
intrinsic subroutines are pure if they are elemental. */
@@ -2868,6 +2940,7 @@ gfc_intrinsic_done_1 (void)
{
gfc_free (functions);
gfc_free (conversion);
+ gfc_free (char_conversions);
gfc_free_namespace (gfc_intrinsic_namespace);
}
@@ -3052,10 +3125,18 @@ check_arglist (gfc_actual_arglist **ap, gfc_intrinsic_sym *sym,
i = 0;
for (; formal; formal = formal->next, actual = actual->next, i++)
{
+ gfc_typespec ts;
+
if (actual->expr == NULL)
continue;
- if (!gfc_compare_types (&formal->ts, &actual->expr->ts))
+ ts = formal->ts;
+
+ /* A kind of 0 means we don't check for kind. */
+ if (ts.kind == 0)
+ ts.kind = actual->expr->ts.kind;
+
+ if (!gfc_compare_types (&ts, &actual->expr->ts))
{
if (error_flag)
gfc_error ("Type of argument '%s' in call to '%s' at %L should "
@@ -3199,9 +3280,10 @@ do_simplify (gfc_intrinsic_sym *specific, gfc_expr *e)
a1 = arg->expr;
arg = arg->next;
- if (specific->simplify.cc == gfc_convert_constant)
+ if (specific->simplify.cc == gfc_convert_constant
+ || specific->simplify.cc == gfc_convert_char_constant)
{
- result = gfc_convert_constant (a1, specific->ts.type, specific->ts.kind);
+ result = specific->simplify.cc (a1, specific->ts.type, specific->ts.kind);
goto finish;
}
@@ -3687,3 +3769,60 @@ bad:
&expr->where);
/* Not reached */
}
+
+
+try
+gfc_convert_chartype (gfc_expr *expr, gfc_typespec *ts)
+{
+ gfc_intrinsic_sym *sym;
+ gfc_typespec from_ts;
+ locus old_where;
+ gfc_expr *new;
+ int rank;
+ mpz_t *shape;
+
+ gcc_assert (expr->ts.type == BT_CHARACTER && ts->type == BT_CHARACTER);
+ from_ts = expr->ts; /* expr->ts gets clobbered */
+
+ sym = find_char_conv (&expr->ts, ts);
+ gcc_assert (sym);
+
+ /* Insert a pre-resolved function call to the right function. */
+ old_where = expr->where;
+ rank = expr->rank;
+ shape = expr->shape;
+
+ new = gfc_get_expr ();
+ *new = *expr;
+
+ new = gfc_build_conversion (new);
+ new->value.function.name = sym->lib_name;
+ new->value.function.isym = sym;
+ new->where = old_where;
+ new->rank = rank;
+ new->shape = gfc_copy_shape (shape, rank);
+
+ gfc_get_ha_sym_tree (sym->name, &new->symtree);
+ new->symtree->n.sym->ts = *ts;
+ new->symtree->n.sym->attr.flavor = FL_PROCEDURE;
+ new->symtree->n.sym->attr.function = 1;
+ new->symtree->n.sym->attr.elemental = 1;
+ new->symtree->n.sym->attr.pure = 1;
+ new->symtree->n.sym->attr.referenced = 1;
+ gfc_intrinsic_symbol(new->symtree->n.sym);
+ gfc_commit_symbol (new->symtree->n.sym);
+
+ *expr = *new;
+
+ gfc_free (new);
+ expr->ts = *ts;
+
+ if (gfc_is_constant_expr (expr->value.function.actual->expr)
+ && do_simplify (sym, expr) == FAILURE)
+ {
+ /* Error already generated in do_simplify() */
+ return FAILURE;
+ }
+
+ return SUCCESS;
+}