aboutsummaryrefslogtreecommitdiff
path: root/gcc/fortran
diff options
context:
space:
mode:
authorDaniel Kraft <d@domob.eu>2008-06-18 15:53:32 +0200
committerDaniel Kraft <domob@gcc.gnu.org>2008-06-18 15:53:32 +0200
commitd28480827e3674794d7d6793148c737d491bc9ba (patch)
tree639abee5a18c067cde88b601cac41a076983e196 /gcc/fortran
parentf0c882ab6fcf7595b5d12203a9840202167d45f1 (diff)
downloadgcc-d28480827e3674794d7d6793148c737d491bc9ba.zip
gcc-d28480827e3674794d7d6793148c737d491bc9ba.tar.gz
gcc-d28480827e3674794d7d6793148c737d491bc9ba.tar.bz2
PR fortran/36517, fortran/36492
2008-06-18 Daniel Kraft <d@domob.eu> PR fortran/36517, fortran/36492 * gfortran.dg/array_constructor_25.f03: New test. * gfortran.dg/array_constructor_26.f03: New test. * gfortran.dg/array_constructor_27.f03: New test. * gfortran.dg/array_constructor_28.f03: New test. * gfortran.dg/array_constructor_29.f03: New test. * gfortran.dg/array_constructor_30.f03: New test. * gfortran.dg/array_constructor_type_19.f03: New test. * gfortran.dg/array_constructor_type_20.f03: New test. * gfortran.dg/array_constructor_type_21.f03: New test. 2008-06-18 Daniel Kraft <d@domob.eu> PR fortran/36517, fortran/36492 * array.c (gfc_resolve_character_array_constructor): Call gfc_set_constant_character_len with changed length-chec argument. * decl.c (gfc_set_constant_character_len): Changed array argument to be a generic length-checking argument that can be used for correct checking with typespec and in special cases where the should-be length is different from the target length. (build_struct): Call gfc_set_constant_character_len with changed length checking argument and introduced additional checks for exceptional conditions on invalid code. (add_init_expr_to_sym), (do_parm): Call gfc_set_constant_character_len with changed argument. * match.h (gfc_set_constant_character_len): Changed third argument to int for the should-be length rather than bool. From-SVN: r136894
Diffstat (limited to 'gcc/fortran')
-rw-r--r--gcc/fortran/ChangeLog17
-rw-r--r--gcc/fortran/array.c42
-rw-r--r--gcc/fortran/decl.c58
-rw-r--r--gcc/fortran/match.h2
4 files changed, 86 insertions, 33 deletions
diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog
index e83c3cb..6362039 100644
--- a/gcc/fortran/ChangeLog
+++ b/gcc/fortran/ChangeLog
@@ -1,3 +1,20 @@
+2008-06-18 Daniel Kraft <d@domob.eu>
+
+ PR fortran/36517, fortran/36492
+ * array.c (gfc_resolve_character_array_constructor): Call
+ gfc_set_constant_character_len with changed length-chec argument.
+ * decl.c (gfc_set_constant_character_len): Changed array argument to
+ be a generic length-checking argument that can be used for correct
+ checking with typespec and in special cases where the should-be length
+ is different from the target length.
+ (build_struct): Call gfc_set_constant_character_len with changed length
+ checking argument and introduced additional checks for exceptional
+ conditions on invalid code.
+ (add_init_expr_to_sym), (do_parm): Call gfc_set_constant_character_len
+ with changed argument.
+ * match.h (gfc_set_constant_character_len): Changed third argument to
+ int for the should-be length rather than bool.
+
2008-06-17 Daniel Kraft <d@domob.eu>
PR fortran/36112
diff --git a/gcc/fortran/array.c b/gcc/fortran/array.c
index 73b78c3..a34695e 100644
--- a/gcc/fortran/array.c
+++ b/gcc/fortran/array.c
@@ -1680,25 +1680,29 @@ got_charlen:
(without typespec) all elements are verified to have the same length
anyway. */
if (found_length != -1)
- for (p = expr->value.constructor; p; p = p->next)
- if (p->expr->expr_type == EXPR_CONSTANT)
- {
- gfc_expr *cl = NULL;
- int current_length = -1;
-
- if (p->expr->ts.cl && p->expr->ts.cl->length)
- {
- cl = p->expr->ts.cl->length;
- gfc_extract_int (cl, &current_length);
- }
-
- /* If gfc_extract_int above set current_length, we implicitly
- know the type is BT_INTEGER and it's EXPR_CONSTANT. */
-
- if (! cl
- || (current_length != -1 && current_length < found_length))
- gfc_set_constant_character_len (found_length, p->expr, true);
- }
+ for (p = expr->value.constructor; p; p = p->next)
+ if (p->expr->expr_type == EXPR_CONSTANT)
+ {
+ gfc_expr *cl = NULL;
+ int current_length = -1;
+ bool has_ts;
+
+ if (p->expr->ts.cl && p->expr->ts.cl->length)
+ {
+ cl = p->expr->ts.cl->length;
+ gfc_extract_int (cl, &current_length);
+ }
+
+ /* If gfc_extract_int above set current_length, we implicitly
+ know the type is BT_INTEGER and it's EXPR_CONSTANT. */
+
+ has_ts = (expr->ts.cl && expr->ts.cl->length_from_typespec);
+
+ if (! cl
+ || (current_length != -1 && current_length < found_length))
+ gfc_set_constant_character_len (found_length, p->expr,
+ has_ts ? -1 : found_length);
+ }
}
return SUCCESS;
diff --git a/gcc/fortran/decl.c b/gcc/fortran/decl.c
index a1c7d5a..57db93f 100644
--- a/gcc/fortran/decl.c
+++ b/gcc/fortran/decl.c
@@ -1084,10 +1084,12 @@ build_sym (const char *name, gfc_charlen *cl,
/* Set character constant to the given length. The constant will be padded or
- truncated. */
+ truncated. If we're inside an array constructor without a typespec, we
+ additionally check that all elements have the same length; check_len -1
+ means no checking. */
void
-gfc_set_constant_character_len (int len, gfc_expr *expr, bool array)
+gfc_set_constant_character_len (int len, gfc_expr *expr, int check_len)
{
gfc_char_t *s;
int slen;
@@ -1110,10 +1112,11 @@ gfc_set_constant_character_len (int len, gfc_expr *expr, bool array)
/* Apply the standard by 'hand' otherwise it gets cleared for
initializers. */
- if (array && slen < len && !(gfc_option.allow_std & GFC_STD_GNU))
+ if (check_len != -1 && slen != check_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);
+ &expr->where, slen, check_len);
s[len] = '\0';
gfc_free (expr->value.character.string);
@@ -1269,7 +1272,7 @@ add_init_expr_to_sym (const char *name, gfc_expr **initp, locus *var_locus)
gfc_constructor * p;
if (init->expr_type == EXPR_CONSTANT)
- gfc_set_constant_character_len (len, init, false);
+ gfc_set_constant_character_len (len, init, -1);
else if (init->expr_type == EXPR_ARRAY)
{
/* Build a new charlen to prevent simplification from
@@ -1280,7 +1283,7 @@ add_init_expr_to_sym (const char *name, gfc_expr **initp, locus *var_locus)
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, false);
+ gfc_set_constant_character_len (len, p->expr, -1);
}
}
}
@@ -1402,19 +1405,48 @@ build_struct (const char *name, gfc_charlen *cl, gfc_expr **init,
/* Should this ever get more complicated, combine with similar section
in add_init_expr_to_sym into a separate function. */
- if (c->ts.type == BT_CHARACTER && !c->pointer && c->initializer)
+ if (c->ts.type == BT_CHARACTER && !c->pointer && c->initializer && c->ts.cl
+ && c->ts.cl->length && c->ts.cl->length->expr_type == EXPR_CONSTANT)
{
- int len = mpz_get_si (c->ts.cl->length->value.integer);
+ int len;
+
+ gcc_assert (c->ts.cl && c->ts.cl->length);
+ gcc_assert (c->ts.cl->length->expr_type == EXPR_CONSTANT);
+ gcc_assert (c->ts.cl->length->ts.type == BT_INTEGER);
+
+ len = mpz_get_si (c->ts.cl->length->value.integer);
if (c->initializer->expr_type == EXPR_CONSTANT)
- gfc_set_constant_character_len (len, c->initializer, false);
+ gfc_set_constant_character_len (len, c->initializer, -1);
else if (mpz_cmp (c->ts.cl->length->value.integer,
c->initializer->ts.cl->length->value.integer))
{
+ bool has_ts;
gfc_constructor *ctor = c->initializer->value.constructor;
- for (;ctor ; ctor = ctor->next)
- if (ctor->expr->expr_type == EXPR_CONSTANT)
- gfc_set_constant_character_len (len, ctor->expr, true);
+
+ bool first = true;
+ int first_len;
+
+ has_ts = (c->initializer->ts.cl
+ && c->initializer->ts.cl->length_from_typespec);
+
+ for (; ctor; ctor = ctor->next)
+ {
+ /* Remember the length of the first element for checking that
+ all elements *in the constructor* have the same length. This
+ need not be the length of the LHS! */
+ if (first)
+ {
+ gcc_assert (ctor->expr->expr_type == EXPR_CONSTANT);
+ gcc_assert (ctor->expr->ts.type == BT_CHARACTER);
+ first_len = ctor->expr->value.character.length;
+ first = false;
+ }
+
+ if (ctor->expr->expr_type == EXPR_CONSTANT)
+ gfc_set_constant_character_len (len, ctor->expr,
+ has_ts ? -1 : first_len);
+ }
}
}
@@ -5822,7 +5854,7 @@ do_parm (void)
&& init->expr_type == EXPR_CONSTANT
&& init->ts.type == BT_CHARACTER)
gfc_set_constant_character_len (
- mpz_get_si (sym->ts.cl->length->value.integer), init, false);
+ mpz_get_si (sym->ts.cl->length->value.integer), init, -1);
else if (sym->ts.type == BT_CHARACTER && sym->ts.cl != NULL
&& sym->ts.cl->length == NULL)
{
diff --git a/gcc/fortran/match.h b/gcc/fortran/match.h
index 5ee91fb..cf30b27 100644
--- a/gcc/fortran/match.h
+++ b/gcc/fortran/match.h
@@ -147,7 +147,7 @@ match gfc_match_final_decl (void);
match gfc_match_implicit_none (void);
match gfc_match_implicit (void);
-void gfc_set_constant_character_len (int, gfc_expr *, bool);
+void gfc_set_constant_character_len (int, gfc_expr *, int);
/* Matchers for attribute declarations. */
match gfc_match_allocatable (void);