aboutsummaryrefslogtreecommitdiff
path: root/gcc/fortran
diff options
context:
space:
mode:
authorFrancois-Xavier Coudert <fxcoudert@gcc.gnu.org>2007-08-06 20:47:17 +0000
committerFrançois-Xavier Coudert <fxcoudert@gcc.gnu.org>2007-08-06 20:47:17 +0000
commit2263c775581fc3bc0a4e26794dd3f301056e3a81 (patch)
tree2abbc1521f7910f2a1dce1f5f9199ff847083230 /gcc/fortran
parentd3ef67eaf39f1af64a1a1331c63ad60dd8c217cd (diff)
downloadgcc-2263c775581fc3bc0a4e26794dd3f301056e3a81.zip
gcc-2263c775581fc3bc0a4e26794dd3f301056e3a81.tar.gz
gcc-2263c775581fc3bc0a4e26794dd3f301056e3a81.tar.bz2
re PR fortran/29828 ([F2003] MIN and MAX with character variables)
PR fortran/29828 * trans.h (gfor_fndecl_string_minmax): New prototype. * trans-decl.c (gfor_fndecl_string_minmax): New variable. (gfc_build_intrinsic_function_decls): Create gfor_fndecl_string_minmax. * check.c (gfc_check_min_max): Allow for character arguments. * trans-intrinsic.c (gfc_conv_intrinsic_minmax_char): New function. (gfc_conv_intrinsic_function): Add special case for MIN and MAX intrinsics with character arguments. * simplify.c (simplify_min_max): Add simplification for character arguments. * intrinsics/string_intrinsics.c (string_minmax): New function and prototype. * gfortran.map (GFORTRAN_1.0): Add _gfortran_string_minmax * gfortran.dg/minmax_char_1.f90: New test. * gfortran.dg/minmax_char_2.f90: New test. * gfortran.dg/min_max_optional_4.f90: New test. From-SVN: r127252
Diffstat (limited to 'gcc/fortran')
-rw-r--r--gcc/fortran/ChangeLog13
-rw-r--r--gcc/fortran/check.c13
-rw-r--r--gcc/fortran/simplify.c32
-rw-r--r--gcc/fortran/trans-decl.c8
-rw-r--r--gcc/fortran/trans-intrinsic.c49
-rw-r--r--gcc/fortran/trans.h1
6 files changed, 109 insertions, 7 deletions
diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog
index cc3b89b..2bd347e 100644
--- a/gcc/fortran/ChangeLog
+++ b/gcc/fortran/ChangeLog
@@ -1,5 +1,18 @@
2007-08-06 Francois-Xavier Coudert <fxcoudert@gcc.gnu.org>
+ PR fortran/29828
+ * trans.h (gfor_fndecl_string_minmax): New prototype.
+ * trans-decl.c (gfor_fndecl_string_minmax): New variable.
+ (gfc_build_intrinsic_function_decls): Create gfor_fndecl_string_minmax.
+ * check.c (gfc_check_min_max): Allow for character arguments.
+ * trans-intrinsic.c (gfc_conv_intrinsic_minmax_char): New function.
+ (gfc_conv_intrinsic_function): Add special case for MIN and MAX
+ intrinsics with character arguments.
+ * simplify.c (simplify_min_max): Add simplification for character
+ arguments.
+
+2007-08-06 Francois-Xavier Coudert <fxcoudert@gcc.gnu.org>
+
PR fortran/31612
* invoke.texi: Adjust documentation for option -fsyntax-only.
diff --git a/gcc/fortran/check.c b/gcc/fortran/check.c
index e792773..ba72aaa 100644
--- a/gcc/fortran/check.c
+++ b/gcc/fortran/check.c
@@ -1512,10 +1512,17 @@ gfc_check_min_max (gfc_actual_arglist *arg)
x = arg->expr;
- if (x->ts.type != BT_INTEGER && x->ts.type != BT_REAL)
+ if (x->ts.type == BT_CHARACTER)
+ {
+ if (gfc_notify_std (GFC_STD_F2003, "Fortran 2003: '%s' intrinsic "
+ "with CHARACTER argument at %L",
+ gfc_current_intrinsic, &x->where) == FAILURE)
+ return FAILURE;
+ }
+ else if (x->ts.type != BT_INTEGER && x->ts.type != BT_REAL)
{
- gfc_error ("'a1' argument of '%s' intrinsic at %L must be INTEGER "
- "or REAL", gfc_current_intrinsic, &x->where);
+ gfc_error ("'a1' argument of '%s' intrinsic at %L must be INTEGER, "
+ "REAL or CHARACTER", gfc_current_intrinsic, &x->where);
return FAILURE;
}
diff --git a/gcc/fortran/simplify.c b/gcc/fortran/simplify.c
index 7919dae..88a146b 100644
--- a/gcc/fortran/simplify.c
+++ b/gcc/fortran/simplify.c
@@ -2361,7 +2361,6 @@ simplify_min_max (gfc_expr *expr, int sign)
if (mpz_cmp (arg->expr->value.integer,
extremum->expr->value.integer) * sign > 0)
mpz_set (extremum->expr->value.integer, arg->expr->value.integer);
-
break;
case BT_REAL:
@@ -2369,11 +2368,40 @@ simplify_min_max (gfc_expr *expr, int sign)
* sign > 0)
mpfr_set (extremum->expr->value.real, arg->expr->value.real,
GFC_RND_MODE);
+ break;
+
+ case BT_CHARACTER:
+#define LENGTH(x) ((x)->expr->value.character.length)
+#define STRING(x) ((x)->expr->value.character.string)
+ if (LENGTH(extremum) < LENGTH(arg))
+ {
+ char * tmp = STRING(extremum);
+
+ STRING(extremum) = gfc_getmem (LENGTH(arg) + 1);
+ memcpy (STRING(extremum), tmp, LENGTH(extremum));
+ memset (&STRING(extremum)[LENGTH(extremum)], ' ',
+ LENGTH(arg) - LENGTH(extremum));
+ STRING(extremum)[LENGTH(arg)] = '\0'; /* For debugger */
+ LENGTH(extremum) = LENGTH(arg);
+ gfc_free (tmp);
+ }
+ if (gfc_compare_string (arg->expr, extremum->expr) * sign > 0)
+ {
+ gfc_free (STRING(extremum));
+ STRING(extremum) = gfc_getmem (LENGTH(extremum) + 1);
+ memcpy (STRING(extremum), STRING(arg), LENGTH(arg));
+ memset (&STRING(extremum)[LENGTH(arg)], ' ',
+ LENGTH(extremum) - LENGTH(arg));
+ STRING(extremum)[LENGTH(extremum)] = '\0'; /* For debugger */
+ }
+#undef LENGTH
+#undef STRING
break;
+
default:
- gfc_internal_error ("gfc_simplify_max(): Bad type in arglist");
+ gfc_internal_error ("simplify_min_max(): Bad type in arglist");
}
/* Delete the extra constant argument. */
diff --git a/gcc/fortran/trans-decl.c b/gcc/fortran/trans-decl.c
index b74b466..c9a195f 100644
--- a/gcc/fortran/trans-decl.c
+++ b/gcc/fortran/trans-decl.c
@@ -125,6 +125,7 @@ tree gfor_fndecl_string_index;
tree gfor_fndecl_string_scan;
tree gfor_fndecl_string_verify;
tree gfor_fndecl_string_trim;
+tree gfor_fndecl_string_minmax;
tree gfor_fndecl_adjustl;
tree gfor_fndecl_adjustr;
@@ -2047,6 +2048,13 @@ gfc_build_intrinsic_function_decls (void)
gfc_charlen_type_node,
pchar_type_node);
+ gfor_fndecl_string_minmax =
+ gfc_build_library_function_decl (get_identifier (PREFIX("string_minmax")),
+ void_type_node, -4,
+ build_pointer_type (gfc_charlen_type_node),
+ ppvoid_type_node, integer_type_node,
+ integer_type_node);
+
gfor_fndecl_ttynam =
gfc_build_library_function_decl (get_identifier (PREFIX("ttynam")),
void_type_node,
diff --git a/gcc/fortran/trans-intrinsic.c b/gcc/fortran/trans-intrinsic.c
index dcdc3c7..ce6b585 100644
--- a/gcc/fortran/trans-intrinsic.c
+++ b/gcc/fortran/trans-intrinsic.c
@@ -1561,6 +1561,45 @@ gfc_conv_intrinsic_minmax (gfc_se * se, gfc_expr * expr, int op)
}
+/* Generate library calls for MIN and MAX intrinsics for character
+ variables. */
+static void
+gfc_conv_intrinsic_minmax_char (gfc_se * se, gfc_expr * expr, int op)
+{
+ tree *args;
+ tree var, len, fndecl, tmp, cond;
+ unsigned int nargs;
+
+ nargs = gfc_intrinsic_argument_list_length (expr);
+ args = alloca (sizeof (tree) * (nargs + 4));
+ gfc_conv_intrinsic_function_args (se, expr, &args[4], nargs);
+
+ /* Create the result variables. */
+ len = gfc_create_var (gfc_charlen_type_node, "len");
+ args[0] = build_fold_addr_expr (len);
+ var = gfc_create_var (build_pointer_type (gfc_character1_type_node), "pstr");
+ args[1] = gfc_build_addr_expr (ppvoid_type_node, var);
+ args[2] = build_int_cst (NULL_TREE, op);
+ args[3] = build_int_cst (NULL_TREE, nargs / 2);
+
+ /* Make the function call. */
+ fndecl = build_addr (gfor_fndecl_string_minmax, current_function_decl);
+ tmp = build_call_array (TREE_TYPE (TREE_TYPE (gfor_fndecl_string_minmax)),
+ fndecl, nargs + 4, args);
+ gfc_add_expr_to_block (&se->pre, tmp);
+
+ /* Free the temporary afterwards, if necessary. */
+ cond = build2 (GT_EXPR, boolean_type_node, len,
+ build_int_cst (TREE_TYPE (len), 0));
+ tmp = gfc_call_free (var);
+ tmp = build3_v (COND_EXPR, cond, tmp, build_empty_stmt ());
+ gfc_add_expr_to_block (&se->post, tmp);
+
+ se->expr = var;
+ se->string_length = len;
+}
+
+
/* Create a symbol node for this intrinsic. The symbol from the frontend
has the generic name. */
@@ -4058,7 +4097,10 @@ gfc_conv_intrinsic_function (gfc_se * se, gfc_expr * expr)
break;
case GFC_ISYM_MAX:
- gfc_conv_intrinsic_minmax (se, expr, GT_EXPR);
+ if (expr->ts.type == BT_CHARACTER)
+ gfc_conv_intrinsic_minmax_char (se, expr, 1);
+ else
+ gfc_conv_intrinsic_minmax (se, expr, GT_EXPR);
break;
case GFC_ISYM_MAXLOC:
@@ -4074,7 +4116,10 @@ gfc_conv_intrinsic_function (gfc_se * se, gfc_expr * expr)
break;
case GFC_ISYM_MIN:
- gfc_conv_intrinsic_minmax (se, expr, LT_EXPR);
+ if (expr->ts.type == BT_CHARACTER)
+ gfc_conv_intrinsic_minmax_char (se, expr, -1);
+ else
+ gfc_conv_intrinsic_minmax (se, expr, LT_EXPR);
break;
case GFC_ISYM_MINLOC:
diff --git a/gcc/fortran/trans.h b/gcc/fortran/trans.h
index 5ad3ca6..8226187 100644
--- a/gcc/fortran/trans.h
+++ b/gcc/fortran/trans.h
@@ -540,6 +540,7 @@ extern GTY(()) tree gfor_fndecl_string_index;
extern GTY(()) tree gfor_fndecl_string_scan;
extern GTY(()) tree gfor_fndecl_string_verify;
extern GTY(()) tree gfor_fndecl_string_trim;
+extern GTY(()) tree gfor_fndecl_string_minmax;
extern GTY(()) tree gfor_fndecl_adjustl;
extern GTY(()) tree gfor_fndecl_adjustr;