aboutsummaryrefslogtreecommitdiff
path: root/gcc/fortran/check.c
diff options
context:
space:
mode:
authorThomas Koenig <tkoenig@gcc.gnu.org>2011-08-05 21:51:59 +0000
committerThomas Koenig <tkoenig@gcc.gnu.org>2011-08-05 21:51:59 +0000
commit86dbed7d1bbbee6c0a5304091e089c48a20c0142 (patch)
tree355e022c7c1cbec05a02dc85dd3da5320674d598 /gcc/fortran/check.c
parent7cfea2ef26a3aab320c90d71c35c69a8c78404d7 (diff)
downloadgcc-86dbed7d1bbbee6c0a5304091e089c48a20c0142.zip
gcc-86dbed7d1bbbee6c0a5304091e089c48a20c0142.tar.gz
gcc-86dbed7d1bbbee6c0a5304091e089c48a20c0142.tar.bz2
re PR fortran/37211 (TRANSFER to characters: Size checking)
2011-08-05 Thomas Koenig <tkoenig@gcc.gnu.org> PR fortran/37221 * gfortran.h (gfc_calculate_transfer_sizes): Add prototype. * target-memory.h (gfc_target_interpret_expr): Add boolean argument wether to convert wide characters. * target-memory.c (gfc_target_expr_size): Also return length of characters for non-constant expressions if these can be determined from the cl. (interpret_array): Add argument for gfc_target_interpret_expr. (gfc_interpret_derived): Likewise. (gfc_target_interpret_expr): Likewise. * check.c: Include target-memory.h. (gfc_calculate_transfer_sizes): New function. (gfc_check_transfer): When -Wsurprising is in force, calculate sizes and warn if result is larger than size (check moved from gfc_simplify_transfer). * simplify.c (gfc_simplify_transfer): Use gfc_calculate_transfer_sizes. Remove warning. 2011-08-05 Thomas Koenig <tkoenig@gcc.gnu.org> PR fortran/37221 * gfortran.dg/transfer_check_2.f90: New test case. From-SVN: r177486
Diffstat (limited to 'gcc/fortran/check.c')
-rw-r--r--gcc/fortran/check.c77
1 files changed, 75 insertions, 2 deletions
diff --git a/gcc/fortran/check.c b/gcc/fortran/check.c
index a95865b..3d4f4c8 100644
--- a/gcc/fortran/check.c
+++ b/gcc/fortran/check.c
@@ -32,6 +32,7 @@ along with GCC; see the file COPYING3. If not see
#include "gfortran.h"
#include "intrinsic.h"
#include "constructor.h"
+#include "target-memory.h"
/* Make sure an expression is a scalar. */
@@ -3864,11 +3865,68 @@ gfc_check_this_image (gfc_expr *coarray, gfc_expr *dim)
return SUCCESS;
}
+/* Calculate the sizes for transfer, used by gfc_check_transfer and also
+ by gfc_simplify_transfer. Return FAILURE if we cannot do so. */
gfc_try
-gfc_check_transfer (gfc_expr *source ATTRIBUTE_UNUSED,
- gfc_expr *mold ATTRIBUTE_UNUSED, gfc_expr *size)
+gfc_calculate_transfer_sizes (gfc_expr *source, gfc_expr *mold, gfc_expr *size,
+ size_t *source_size, size_t *result_size,
+ size_t *result_length_p)
+
+{
+ size_t result_elt_size;
+ mpz_t tmp;
+ gfc_expr *mold_element;
+
+ if (source->expr_type == EXPR_FUNCTION)
+ return FAILURE;
+
+ /* Calculate the size of the source. */
+ if (source->expr_type == EXPR_ARRAY
+ && gfc_array_size (source, &tmp) == FAILURE)
+ return FAILURE;
+
+ *source_size = gfc_target_expr_size (source);
+
+ mold_element = mold->expr_type == EXPR_ARRAY
+ ? gfc_constructor_first (mold->value.constructor)->expr
+ : mold;
+
+ /* Determine the size of the element. */
+ result_elt_size = gfc_target_expr_size (mold_element);
+ if (result_elt_size == 0)
+ return FAILURE;
+
+ if (mold->expr_type == EXPR_ARRAY || mold->rank || size)
+ {
+ int result_length;
+
+ if (size)
+ result_length = (size_t)mpz_get_ui (size->value.integer);
+ else
+ {
+ result_length = *source_size / result_elt_size;
+ if (result_length * result_elt_size < *source_size)
+ result_length += 1;
+ }
+
+ *result_size = result_length * result_elt_size;
+ if (result_length_p)
+ *result_length_p = result_length;
+ }
+ else
+ *result_size = result_elt_size;
+
+ return SUCCESS;
+}
+
+
+gfc_try
+gfc_check_transfer (gfc_expr *source, gfc_expr *mold, gfc_expr *size)
{
+ size_t source_size;
+ size_t result_size;
+
if (mold->ts.type == BT_HOLLERITH)
{
gfc_error ("'MOLD' argument of 'TRANSFER' intrinsic at %L must not be %s",
@@ -3888,6 +3946,21 @@ gfc_check_transfer (gfc_expr *source ATTRIBUTE_UNUSED,
return FAILURE;
}
+ if (!gfc_option.warn_surprising)
+ return SUCCESS;
+
+ /* If we can't calculate the sizes, we cannot check any more.
+ Return SUCCESS for that case. */
+
+ if (gfc_calculate_transfer_sizes (source, mold, size, &source_size,
+ &result_size, NULL) == FAILURE)
+ return SUCCESS;
+
+ if (source_size < result_size)
+ gfc_warning("Intrinsic TRANSFER at %L has partly undefined result: "
+ "source size %ld < result size %ld", &source->where,
+ (long) source_size, (long) result_size);
+
return SUCCESS;
}