aboutsummaryrefslogtreecommitdiff
path: root/gcc/fortran
diff options
context:
space:
mode:
authorPaul Thomas <pault@gcc.gnu.org>2007-01-05 14:45:20 +0000
committerPaul Thomas <pault@gcc.gnu.org>2007-01-05 14:45:20 +0000
commit2220652d3f79f773fb25b4d21ea4cbf4406d1df2 (patch)
tree2999345f4ce5653de4bd004643e637f2cce6e449 /gcc/fortran
parent4b322f430a748cc600d3ef66865a24d7c1b743d5 (diff)
downloadgcc-2220652d3f79f773fb25b4d21ea4cbf4406d1df2.zip
gcc-2220652d3f79f773fb25b4d21ea4cbf4406d1df2.tar.gz
gcc-2220652d3f79f773fb25b4d21ea4cbf4406d1df2.tar.bz2
re PR fortran/23232 ([4.1 only] DATA implied DO variables)
2007-01-05 Paul Thomas <pault@gcc.gnu.org> PR fortran/23232 * decl.c (gfc_in_match_data, gfc_set_in_match_data): New functions to signal that a DATA statement is being matched. (gfc_match_data): Call gfc_set_in_match_data on entry and on exit. * gfortran.h : Add prototypes for above. * expr.c (check_init_expr): Avoid check on parameter or variable if gfc_in_match_data is true. (gfc_match_init_expr): Do not call error on non-reduction of expression if gfc_in_match_data is true. PR fortran/27996 PR fortran/27998 * decl.c (gfc_set_constant_character_len): Add boolean arg to flag array constructor resolution. Warn if string is being truncated. Standard dependent error if string is padded. Set new arg to false for all three calls to gfc_set_constant_character_len. * match.h : Add boolean arg to prototype for gfc_set_constant_character_len. * gfortran.h : Add warn_character_truncation to gfc_options. * options.c (set_Wall): Set warn_character_truncation if -Wall is set. * resolve.c (resolve_code): Warn if rhs string in character assignment has to be truncated. * array.c (gfc_resolve_character_array_constructor): Set new argument to true for call to gfc_set_constant_character_len. 2007-01-05 Paul Thomas <pault@gcc.gnu.org> PR fortran/23232 * gfortran.dg/data_implied_do_1.f90: New test. PR fortran/27996 PR fortran/27998 * gfortran.dg/char_length_1.f90: New test. From-SVN: r120485
Diffstat (limited to 'gcc/fortran')
-rw-r--r--gcc/fortran/ChangeLog30
-rw-r--r--gcc/fortran/array.c2
-rw-r--r--gcc/fortran/decl.c39
-rw-r--r--gcc/fortran/expr.c6
-rw-r--r--gcc/fortran/gfortran.h5
-rw-r--r--gcc/fortran/match.h2
-rw-r--r--gcc/fortran/options.c1
-rw-r--r--gcc/fortran/resolve.c91
8 files changed, 151 insertions, 25 deletions
diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog
index be3a9b5..0d9ade0 100644
--- a/gcc/fortran/ChangeLog
+++ b/gcc/fortran/ChangeLog
@@ -1,3 +1,33 @@
+2007-01-05 Paul Thomas <pault@gcc.gnu.org>
+
+ PR fortran/23232
+ * decl.c (gfc_in_match_data, gfc_set_in_match_data): New
+ functions to signal that a DATA statement is being matched.
+ (gfc_match_data): Call gfc_set_in_match_data on entry and on
+ exit.
+ * gfortran.h : Add prototypes for above.
+ * expr.c (check_init_expr): Avoid check on parameter or
+ variable if gfc_in_match_data is true.
+ (gfc_match_init_expr): Do not call error on non-reduction of
+ expression if gfc_in_match_data is true.
+
+ PR fortran/27996
+ PR fortran/27998
+ * decl.c (gfc_set_constant_character_len): Add boolean arg to
+ flag array constructor resolution. Warn if string is being
+ truncated. Standard dependent error if string is padded. Set
+ new arg to false for all three calls to
+ gfc_set_constant_character_len.
+ * match.h : Add boolean arg to prototype for
+ gfc_set_constant_character_len.
+ * gfortran.h : Add warn_character_truncation to gfc_options.
+ * options.c (set_Wall): Set warn_character_truncation if -Wall
+ is set.
+ * resolve.c (resolve_code): Warn if rhs string in character
+ assignment has to be truncated.
+ * array.c (gfc_resolve_character_array_constructor): Set new
+ argument to true for call to gfc_set_constant_character_len.
+
2007-01-05 Tobias Burnus <burnus@net-b.de>
PR fortran/29624
diff --git a/gcc/fortran/array.c b/gcc/fortran/array.c
index 479e60b..d3606f5 100644
--- a/gcc/fortran/array.c
+++ b/gcc/fortran/array.c
@@ -1587,7 +1587,7 @@ got_charlen:
/* Update the element constructors. */
for (p = expr->value.constructor; p; p = p->next)
if (p->expr->expr_type == EXPR_CONSTANT)
- gfc_set_constant_character_len (max_length, p->expr);
+ gfc_set_constant_character_len (max_length, p->expr, true);
}
}
}
diff --git a/gcc/fortran/decl.c b/gcc/fortran/decl.c
index d8988fd..b2f401f 100644
--- a/gcc/fortran/decl.c
+++ b/gcc/fortran/decl.c
@@ -74,6 +74,20 @@ gfc_symbol *gfc_new_block;
/********************* DATA statement subroutines *********************/
+static bool in_match_data = false;
+
+bool
+gfc_in_match_data (void)
+{
+ return in_match_data;
+}
+
+void
+gfc_set_in_match_data (bool set_value)
+{
+ in_match_data = set_value;
+}
+
/* Free a gfc_data_variable structure and everything beneath it. */
static void
@@ -455,6 +469,8 @@ gfc_match_data (void)
gfc_data *new;
match m;
+ gfc_set_in_match_data (true);
+
for (;;)
{
new = gfc_get_data ();
@@ -477,6 +493,8 @@ gfc_match_data (void)
gfc_match_char (','); /* Optional comma */
}
+ gfc_set_in_match_data (false);
+
if (gfc_pure (NULL))
{
gfc_error ("DATA statement at %C is not allowed in a PURE procedure");
@@ -486,6 +504,7 @@ gfc_match_data (void)
return MATCH_YES;
cleanup:
+ gfc_set_in_match_data (false);
gfc_free_data (new);
return MATCH_ERROR;
}
@@ -743,7 +762,7 @@ build_sym (const char *name, gfc_charlen * cl,
truncated. */
void
-gfc_set_constant_character_len (int len, gfc_expr * expr)
+gfc_set_constant_character_len (int len, gfc_expr * expr, bool array)
{
char * s;
int slen;
@@ -758,6 +777,18 @@ gfc_set_constant_character_len (int len, gfc_expr * expr)
memcpy (s, expr->value.character.string, MIN (len, slen));
if (len > slen)
memset (&s[slen], ' ', len - slen);
+
+ if (gfc_option.warn_character_truncation && slen > len)
+ gfc_warning_now ("CHARACTER expression at %L is being truncated "
+ "(%d/%d)", &expr->where, slen, len);
+
+ /* Apply the standard by 'hand' otherwise it gets cleared for
+ initializers. */
+ if (array && slen < len && !(gfc_option.allow_std & GFC_STD_GNU))
+ gfc_error_now ("The CHARACTER elements of the array constructor "
+ "at %L must have the same length (%d/%d)",
+ &expr->where, slen, len);
+
s[len] = '\0';
gfc_free (expr->value.character.string);
expr->value.character.string = s;
@@ -909,13 +940,13 @@ add_init_expr_to_sym (const char *name, gfc_expr ** initp,
gfc_constructor * p;
if (init->expr_type == EXPR_CONSTANT)
- gfc_set_constant_character_len (len, init);
+ gfc_set_constant_character_len (len, init, false);
else if (init->expr_type == EXPR_ARRAY)
{
gfc_free_expr (init->ts.cl->length);
init->ts.cl->length = gfc_copy_expr (sym->ts.cl->length);
for (p = init->value.constructor; p; p = p->next)
- gfc_set_constant_character_len (len, p->expr);
+ gfc_set_constant_character_len (len, p->expr, false);
}
}
}
@@ -4025,7 +4056,7 @@ do_parm (void)
&& init->ts.type == BT_CHARACTER
&& init->ts.kind == 1)
gfc_set_constant_character_len (
- mpz_get_si (sym->ts.cl->length->value.integer), init);
+ mpz_get_si (sym->ts.cl->length->value.integer), init, false);
sym->value = init;
return MATCH_YES;
diff --git a/gcc/fortran/expr.c b/gcc/fortran/expr.c
index 7c2069c..1146bd1 100644
--- a/gcc/fortran/expr.c
+++ b/gcc/fortran/expr.c
@@ -1829,6 +1829,9 @@ check_init_expr (gfc_expr * e)
break;
}
+ if (gfc_in_match_data ())
+ break;
+
gfc_error ("Parameter '%s' at %L has not been declared or is "
"a variable, which does not reduce to a constant "
"expression", e->symtree->n.sym->name, &e->where);
@@ -1912,7 +1915,8 @@ gfc_match_init_expr (gfc_expr ** result)
/* Not all inquiry functions are simplified to constant expressions
so it is necessary to call check_inquiry again. */
if (!gfc_is_constant_expr (expr)
- && check_inquiry (expr, 1) == FAILURE)
+ && check_inquiry (expr, 1) == FAILURE
+ && !gfc_in_match_data ())
{
gfc_error ("Initialization expression didn't reduce %C");
return MATCH_ERROR;
diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h
index 6286297..695d26d 100644
--- a/gcc/fortran/gfortran.h
+++ b/gcc/fortran/gfortran.h
@@ -1637,6 +1637,7 @@ typedef struct
int warn_surprising;
int warn_tabs;
int warn_underflow;
+ int warn_character_truncation;
int max_errors;
int flag_all_intrinsics;
@@ -1713,6 +1714,10 @@ void gfc_assign_data_value (gfc_expr *, gfc_expr *, mpz_t);
void gfc_assign_data_value_range (gfc_expr *, gfc_expr *, mpz_t, mpz_t);
void gfc_advance_section (mpz_t *, gfc_array_ref *, mpz_t *);
+/* decl.c */
+bool gfc_in_match_data (void);
+void gfc_set_in_match_data (bool);
+
/* scanner.c */
void gfc_scanner_done_1 (void);
void gfc_scanner_init_1 (void);
diff --git a/gcc/fortran/match.h b/gcc/fortran/match.h
index 2209c0d..3c8089a 100644
--- a/gcc/fortran/match.h
+++ b/gcc/fortran/match.h
@@ -130,7 +130,7 @@ match gfc_match_derived_decl (void);
match gfc_match_implicit_none (void);
match gfc_match_implicit (void);
-void gfc_set_constant_character_len (int, gfc_expr *);
+void gfc_set_constant_character_len (int, gfc_expr *, bool);
/* Matchers for attribute declarations */
match gfc_match_allocatable (void);
diff --git a/gcc/fortran/options.c b/gcc/fortran/options.c
index 8819b60..da8db65 100644
--- a/gcc/fortran/options.c
+++ b/gcc/fortran/options.c
@@ -309,6 +309,7 @@ set_Wall (void)
gfc_option.warn_surprising = 1;
gfc_option.warn_tabs = 0;
gfc_option.warn_underflow = 1;
+ gfc_option.warn_character_truncation = 1;
set_Wunused (1);
warn_return_type = 1;
diff --git a/gcc/fortran/resolve.c b/gcc/fortran/resolve.c
index 3c28d45..44236e5 100644
--- a/gcc/fortran/resolve.c
+++ b/gcc/fortran/resolve.c
@@ -5084,6 +5084,28 @@ resolve_code (gfc_code * code, gfc_namespace * ns)
goto call;
}
+ if (code->expr->ts.type == BT_CHARACTER
+ && gfc_option.warn_character_truncation)
+ {
+ int llen = 0, rlen = 0;
+ gfc_symbol *sym;
+ sym = code->expr->symtree->n.sym;
+ if (sym->ts.cl->length->expr_type == EXPR_CONSTANT)
+ llen = mpz_get_si (sym->ts.cl->length->value.integer);
+
+ if (code->expr2->expr_type == EXPR_CONSTANT)
+ rlen = code->expr2->value.character.length;
+
+ else if (code->expr2->ts.cl != NULL
+ && code->expr2->ts.cl->length != NULL
+ && code->expr2->ts.cl->length->expr_type == EXPR_CONSTANT)
+ rlen = mpz_get_si (code->expr2->ts.cl->length->value.integer);
+
+ if (rlen && llen && rlen > llen)
+ gfc_warning_now ("rhs of CHARACTER assignment at %L will "
+ "be truncated (%d/%d)", &code->loc, rlen, llen);
+ }
+
if (gfc_pure (NULL))
{
if (gfc_impure_variable (code->expr->symtree->n.sym))
@@ -6435,17 +6457,47 @@ traverse_data_list (gfc_data_variable * var, locus * where)
{
mpz_t trip;
iterator_stack frame;
- gfc_expr *e;
+ gfc_expr *e, *start, *end, *step;
+ try retval = SUCCESS;
mpz_init (frame.value);
- mpz_init_set (trip, var->iter.end->value.integer);
- mpz_sub (trip, trip, var->iter.start->value.integer);
- mpz_add (trip, trip, var->iter.step->value.integer);
+ start = gfc_copy_expr (var->iter.start);
+ end = gfc_copy_expr (var->iter.end);
+ step = gfc_copy_expr (var->iter.step);
+
+ if (gfc_simplify_expr (start, 1) == FAILURE
+ || start->expr_type != EXPR_CONSTANT)
+ {
+ gfc_error ("iterator start at %L does not simplify",
+ &start->where);
+ retval = FAILURE;
+ goto cleanup;
+ }
+ if (gfc_simplify_expr (end, 1) == FAILURE
+ || end->expr_type != EXPR_CONSTANT)
+ {
+ gfc_error ("iterator end at %L does not simplify",
+ &end->where);
+ retval = FAILURE;
+ goto cleanup;
+ }
+ if (gfc_simplify_expr (step, 1) == FAILURE
+ || step->expr_type != EXPR_CONSTANT)
+ {
+ gfc_error ("iterator step at %L does not simplify",
+ &step->where);
+ retval = FAILURE;
+ goto cleanup;
+ }
+
+ mpz_init_set (trip, end->value.integer);
+ mpz_sub (trip, trip, start->value.integer);
+ mpz_add (trip, trip, step->value.integer);
- mpz_div (trip, trip, var->iter.step->value.integer);
+ mpz_div (trip, trip, step->value.integer);
- mpz_set (frame.value, var->iter.start->value.integer);
+ mpz_set (frame.value, start->value.integer);
frame.prev = iter_stack;
frame.variable = var->iter.var->symtree;
@@ -6456,26 +6508,34 @@ traverse_data_list (gfc_data_variable * var, locus * where)
if (traverse_data_var (var->list, where) == FAILURE)
{
mpz_clear (trip);
- return FAILURE;
+ retval = FAILURE;
+ goto cleanup;
}
e = gfc_copy_expr (var->expr);
if (gfc_simplify_expr (e, 1) == FAILURE)
- {
- gfc_free_expr (e);
- return FAILURE;
- }
+ {
+ gfc_free_expr (e);
+ mpz_clear (trip);
+ retval = FAILURE;
+ goto cleanup;
+ }
- mpz_add (frame.value, frame.value, var->iter.step->value.integer);
+ mpz_add (frame.value, frame.value, step->value.integer);
mpz_sub_ui (trip, trip, 1);
}
mpz_clear (trip);
+cleanup:
mpz_clear (frame.value);
+ gfc_free_expr (start);
+ gfc_free_expr (end);
+ gfc_free_expr (step);
+
iter_stack = frame.prev;
- return SUCCESS;
+ return retval;
}
@@ -6520,11 +6580,6 @@ resolve_data_variables (gfc_data_variable * d)
if (gfc_resolve_iterator (&d->iter, false) == FAILURE)
return FAILURE;
- if (d->iter.start->expr_type != EXPR_CONSTANT
- || d->iter.end->expr_type != EXPR_CONSTANT
- || d->iter.step->expr_type != EXPR_CONSTANT)
- gfc_internal_error ("resolve_data_variables(): Bad iterator");
-
if (resolve_data_variables (d->list) == FAILURE)
return FAILURE;
}