diff options
author | Thomas Koenig <tkoenig@gcc.gnu.org> | 2011-08-05 21:51:59 +0000 |
---|---|---|
committer | Thomas Koenig <tkoenig@gcc.gnu.org> | 2011-08-05 21:51:59 +0000 |
commit | 86dbed7d1bbbee6c0a5304091e089c48a20c0142 (patch) | |
tree | 355e022c7c1cbec05a02dc85dd3da5320674d598 /gcc/fortran/check.c | |
parent | 7cfea2ef26a3aab320c90d71c35c69a8c78404d7 (diff) | |
download | gcc-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.c | 77 |
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; } |