This is the mail archive of the
fortran@gcc.gnu.org
mailing list for the GNU Fortran project.
Re: PING: [patch, fortran] PR 27997: Implement F2003-style array constructor with typespec
- From: Daniel Kraft <d at domob dot eu>
- To: Fortran List <fortran at gcc dot gnu dot org>, gcc-patches at gcc dot gnu dot org
- Date: Sat, 03 May 2008 14:25:20 +0000
- Subject: Re: PING: [patch, fortran] PR 27997: Implement F2003-style array constructor with typespec
- References: <480E2FA1.4050601@domob.eu> <7D6A14EC-3753-4EA1-AFEF-742E186BDEB3@gmail.com> <481367F6.4050900@domob.eu> <AC49E066-BB1F-4EEE-A463-862B8421EADD@gmail.com>
FX wrote:
Here is my review of your revised patch. First, a small formal issue:
you need to provide updated ChangeLog entries with an updated patch.
Second, you need to indicate what testing has been done on the new patch
and where (again, something along the lines of "bootstrapped and
regtested on x86_64-linux, with both -m32 and -m64). [1] Third, until
you have your copyright assignment confirmed, no commit possible, so I
propose you send us a final, updated version of your patch after we work
on the last comments below and ChangeLog entries, for reference until we
can commit it.
Thanks for the second review, here's another updated patch; I believe
this could be the final one if you are ok with it.
Updated ChangeLog and patch attached, tested on GNU/Linux i686 without
failures. (I'm not sure what I have to do exactly for bootstrapping,
but I did a full successful rebuild with the patch applied, too.)
I've tried to trigger that code and could not see it work. I cannot
see a runtime error, neither with
For this I didn't do anything by now, if it is ok I suggest we look at
this separatly?
OK. But please give it some thought if you have a bit of time.
Filed a new PR for this, will work on it there.
+ /* get_array_ctor_strlen walks the elements of the constructor,
if a
+ typespec was given, we already know the string length and want
the one
+ specified there. */
+ /* XXX: Adding typespec_chararray_ctor here was merely a hack
to make
+ gfortran.dg/array_constructor_17.f90 work (ICE otherwise). Is this
+ ok anyway or should I look for another solution? */
+ if (typespec_chararray_ctor && ss->expr->ts.cl->length
+ && ss->expr->ts.cl->length->expr_type != EXPR_CONSTANT)
I'd prefer we find out and don't leave such a comment (and question) in
the code: "adding" will not mean anything to the reader when the rest of
the code has changed, and now is the best time to solve this issue. What
is the backtrace of the ICE if you leave typespec_chararray_ctor out?
Did remove the comment (this was the only change to the patch) after I
gave it some new thoughts; honestly, I wasn't able to figure out what
exactly was wrong without typespec_chararray_ctor there, but I believe
it is "correct" to have it here as this simply means we're only visiting
the new branch if there was a typespec given, which is probably what we
want.
When I added this comment I somehow had the impression this check should
be superfluous as ss->expr->ts.cl->length was enough, but is seems this
could be set by some other ways as a typespec and adding the explicit
typespec-check is ok and the right thing.
Ok with this? (BTW, this test-case mentioned is for PR31219)
Thanks,
Daniel
--
Done: Bar-Sam-Val-Wiz, Dwa-Elf-Hum-Orc, Cha-Law, Fem-Mal
Underway: Ran-Gno-Neu-Fem
To go: Arc-Cav-Hea-Kni-Mon-Pri-Rog-Tou
2008-04-07 Daniel Kraft <d@domob.eu>
PR fortran/27997
* gfortran.h: Added field "length_from_typespec" to gfc_charlength.
* aray.c (gfc_match_array_constructor): Added code to parse typespec.
(check_element_type, check_constructor_type, gfc_check_constructor_type):
Extended to support explicit typespec on constructor.
(gfc_resolve_character_array_constructor): Pad strings correctly for
explicit, constant character length.
* trans-array.c: New static global variable "typespec_chararray_ctor"
(gfc_trans_array_constructor): New code to support explicit but dynamic
character lengths.
2008-04-07 Daniel Kraft <d@domob.eu>
PR fortran/27997
* gfortran.dg/array_constructor_type_1.f03: New test
* gfortran.dg/array_constructor_type_2.f03: New test
* gfortran.dg/array_constructor_type_3.f03: New test
* gfortran.dg/array_constructor_type_4.f03: New test
* gfortran.dg/array_constructor_type_5.f03: New test
* gfortran.dg/array_constructor_type_6.f03: New test
* gfortran.dg/array_constructor_type_7.f03: New test
* gfortran.dg/array_constructor_type_8.f03: New test
* gfortran.dg/array_constructor_type_9.f: New test
* gfortran.dg/array_constructor_type_10.f03: New test
* gfortran.dg/array_constructor_type_11.f03: New test
* gfortran.dg/array_constructor_type_12.f03: New test
* gfortran.dg/array_constructor_type_13.f90: New test
* gfortran.dg/array_constructor_type_14.f03: New test
* gfortran.dg/array_constructor_type_15.f03: New test
* gfortran.dg/array_constructor_type_16.f03: New test
* gfortran.dg/array_constructor_type_17.f03: New test
* gfortran.dg/array_constructor_type_18.f03: New test
Index: gcc/testsuite/gfortran.dg/array_constructor_type_5.f03
===================================================================
--- gcc/testsuite/gfortran.dg/array_constructor_type_5.f03 (revision 0)
+++ gcc/testsuite/gfortran.dg/array_constructor_type_5.f03 (revision 0)
@@ -0,0 +1,18 @@
+! { dg-do run }
+!
+! PR fortran/27997
+!
+! Array constructor with typespec and small length value.
+!
+program test
+ implicit none
+ character(15) :: a(3)
+ a = (/ character(len=3) :: 'Takata', 'Tanaka', 'Hayashi' /)
+ if( a(1) /= 'Tak' .or. a(1)(4:4) /= achar(32) &
+ .or. a(1)(15:15) /= achar(32) &
+ .or. a(2) /= 'Tan' .or. a(2)(4:4) /= achar(32) &
+ .or. a(2)(15:15) /= achar(32) &
+ .or. a(3) /= 'Hay' .or. a(3)(4:4) /= achar(32) &
+ .or. a(3)(15:15) /= achar(32))&
+ call abort()
+end program test
Index: gcc/testsuite/gfortran.dg/array_constructor_type_6.f03
===================================================================
--- gcc/testsuite/gfortran.dg/array_constructor_type_6.f03 (revision 0)
+++ gcc/testsuite/gfortran.dg/array_constructor_type_6.f03 (revision 0)
@@ -0,0 +1,30 @@
+! { dg-do run }
+! { dg-options "-fbounds-check" }
+!
+! PR fortran/27997
+!
+! Array constructor with typespec.
+!
+program test
+ character(15) :: a(3)
+ character(10), volatile :: b(3)
+ b(1) = 'Takata'
+ b(2) = 'Tanaka'
+ b(3) = 'Hayashi'
+
+ a = (/ character(len=7) :: trim(b(1)), trim(b(2)), trim(b(3)) /)
+ if (a(1) /= 'Takata' .or. a(2) /= 'Tanaka' .or. a(3) /= 'Hayashi') then
+ call abort ()
+ end if
+
+ a = (/ character(len=2) :: trim(b(1)), trim(b(2)), trim(b(3)) /)
+ if (a(1) /= 'Ta' .or. a(2) /= 'Ta' .or. a(3) /= 'Ha') then
+ call abort ()
+ end if
+
+ a = (/ character(len=8) :: trim(b(1)), trim(b(2)), trim(b(3)) /)
+ if (a(1) /= 'Takata' .or. a(2) /= 'Tanaka' .or. a(3) /= 'Hayashi') then
+ call abort ()
+ end if
+
+end program test
Index: gcc/testsuite/gfortran.dg/array_constructor_type_10.f03
===================================================================
--- gcc/testsuite/gfortran.dg/array_constructor_type_10.f03 (revision 0)
+++ gcc/testsuite/gfortran.dg/array_constructor_type_10.f03 (revision 0)
@@ -0,0 +1,23 @@
+! { dg-do run }
+! { dg-options "-fbounds-check" }
+!
+! PR fortran/27997
+!
+! Array constructor with typespec and dynamic
+! character length.
+!
+PROGRAM test
+ CALL foo(8, "short", "short")
+ CALL foo(2, "lenghty", "le")
+CONTAINS
+ SUBROUTINE foo (n, s, shouldBe)
+ CHARACTER(len=*) :: s
+ CHARACTER(len=*) :: shouldBe
+ CHARACTER(len=16) :: arr(2)
+ INTEGER :: n
+ arr = [ character(len=n) :: s, s ]
+ IF (arr(1) /= shouldBe .OR. arr(2) /= shouldBe) THEN
+ CALL abort ()
+ END IF
+ END SUBROUTINE foo
+END PROGRAM test
Index: gcc/testsuite/gfortran.dg/array_constructor_type_7.f03
===================================================================
--- gcc/testsuite/gfortran.dg/array_constructor_type_7.f03 (revision 0)
+++ gcc/testsuite/gfortran.dg/array_constructor_type_7.f03 (revision 0)
@@ -0,0 +1,23 @@
+! { dg-do run }
+! { dg-options "-fbounds-check" }
+!
+! PR fortran/27997
+!
+! Array constructor with typespec and dynamic
+! character length.
+!
+PROGRAM test
+ CALL foo(8, "short", "test", "short")
+ CALL foo(2, "lenghty", "te", "le")
+CONTAINS
+ SUBROUTINE foo (n, s, a1, a2)
+ CHARACTER(len=*) :: s
+ CHARACTER(len=*) :: a1, a2
+ CHARACTER(len=n) :: arr(2)
+ INTEGER :: n
+ arr = [ character(len=n) :: 'test', s ]
+ IF (arr(1) /= a1 .OR. arr(2) /= a2) THEN
+ CALL abort ()
+ END IF
+ END SUBROUTINE foo
+END PROGRAM test
Index: gcc/testsuite/gfortran.dg/array_constructor_type_11.f03
===================================================================
--- gcc/testsuite/gfortran.dg/array_constructor_type_11.f03 (revision 0)
+++ gcc/testsuite/gfortran.dg/array_constructor_type_11.f03 (revision 0)
@@ -0,0 +1,11 @@
+! { dg-do run }
+!
+! PR fortran/27997
+!
+! Empty array constructor with typespec.
+!
+ integer :: i(3)
+ i(3:2) = (/ integer :: /)
+ if (len((/ character(5) :: /)) /= 5) call abort()
+ if (kind((/ integer(8) :: /)) /= 8) call abort()
+end
Index: gcc/testsuite/gfortran.dg/array_constructor_type_8.f03
===================================================================
--- gcc/testsuite/gfortran.dg/array_constructor_type_8.f03 (revision 0)
+++ gcc/testsuite/gfortran.dg/array_constructor_type_8.f03 (revision 0)
@@ -0,0 +1,13 @@
+! { dg-do run }
+!
+! PR fortran/27997
+!
+! Array constructor with typespec, check for regression
+!
+program test
+ implicit none
+ type :: real_info
+ integer :: kind
+ end type real_info
+ type (real_info) :: real_infos(1) = (/ real_info (4) /)
+end program test
Index: gcc/testsuite/gfortran.dg/array_constructor_type_12.f03
===================================================================
--- gcc/testsuite/gfortran.dg/array_constructor_type_12.f03 (revision 0)
+++ gcc/testsuite/gfortran.dg/array_constructor_type_12.f03 (revision 0)
@@ -0,0 +1,12 @@
+! { dg-do run }
+!
+! PR fortran/27997
+!
+! Array constructor with typespec.
+!
+real :: a(3)
+integer :: j(3)
+a = (/ integer :: 1.4, 2.2, 3.33 /)
+j = (/ 1.4, 2.2, 3.33 /)
+if( any(a /= j )) call abort()
+end
Index: gcc/testsuite/gfortran.dg/array_constructor_type_14.f03
===================================================================
--- gcc/testsuite/gfortran.dg/array_constructor_type_14.f03 (revision 0)
+++ gcc/testsuite/gfortran.dg/array_constructor_type_14.f03 (revision 0)
@@ -0,0 +1,24 @@
+! { dg-do run }
+! PR fortran/27997
+!
+! Array constructor with typespec
+! for derived types.
+
+PROGRAM test
+ IMPLICIT NONE
+
+ TYPE foo
+ INTEGER :: i
+ REAL :: x
+ END TYPE foo
+
+ TYPE(foo), PARAMETER :: x = foo(42, 42.)
+
+ TYPE(foo), DIMENSION(2) :: arr
+
+ arr = (/ TYPE(foo) :: x, foo(0, 1.) /)
+ IF (arr(1)%i /= 42 .OR. arr(1)%x /= 42. .OR. &
+ arr(2)%i /= 0 .OR. arr(2)%x /= 1.) THEN
+ CALL abort()
+ END IF
+END PROGRAM test
Index: gcc/testsuite/gfortran.dg/array_constructor_type_15.f03
===================================================================
--- gcc/testsuite/gfortran.dg/array_constructor_type_15.f03 (revision 0)
+++ gcc/testsuite/gfortran.dg/array_constructor_type_15.f03 (revision 0)
@@ -0,0 +1,22 @@
+! { dg-do compile }
+! PR fortran/27997
+!
+! Array constructor with typespec
+! for derived types, failing conversion.
+
+PROGRAM test
+ IMPLICIT NONE
+
+ TYPE foo
+ INTEGER :: i
+ REAL :: x
+ END TYPE foo
+
+ TYPE bar
+ LOGICAL :: logos
+ END TYPE bar
+
+ TYPE(foo), PARAMETER :: x = foo(42, 42.)
+
+ WRITE (*,*) (/ TYPE(foo) :: x, foo(0, 1.), bar(.TRUE.) /) ! { dg-error "convert TYPE" }
+END PROGRAM test
Index: gcc/testsuite/gfortran.dg/array_constructor_type_9.f
===================================================================
--- gcc/testsuite/gfortran.dg/array_constructor_type_9.f (revision 0)
+++ gcc/testsuite/gfortran.dg/array_constructor_type_9.f (revision 0)
@@ -0,0 +1,10 @@
+! { dg-do run }
+!
+! PR fortran/27997
+!
+! Array constructor with typespec, check for regression
+! with fixed form.
+!
+ integer :: a(2), realabc, real_abc2
+ a = [ realabc, real_abc2 ]
+ end
Index: gcc/testsuite/gfortran.dg/array_constructor_type_13.f90
===================================================================
--- gcc/testsuite/gfortran.dg/array_constructor_type_13.f90 (revision 0)
+++ gcc/testsuite/gfortran.dg/array_constructor_type_13.f90 (revision 0)
@@ -0,0 +1,14 @@
+! { dg-do compile }
+! { dg-options "-std=f95" }
+!
+! PR fortran/27997
+!
+! Array constructor with typespec
+! should be rejected for Fortran 95.
+!
+real :: a(3)
+integer :: j(3)
+a = (/ integer :: 1.4, 2.2, 3.33 /) ! { dg-error "Fortran 2003" }
+j = (/ 1.4, 2.2, 3.33 /)
+if( any(a /= j )) call abort()
+end
Index: gcc/testsuite/gfortran.dg/array_constructor_type_16.f03
===================================================================
--- gcc/testsuite/gfortran.dg/array_constructor_type_16.f03 (revision 0)
+++ gcc/testsuite/gfortran.dg/array_constructor_type_16.f03 (revision 0)
@@ -0,0 +1,25 @@
+! { dg-do run }
+! PR fortran/27997
+!
+! Nested array constructors with typespec.
+
+PROGRAM test
+ IMPLICIT NONE
+
+ INTEGER(KIND=8) :: arr(3)
+ CHARACTER(len=6) :: carr(3)
+
+ arr = (/ INTEGER(KIND=8) :: 4, [ INTEGER(KIND=4) :: 42, 12 ] /)
+ IF (arr(1) /= 4 .OR. arr(2) /= 42 .OR. arr(3) /= 12) CALL abort()
+ arr = (/ INTEGER(KIND=8) :: [ INTEGER(KIND=4) :: 4, 42, 12 ] /)
+ IF (arr(1) /= 4 .OR. arr(2) /= 42 .OR. arr(3) /= 12) CALL abort()
+ arr = (/ INTEGER(KIND=8) :: [ INTEGER(KIND=4) :: 4, 42 ], 12 /)
+ IF (arr(1) /= 4 .OR. arr(2) /= 42 .OR. arr(3) /= 12) CALL abort()
+ arr = (/ INTEGER(KIND=8) :: [ INTEGER(KIND=4) :: ], 4, 42, 12 /)
+ IF (arr(1) /= 4 .OR. arr(2) /= 42 .OR. arr(3) /= 12) CALL abort()
+
+ carr = [ CHARACTER(len=6) :: "foo", [ CHARACTER(len=4) :: "foobar", "xyz" ] ]
+ IF (carr(1) /= "foo" .OR. carr(2) /= "foob" .OR. carr(3) /= "xyz") THEN
+ CALL abort()
+ END IF
+END PROGRAM test
Index: gcc/testsuite/gfortran.dg/array_constructor_type_17.f03
===================================================================
--- gcc/testsuite/gfortran.dg/array_constructor_type_17.f03 (revision 0)
+++ gcc/testsuite/gfortran.dg/array_constructor_type_17.f03 (revision 0)
@@ -0,0 +1,12 @@
+! { dg-do compile }
+! { dg-options "-fno-range-check -Wconversion" }
+! PR fortran/27997
+!
+! Range check on array-constructors with typespec.
+
+PROGRAM test
+ IMPLICIT NONE
+
+ INTEGER(KIND=4) :: arr(1)
+ arr = (/ INTEGER(KIND=4) :: HUGE(0_8) /) ! { dg-warning "Conversion from" }
+END PROGRAM test
Index: gcc/testsuite/gfortran.dg/array_constructor_type_18.f03
===================================================================
--- gcc/testsuite/gfortran.dg/array_constructor_type_18.f03 (revision 0)
+++ gcc/testsuite/gfortran.dg/array_constructor_type_18.f03 (revision 0)
@@ -0,0 +1,12 @@
+! { dg-do compile }
+! { dg-options "-frange-check" }
+! PR fortran/27997
+!
+! Range check on array-constructors with typespec.
+
+PROGRAM test
+ IMPLICIT NONE
+
+ INTEGER(KIND=4) :: arr(1)
+ arr = (/ INTEGER(KIND=4) :: HUGE(0_8) /) ! { dg-error "overflow converting" }
+END PROGRAM test
Index: gcc/testsuite/gfortran.dg/array_constructor_type_1.f03
===================================================================
--- gcc/testsuite/gfortran.dg/array_constructor_type_1.f03 (revision 0)
+++ gcc/testsuite/gfortran.dg/array_constructor_type_1.f03 (revision 0)
@@ -0,0 +1,17 @@
+! { dg-do run }
+!
+! PR fortran/27997
+!
+! Simple array constructor with typespec.
+!
+PROGRAM test
+ IMPLICIT NONE
+ INTEGER :: array(5)
+
+ array = (/ INTEGER :: 18, 12, 31, 3, 42.4 /)
+
+ IF (array(1) /= 18 .OR. array(2) /= 12 .OR. &
+ array(3) /= 31 .OR. array(4) /= 3 .OR. array(5) /= 42) THEN
+ CALL abort()
+ END IF
+END PROGRAM test
Index: gcc/testsuite/gfortran.dg/array_constructor_type_2.f03
===================================================================
--- gcc/testsuite/gfortran.dg/array_constructor_type_2.f03 (revision 0)
+++ gcc/testsuite/gfortran.dg/array_constructor_type_2.f03 (revision 0)
@@ -0,0 +1,20 @@
+! { dg-do run }
+!
+! PR fortran/27997
+!
+! Array constructor with typespec, length parameter.
+!
+program test
+ implicit none
+ character(15) :: a(3)
+ a = (/ character(len=7) :: 'Takata', 'Tanaka', 'Hayashi' /)
+ if ( len([ character(len=7) :: ]) /= 7) call abort()
+ if ( size([ integer :: ]) /= 0) call abort()
+ if( a(1) /= 'Takata' .or. a(1)(7:7) /= achar(32) &
+ .or. a(1)(15:15) /= achar(32) &
+ .or. a(2) /= 'Tanaka' .or. a(2)(7:7) /= achar(32) &
+ .or. a(2)(15:15) /= achar(32) &
+ .or. a(3) /= 'Hayashi' .or. a(3)(8:8) /= achar(32) &
+ .or. a(3)(15:15) /= achar(32))&
+ call abort()
+end program test
Index: gcc/testsuite/gfortran.dg/array_constructor_type_3.f03
===================================================================
--- gcc/testsuite/gfortran.dg/array_constructor_type_3.f03 (revision 0)
+++ gcc/testsuite/gfortran.dg/array_constructor_type_3.f03 (revision 0)
@@ -0,0 +1,16 @@
+! { dg-do run }
+!
+! PR fortran/27997
+!
+! Test empty array constructor with typespec.
+!
+PROGRAM test
+ IMPLICIT NONE
+ INTEGER :: array(2)
+
+ array = (/ 5, [INTEGER ::], 6 /)
+
+ IF (array(1) /= 5 .OR. array(2) /= 6) THEN
+ CALL abort()
+ END IF
+END PROGRAM test
Index: gcc/testsuite/gfortran.dg/array_constructor_type_4.f03
===================================================================
--- gcc/testsuite/gfortran.dg/array_constructor_type_4.f03 (revision 0)
+++ gcc/testsuite/gfortran.dg/array_constructor_type_4.f03 (revision 0)
@@ -0,0 +1,15 @@
+! { dg-do run }
+!
+! PR fortran/27997
+!
+! Ensure that :: is present when a typespec is deduced.
+!
+PROGRAM test
+ INTEGER :: array(1)
+ INTEGER = 42
+
+ array = [ INTEGER ]
+ IF (array(1) /= 42) THEN
+ CALL abort()
+ END IF
+END PROGRAM test
Index: gcc/fortran/trans-array.c
===================================================================
--- gcc/fortran/trans-array.c (revision 134885)
+++ gcc/fortran/trans-array.c (working copy)
@@ -959,9 +959,10 @@ gfc_put_offset_into_var (stmtblock_t * p
}
-/* Assign an element of an array constructor. */
+/* Variables needed for bounds-checking. */
static bool first_len;
static tree first_len_val;
+static bool typespec_chararray_ctor;
static void
gfc_trans_array_ctor_element (stmtblock_t * pblock, tree desc,
@@ -998,7 +999,7 @@ gfc_trans_array_ctor_element (stmtblock_
se->string_length,
se->expr);
}
- if (flag_bounds_check)
+ if (flag_bounds_check && !typespec_chararray_ctor)
{
if (first_len)
{
@@ -1677,7 +1678,13 @@ gfc_trans_array_constructor (gfc_loopinf
tree loopfrom;
bool dynamic;
- if (flag_bounds_check && ss->expr->ts.type == BT_CHARACTER)
+ /* Do bounds-checking here and in gfc_trans_array_ctor_element only if no
+ typespec was given for the array constructor. */
+ typespec_chararray_ctor = (ss->expr->ts.cl
+ && ss->expr->ts.cl->length_from_typespec);
+
+ if (flag_bounds_check && ss->expr->ts.type == BT_CHARACTER
+ && !typespec_chararray_ctor)
{
first_len_val = gfc_create_var (gfc_charlen_type_node, "len");
first_len = true;
@@ -1688,7 +1695,27 @@ gfc_trans_array_constructor (gfc_loopinf
c = ss->expr->value.constructor;
if (ss->expr->ts.type == BT_CHARACTER)
{
- bool const_string = get_array_ctor_strlen (&loop->pre, c, &ss->string_length);
+ bool const_string;
+
+ /* get_array_ctor_strlen walks the elements of the constructor, if a
+ typespec was given, we already know the string length and want the one
+ specified there. */
+ if (typespec_chararray_ctor && ss->expr->ts.cl->length
+ && ss->expr->ts.cl->length->expr_type != EXPR_CONSTANT)
+ {
+ gfc_se length_se;
+
+ const_string = false;
+ gfc_init_se (&length_se, NULL);
+ gfc_conv_expr_type (&length_se, ss->expr->ts.cl->length,
+ gfc_charlen_type_node);
+ ss->string_length = length_se.expr;
+ gfc_add_block_to_block (&loop->pre, &length_se.pre);
+ gfc_add_block_to_block (&loop->post, &length_se.post);
+ }
+ else
+ const_string = get_array_ctor_strlen (&loop->pre, c,
+ &ss->string_length);
/* Complex character array constructors should have been taken care of
and not end up here. */
Index: gcc/fortran/array.c
===================================================================
--- gcc/fortran/array.c (revision 134885)
+++ gcc/fortran/array.c (working copy)
@@ -877,9 +877,11 @@ gfc_match_array_constructor (gfc_expr **
{
gfc_constructor *head, *tail, *new;
gfc_expr *expr;
+ gfc_typespec ts;
locus where;
match m;
const char *end_delim;
+ bool seen_ts;
if (gfc_match (" (/") == MATCH_NO)
{
@@ -898,11 +900,33 @@ gfc_match_array_constructor (gfc_expr **
where = gfc_current_locus;
head = tail = NULL;
+ seen_ts = false;
+
+ /* Try to match an optional "type-spec ::" */
+ if (gfc_match_type_spec (&ts, 0) == MATCH_YES)
+ {
+ seen_ts = (gfc_match (" ::") == MATCH_YES);
+
+ if (seen_ts)
+ {
+ if (gfc_notify_std (GFC_STD_F2003, "Fortran 2003: Array constructor "
+ "including type specification at %C") == FAILURE)
+ goto cleanup;
+ }
+ }
+
+ if (! seen_ts)
+ gfc_current_locus = where;
if (gfc_match (end_delim) == MATCH_YES)
{
- gfc_error ("Empty array constructor at %C is not allowed");
- goto cleanup;
+ if (seen_ts)
+ goto done;
+ else
+ {
+ gfc_error ("Empty array constructor at %C is not allowed");
+ goto cleanup;
+ }
}
for (;;)
@@ -927,6 +951,7 @@ gfc_match_array_constructor (gfc_expr **
if (gfc_match (end_delim) == MATCH_NO)
goto syntax;
+done:
expr = gfc_get_expr ();
expr->expr_type = EXPR_ARRAY;
@@ -934,6 +959,14 @@ gfc_match_array_constructor (gfc_expr **
expr->value.constructor = head;
/* Size must be calculated at resolution time. */
+ if (seen_ts)
+ expr->ts = ts;
+ else
+ expr->ts.type = BT_UNKNOWN;
+
+ if (expr->ts.cl)
+ expr->ts.cl->length_from_typespec = seen_ts;
+
expr->where = where;
expr->rank = 1;
@@ -964,7 +997,7 @@ static enum
cons_state;
static int
-check_element_type (gfc_expr *expr)
+check_element_type (gfc_expr *expr, bool convert)
{
if (cons_state == CONS_BAD)
return 0; /* Suppress further errors */
@@ -985,6 +1018,9 @@ check_element_type (gfc_expr *expr)
if (gfc_compare_types (&constructor_ts, &expr->ts))
return 0;
+ if (convert)
+ return gfc_convert_type (expr, &constructor_ts, 1) == SUCCESS ? 0 : 1;
+
gfc_error ("Element in %s array constructor at %L is %s",
gfc_typename (&constructor_ts), &expr->where,
gfc_typename (&expr->ts));
@@ -997,7 +1033,7 @@ check_element_type (gfc_expr *expr)
/* Recursive work function for gfc_check_constructor_type(). */
static try
-check_constructor_type (gfc_constructor *c)
+check_constructor_type (gfc_constructor *c, bool convert)
{
gfc_expr *e;
@@ -1007,13 +1043,13 @@ check_constructor_type (gfc_constructor
if (e->expr_type == EXPR_ARRAY)
{
- if (check_constructor_type (e->value.constructor) == FAILURE)
+ if (check_constructor_type (e->value.constructor, convert) == FAILURE)
return FAILURE;
continue;
}
- if (check_element_type (e))
+ if (check_element_type (e, convert))
return FAILURE;
}
@@ -1029,10 +1065,20 @@ gfc_check_constructor_type (gfc_expr *e)
{
try t;
- cons_state = CONS_START;
- gfc_clear_ts (&constructor_ts);
+ if (e->ts.type != BT_UNKNOWN)
+ {
+ cons_state = CONS_GOOD;
+ constructor_ts = e->ts;
+ }
+ else
+ {
+ cons_state = CONS_START;
+ gfc_clear_ts (&constructor_ts);
+ }
- t = check_constructor_type (e->value.constructor);
+ /* If e->ts.type != BT_UNKNOWN, the array constructor included a
+ typespec, and we will now convert the values on the fly. */
+ t = check_constructor_type (e->value.constructor, e->ts.type != BT_UNKNOWN);
if (t == SUCCESS && e->ts.type == BT_UNKNOWN)
e->ts = constructor_ts;
@@ -1526,13 +1572,15 @@ resolve_array_list (gfc_constructor *p)
/* Resolve character array constructor. If it is a constant character array and
not specified character length, update character length to the maximum of
- its element constructors' length. */
+ its element constructors' length. For arrays with fixed length, pad the
+ elements as necessary with needed_length. */
void
gfc_resolve_character_array_constructor (gfc_expr *expr)
{
gfc_constructor *p;
int max_length;
+ bool generated_length;
gcc_assert (expr->expr_type == EXPR_ARRAY);
gcc_assert (expr->ts.type == BT_CHARACTER);
@@ -1557,6 +1605,7 @@ gfc_resolve_character_array_constructor
got_charlen:
+ generated_length = false;
if (expr->ts.cl->length == NULL)
{
/* Find the maximum length of the elements. Do nothing for variable
@@ -1596,12 +1645,46 @@ got_charlen:
{
/* Update the character length of the array constructor. */
expr->ts.cl->length = gfc_int_expr (max_length);
- /* 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, true);
+ generated_length = true;
+ /* Real update follows below. */
}
}
+ else
+ {
+ /* We've got a character length specified. It should be an integer,
+ otherwise an error is signalled elsewhere. */
+ gcc_assert (expr->ts.cl->length);
+
+ /* If we've got a constant character length, pad according to this.
+ gfc_extract_int does check for BT_INTEGER and EXPR_CONSTANT and sets
+ max_length only if they pass. */
+ gfc_extract_int (expr->ts.cl->length, &max_length);
+ }
+
+ /* Found a length to update to, do it for all element strings shorter than
+ the target length. */
+ if (max_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, ¤t_length);
+ }
+
+ /* If gfc_extract_int above set current_length, we implicitly
+ know the type is BT_INTEGER and it's EXPR_CONSTANT. */
+
+ if (generated_length || ! cl
+ || (current_length != -1 && current_length < max_length))
+ gfc_set_constant_character_len (max_length, p->expr, true);
+ }
+ }
}
Index: gcc/fortran/gfortran.h
===================================================================
--- gcc/fortran/gfortran.h (revision 134885)
+++ gcc/fortran/gfortran.h (working copy)
@@ -763,6 +763,7 @@ typedef struct gfc_charlen
{
struct gfc_expr *length;
struct gfc_charlen *next;
+ bool length_from_typespec; /* Length from explicit array ctor typespec? */
tree backend_decl;
int resolved;