[PATCH,fortran] Relax restrictions on KIND in SELECT CASE constructs
Steve Kargl
sgk@troutmask.apl.washington.edu
Sat Jan 1 21:24:00 GMT 2005
On Tue, Dec 28, 2004 at 11:09:02AM -0800, Steve Kargl wrote:
> On Mon, Dec 27, 2004 at 09:27:23AM -0800, Steve Kargl wrote:
> > On Mon, Dec 27, 2004 at 01:46:16PM +0000, Paul Brook wrote:
> > > > 2004-12-17 Steven G. Kargl <kargls@comcast.net>
> > > >
> > > > * resolve.c (validate_case_label_expr): Fix handling of mismatched
> > > > KINDs.
> > >
> > > No.
> >
> > Okay, I'll open a PR about this problem. I have no idea
> > how to fix this at the moment.
> >
>
> I just re-read Pauls original reply and I think his suggestion
> is incorrect with respect to 7.2.3 of the standard. I deleted
> his email so, I'm reproducing it here:
>
> > program foo
> > integer i
> > select case (i)
> > case (0_4)
> > case (1_8)
> > end select
> > end program
> >
> > Gives:
> >
> > SELECT CASE __convert_i4_i8[[((i))]]
> > CASE (0 0)
> > CASE (1_8 1_8)
> > END SELECT
> >
> > Which is obviously wrong.
> >
> > We should probably convert all cases to the type of the select
> > expression. Out of range values should either error, or warn
> > and remove that case.
>
> I think this is wrong because we need to convert "i == 1_8" to the
> KIND of i + 1_8 per 7.2.3, which has the kind of 1_8. The passage
> from the standard is
>
> In the numeric relational operation
> x1 rel-op x2
> if the types or kind type parameters of x1 and x2 differ, their values
> are converted to the type and kind type parameter of the expression
> x1 + x2 before evaluation.
>
> Since the conversion must be performed before evaluation, we may now
> conclude that in principle there are no out-of-range values. Note,
> this does not mean that certain cases are not unreachable. For example,
>
> integer*1 i ! kind = 1, -128 <= i < 127
> select case (i) ! need to convert i to kind = 4.
> case (1) ! kind = 4, reachable
> case (200) ! kind = 4, unreachable because of range of i
> end select
>
> The question becomes more complicated with a slight variation of
> Paul's example.
>
> integer*1 i ! kind = 1, -128 <= i < 127
> select case (i) !
> case (1_4) ! kind = 4, reachable
> case (2_8) ! kind = 8, reachable
> end select
>
> Do we convert i and 1_4 to kind = 8? Do we convert i to kind = 4
> in the comparison with 1_4 and convert it to kind = 8 in the
> comparison with 2_8? It is probably safe to convert everything to
> the largest kind, because the smaller kind are proper subsets
> of the larger kinds.
>
With the overwhelming support of the gfortran community,
I've implemented the first choice. The attached patch
is the result of this effort and the 3 additional test
case do what I expect. These test cases should be committed
along with the test cases posted here:
http://gcc.gnu.org/ml/fortran/2004-12/msg00260.html
This patch walks the list of case values/ranges and
adjusts the kind of case expression if needed. It
then adjusts the kind of the case/values/ranges
during validation. As per 7.2.3, no warning of the
kind conversion are necesssary, so I did not issue
any warnings.
Bootstrapped and regression tested on i386-*-freebsd6.0.
Additional test cases are provided.
Please commit.
2005-01-01 Steven G. Kargl <kargls@comcast.net>
PR 19168
*resolve.c (check_case_overlap): Typo in comment
(validate_case_label_expr): Fix up kinds of case values
(resolve_select): Properly handle kind mismatches.
--
Steve
-------------- next part --------------
Index: resolve.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/fortran/resolve.c,v
retrieving revision 1.24
diff -u -b -u -b -B -r1.24 resolve.c
--- resolve.c 15 Dec 2004 03:56:05 -0000 1.24
+++ resolve.c 1 Jan 2005 21:11:46 -0000
@@ -2614,7 +2579,7 @@
/* Count this merge. */
nmerges++;
- /* Cut the list in two pieces by steppin INSIZE places
+ /* Cut the list in two pieces by stepping INSIZE places
forward in the list, starting from P. */
psize = 0;
q = p;
@@ -2711,32 +2676,39 @@
}
-/* Check to see if an expression is suitable for use in a CASE
- statement. Makes sure that all case expressions are scalar
- constants of the same type/kind. Return FAILURE if anything
- is wrong. */
+/* Check to see if an expression is suitable for use in a CASE statement.
+ Makes sure that all case expressions are scalar constants of the same
+ type. Return FAILURE if anything is wrong. */
static try
validate_case_label_expr (gfc_expr * e, gfc_expr * case_expr)
{
- gfc_typespec case_ts = case_expr->ts;
if (e == NULL) return SUCCESS;
- if (e->ts.type != case_ts.type)
+ if (e->ts.type != case_expr->ts.type)
{
gfc_error ("Expression in CASE statement at %L must be of type %s",
- &e->where, gfc_basic_typename (case_ts.type));
+ &e->where, gfc_basic_typename (case_expr->ts.type));
return FAILURE;
}
- if (e->ts.kind != case_ts.kind)
+ /* C805 (R808) For a given case-construct, each case-value shall be of
+ the same type as case-expr. For character type, length differences
+ are allowed, but the kind type parameters shall be the same. */
+
+ if (case_expr->ts.type == BT_CHARACTER && e->ts.kind != case_expr->ts.kind)
{
gfc_error("Expression in CASE statement at %L must be kind %d",
- &e->where, case_ts.kind);
+ &e->where, case_expr->ts.kind);
return FAILURE;
}
+ /* Convert the case value kind to that of case expression kind, if needed.
+ FIXME: Should a warning be issued? */
+ if (e->ts.kind != case_expr->ts.kind)
+ gfc_convert_type_warn (e, &case_expr->ts, 2, 0);
+
if (e->rank != 0)
{
gfc_error ("Expression in CASE statement at %L must be scalar",
@@ -2819,6 +2791,40 @@
return;
}
+ /* PR 19168 has a long discussion concerning a mismatch of the kinds
+ of the SELECT CASE expression and its CASE values. Walk the lists
+ of case values, and if we find a mismatch, promote case_expr to
+ the appropriate kind. */
+
+ if (type == BT_LOGICAL || type == BT_INTEGER)
+ {
+ for (body = code->block; body; body = body->block)
+ {
+ /* Walk the case label list. */
+ for (cp = body->ext.case_list; cp; cp = cp->next)
+ {
+ /* Intercept the DEFAULT case. It does not have a kind. */
+ if (cp->low == NULL && cp->high == NULL)
+ continue;
+
+ /* Unreachable case ranges are discarded, so ignore. */
+ if (cp->low != NULL && cp->high != NULL
+ && cp->low != cp->high
+ && gfc_compare_expr (cp->low, cp->high) > 0)
+ continue;
+
+ /* FIXME: Should a warning be issued? */
+ if (cp->low != NULL
+ && case_expr->ts.kind != gfc_kind_max(case_expr, cp->low))
+ gfc_convert_type_warn (case_expr, &cp->low->ts, 2, 0);
+
+ if (cp->high != NULL
+ && case_expr->ts.kind != gfc_kind_max(case_expr, cp->high))
+ gfc_convert_type_warn (case_expr, &cp->high->ts, 2, 0);
+ }
+ }
+ }
+
/* Assume there is no DEFAULT case. */
default_case = NULL;
head = tail = NULL;
-------------- next part --------------
program select_7
integer*1 i ! kind = 1, -128 <= i < 127
do i = 1, 4
select case (i)
case (1_4) ! kind = 4, reachable
if (i /= 1_4) call abort
case (2_8) ! kind = 8, reachable
if (i /= 2_8) call abort
end select
end do
end program select_7
!
! Used with other Fortran 95 compilers
!
!subroutine abort
! print *, 'Abort'
! stop
!end subroutine abort
-------------- next part --------------
program select_8
integer*1 i ! kind = 1, -128 <= i < 127
do i = 1, 4
select case (i) ! need to convert i to kind = 4.
case (1) ! kind = 4, reachable
if (i /= 1) call abort
case (200) ! kind = 4, unreachable because of range of i
if (i /= 200) call abort
end select
end do
end program select_8
!
! Used with other Fortran 95 compilers
!
!subroutine abort
! print *, 'Abort'
! stop
!end subroutine abort
-------------- next part --------------
program select_9
integer i
do i = 1, 4
select case (i)
case (1_1)
if (i /= 1) call abort
case (2_2)
if (i /= 2) call abort
case (3)
if (i /= 3) call abort
case (4_8)
if (i /= 4) call abort
end select
end do
end program select_9
!
! Used with other Fortran 95 compilers
!
!subroutine abort
! print *, 'Abort'
! stop
!end subroutine abort
More information about the Fortran
mailing list