Blame SOURCES/0004-Allow-conversion-between-Hollerith-constants-and-CHA.patch

3db796
From 7420e95a0ebb2401d67ad405670fb6a8d33f02da Mon Sep 17 00:00:00 2001
3db796
From: Jim MacArthur <jim.macarthur@codethink.co.uk>
3db796
Date: Thu, 4 Feb 2016 17:18:30 +0000
3db796
Subject: [PATCH 04/23] Allow conversion between Hollerith constants and
3db796
 CHARACTER and INTEGER
3db796
3db796
Warnings are raised when this happens.
3db796
3db796
This feature is enabled with the `-std=extra-legacy` compiler flag.
3db796
3db796
        0004-Allow-conversion-between-Hollerith-constants-and-CHA.patch
3db796
3db796
diff --git a/gcc/fortran/arith.c b/gcc/fortran/arith.c
3db796
index 8fa305c..fc1be48 100644
3db796
--- a/gcc/fortran/arith.c
3db796
+++ b/gcc/fortran/arith.c
3db796
@@ -2514,7 +2514,7 @@ gfc_int2log (gfc_expr *src, int kind)
3db796
 }
3db796
 
3db796
 
3db796
-/* Helper function to set the representation in a Hollerith conversion.  
3db796
+/* Helper function to set the representation in a Hollerith conversion.
3db796
    This assumes that the ts.type and ts.kind of the result have already
3db796
    been set.  */
3db796
 
3db796
@@ -2545,6 +2545,34 @@ hollerith2representation (gfc_expr *result, gfc_expr *src)
3db796
 }
3db796
 
3db796
 
3db796
+/* Helper function to set the representation in a character conversion.
3db796
+   This assumes that the ts.type and ts.kind of the result have already
3db796
+   been set.  */
3db796
+
3db796
+static void
3db796
+character2representation (gfc_expr *result, gfc_expr *src)
3db796
+{
3db796
+  int src_len, result_len;
3db796
+  int i;
3db796
+  src_len = src->value.character.length;
3db796
+  result_len = gfc_target_expr_size (result);
3db796
+
3db796
+  if (src_len > result_len)
3db796
+    gfc_warning (0, "The character constant at %L is too long to convert to %s",
3db796
+		 &src->where, gfc_typename(&result->ts));
3db796
+
3db796
+  result->representation.string = XCNEWVEC (char, result_len + 1);
3db796
+
3db796
+  for (i = 0; i < MIN (result_len, src_len); i++)
3db796
+    result->representation.string[i] = (char) src->value.character.string[i];
3db796
+
3db796
+  if (src_len < result_len)
3db796
+    memset (&result->representation.string[src_len], ' ', result_len - src_len);
3db796
+
3db796
+  result->representation.string[result_len] = '\0'; /* For debugger  */
3db796
+  result->representation.length = result_len;
3db796
+}
3db796
+
3db796
 /* Convert Hollerith to integer. The constant will be padded or truncated.  */
3db796
 
3db796
 gfc_expr *
3db796
@@ -2560,6 +2588,19 @@ gfc_hollerith2int (gfc_expr *src, int kind)
3db796
   return result;
3db796
 }
3db796
 
3db796
+/* Convert character to integer. The constant will be padded or truncated. */
3db796
+
3db796
+gfc_expr *
3db796
+gfc_character2int (gfc_expr *src, int kind)
3db796
+{
3db796
+  gfc_expr *result;
3db796
+  result = gfc_get_constant_expr (BT_INTEGER, kind, &src->where);
3db796
+
3db796
+  character2representation (result, src);
3db796
+  gfc_interpret_integer (kind, (unsigned char *) result->representation.string,
3db796
+			 result->representation.length, result->value.integer);
3db796
+  return result;
3db796
+}
3db796
 
3db796
 /* Convert Hollerith to real. The constant will be padded or truncated.  */
3db796
 
3db796
diff --git a/gcc/fortran/arith.h b/gcc/fortran/arith.h
3db796
index 9c623a4..3cd663b 100644
3db796
--- a/gcc/fortran/arith.h
3db796
+++ b/gcc/fortran/arith.h
3db796
@@ -82,6 +82,7 @@ gfc_expr *gfc_hollerith2real (gfc_expr *, int);
3db796
 gfc_expr *gfc_hollerith2complex (gfc_expr *, int);
3db796
 gfc_expr *gfc_hollerith2character (gfc_expr *, int);
3db796
 gfc_expr *gfc_hollerith2logical (gfc_expr *, int);
3db796
+gfc_expr *gfc_character2int (gfc_expr *, int);
3db796
 
3db796
 #endif /* GFC_ARITH_H  */
3db796
 
3db796
diff --git a/gcc/fortran/check.c b/gcc/fortran/check.c
3db796
index 6e62d40..4f2d216 100644
3db796
--- a/gcc/fortran/check.c
3db796
+++ b/gcc/fortran/check.c
3db796
@@ -2544,9 +2544,14 @@ gfc_check_index (gfc_expr *string, gfc_expr *substring, gfc_expr *back,
3db796
 }
3db796
 
3db796
 
3db796
+/* This is the check function for the argument to the INT intrinsic */
3db796
 bool
3db796
 gfc_check_int (gfc_expr *x, gfc_expr *kind)
3db796
 {
3db796
+  if ((gfc_option.allow_std & GFC_STD_EXTRA_LEGACY)
3db796
+      && x->ts.type == BT_CHARACTER)
3db796
+    return true;
3db796
+
3db796
   if (!numeric_check (x, 0))
3db796
     return false;
3db796
 
3db796
diff --git a/gcc/fortran/intrinsic.c b/gcc/fortran/intrinsic.c
3db796
index 2f60fe8..371f5b8 100644
3db796
--- a/gcc/fortran/intrinsic.c
3db796
+++ b/gcc/fortran/intrinsic.c
3db796
@@ -3928,6 +3928,17 @@ add_conversions (void)
3db796
 	  add_conv (BT_LOGICAL, gfc_logical_kinds[j].kind,
3db796
 		    BT_INTEGER, gfc_integer_kinds[i].kind, GFC_STD_LEGACY);
3db796
 	}
3db796
+
3db796
+  /* Oracle allows character values to be converted to integers,
3db796
+     similar to Hollerith-Integer conversion - the first characters will
3db796
+     be turned into ascii values. */
3db796
+  if (gfc_option.allow_std & GFC_STD_EXTRA_LEGACY)
3db796
+    {
3db796
+      /* Character-Integer conversions.  */
3db796
+      for (i = 0; gfc_integer_kinds[i].kind != 0; i++)
3db796
+	add_conv (BT_CHARACTER, gfc_default_character_kind,
3db796
+		  BT_INTEGER, gfc_integer_kinds[i].kind, GFC_STD_LEGACY);
3db796
+    }
3db796
 }
3db796
 
3db796
 
3db796
@@ -5008,6 +5019,15 @@ gfc_convert_type_warn (gfc_expr *expr, gfc_typespec *ts, int eflag, int wflag)
3db796
 			     gfc_typename (&from_ts), gfc_typename (ts),
3db796
 			     &expr->where);
3db796
 	}
3db796
+      else if ((gfc_option.allow_std & GFC_STD_EXTRA_LEGACY)
3db796
+	       && from_ts.type == BT_CHARACTER
3db796
+	       && ts->type == BT_INTEGER)
3db796
+	{
3db796
+	  if (warn_conversion_extra || warn_conversion)
3db796
+	    gfc_warning_now (0, "Conversion from %s to %s at %L",
3db796
+			     gfc_typename (&from_ts), gfc_typename (ts),
3db796
+			     &expr->where);
3db796
+	}
3db796
       else
3db796
         gcc_unreachable ();
3db796
     }
3db796
diff --git a/gcc/fortran/resolve.c b/gcc/fortran/resolve.c
3db796
index 4bb88b4..84a4827 100644
3db796
--- a/gcc/fortran/resolve.c
3db796
+++ b/gcc/fortran/resolve.c
3db796
@@ -3615,6 +3615,30 @@ logical_to_bitwise (gfc_expr *e)
3db796
   return e;
3db796
 }
3db796
 
3db796
+/* Return true if TYPE is character based, false otherwise.  */
3db796
+
3db796
+static int
3db796
+is_character_based (bt type)
3db796
+{
3db796
+  return type == BT_CHARACTER || type == BT_HOLLERITH;
3db796
+}
3db796
+
3db796
+/* If E is a logical, convert it to an integer and issue a warning
3db796
+   for the conversion.  */
3db796
+
3db796
+static void
3db796
+convert_logical_to_integer (gfc_expr *e)
3db796
+{
3db796
+  if (e->ts.type == BT_LOGICAL)
3db796
+    {
3db796
+      /* Convert to INTEGER */
3db796
+      gfc_typespec t;
3db796
+      t.type = BT_INTEGER;
3db796
+      t.kind = 1;
3db796
+      gfc_convert_type_warn (e, &t, 2, 1);
3db796
+    }
3db796
+}
3db796
+
3db796
 /* Resolve an operator expression node.  This can involve replacing the
3db796
    operation with a user defined function call.  */
3db796
 
3db796
@@ -3781,6 +3805,38 @@ resolve_operator (gfc_expr *e)
3db796
     case INTRINSIC_EQ_OS:
3db796
     case INTRINSIC_NE:
3db796
     case INTRINSIC_NE_OS:
3db796
+
3db796
+      if (gfc_option.allow_std & GFC_STD_EXTRA_LEGACY)
3db796
+	{
3db796
+	  convert_logical_to_integer (op1);
3db796
+	  convert_logical_to_integer (op2);
3db796
+	}
3db796
+
3db796
+      /* If you're comparing hollerith contants to character expresisons,
3db796
+	 convert the hollerith constant */
3db796
+      if ((gfc_option.allow_std & GFC_STD_EXTRA_LEGACY)
3db796
+	  && is_character_based (op1->ts.type)
3db796
+	  && is_character_based (op2->ts.type))
3db796
+	{
3db796
+	  gfc_typespec ts;
3db796
+	  ts.type = BT_CHARACTER;
3db796
+	  ts.kind = op1->ts.kind;
3db796
+	  if (op1->ts.type == BT_HOLLERITH)
3db796
+	  {
3db796
+	    gfc_convert_type_warn (op1, &ts, 2, 1);
3db796
+	    gfc_warning (0, "Promoting argument for comparison from HOLLERITH "
3db796
+	                 "to CHARACTER at %L", &op1->where);
3db796
+	  }
3db796
+	  ts.type = BT_CHARACTER;
3db796
+	  ts.kind = op2->ts.kind;
3db796
+	  if (op2->ts.type == BT_HOLLERITH)
3db796
+	  {
3db796
+	    gfc_convert_type_warn (op2, &ts, 2, 1);
3db796
+	    gfc_warning (0, "Promoting argument for comparison from HOLLERITH "
3db796
+                         "to CHARACTER at %L", &op2->where);
3db796
+	  }
3db796
+	}
3db796
+
3db796
       if (op1->ts.type == BT_CHARACTER && op2->ts.type == BT_CHARACTER
3db796
 	  && op1->ts.kind == op2->ts.kind)
3db796
 	{
3db796
@@ -3789,6 +3845,29 @@ resolve_operator (gfc_expr *e)
3db796
 	  break;
3db796
 	}
3db796
 
3db796
+      /* Numeric to hollerith comparisons */
3db796
+      if ((gfc_option.allow_std & GFC_STD_EXTRA_LEGACY)
3db796
+	  && gfc_numeric_ts (&op1->ts)
3db796
+	  && (op2->ts.type == BT_HOLLERITH || op2->ts.type == BT_CHARACTER))
3db796
+	{
3db796
+	  gfc_warning (0, "Promoting argument for comparison from character type to INTEGER at %L", &op2->where);
3db796
+	  gfc_typespec ts;
3db796
+	  ts.type = BT_INTEGER;
3db796
+	  ts.kind = 4;
3db796
+	  gfc_convert_type_warn (op2, &ts, 2, 1);
3db796
+	}
3db796
+
3db796
+      if ((gfc_option.allow_std & GFC_STD_EXTRA_LEGACY)
3db796
+	  && gfc_numeric_ts (&op2->ts)
3db796
+	  && (op1->ts.type == BT_HOLLERITH || op1->ts.type == BT_CHARACTER))
3db796
+	{
3db796
+	  gfc_warning (0, "Promoting argument for comparison from character type to INTEGER at %L", &op1->where);
3db796
+	  gfc_typespec ts;
3db796
+	  ts.type = BT_INTEGER;
3db796
+	  ts.kind = 4;
3db796
+	  gfc_convert_type_warn (op1, &ts, 2, 1);
3db796
+	}
3db796
+
3db796
       if (gfc_numeric_ts (&op1->ts) && gfc_numeric_ts (&op2->ts))
3db796
 	{
3db796
 	  gfc_type_convert_binary (e, 1);
3db796
@@ -3985,7 +4064,6 @@ bad_op:
3db796
   return false;
3db796
 }
3db796
 
3db796
-
3db796
 /************** Array resolution subroutines **************/
3db796
 
3db796
 enum compare_result
3db796
diff --git a/gcc/fortran/simplify.c b/gcc/fortran/simplify.c
3db796
index 09da1d2..80c9637 100644
3db796
--- a/gcc/fortran/simplify.c
3db796
+++ b/gcc/fortran/simplify.c
3db796
@@ -7144,6 +7144,14 @@ gfc_convert_constant (gfc_expr *e, bt type, int kind)
3db796
 	}
3db796
       break;
3db796
 
3db796
+   case BT_CHARACTER:
3db796
+      if (type == BT_INTEGER)
3db796
+	{
3db796
+	  f = gfc_character2int;
3db796
+	  break;
3db796
+	}
3db796
+      goto oops;
3db796
+
3db796
     default:
3db796
     oops:
3db796
       gfc_internal_error ("gfc_convert_constant(): Unexpected type");
3db796
diff --git a/gcc/testsuite/gfortran.dg/hollerith-character-comparison.f90 b/gcc/testsuite/gfortran.dg/hollerith-character-comparison.f90
3db796
new file mode 100644
3db796
index 0000000..9c462b9
3db796
--- /dev/null
3db796
+++ b/gcc/testsuite/gfortran.dg/hollerith-character-comparison.f90
3db796
@@ -0,0 +1,15 @@
3db796
+       ! { dg-options "-std=extra-legacy" }
3db796
+
3db796
+      program convert
3db796
+      REAL*4 a
3db796
+      INTEGER*4 b
3db796
+      b = 1000
3db796
+      print *, 4HJMAC.eq.4HJMAC ! { dg-warning "Promoting argument for comparison from HOLLERITH to CHARACTER at" }
3db796
+      print *, 4HJMAC.eq."JMAC" ! { dg-warning "Promoting argument for comparison from HOLLERITH to CHARACTER at" }
3db796
+      print *, 4HJMAC.eq."JMAN" ! { dg-warning "Promoting argument for comparison from HOLLERITH to CHARACTER at" }
3db796
+      print *, "JMAC".eq.4HJMAN !  { dg-warning "Promoting argument for comparison from HOLLERITH to CHARACTER at" }
3db796
+      print *, "AAAA".eq.5HAAAAA ! { dg-warning "Promoting argument for comparison from HOLLERITH to CHARACTER at" }
3db796
+      print *, "BBBBB".eq.5HBBBB ! { dg-warning "Promoting argument for comparison from HOLLERITH to CHARACTER at" }
3db796
+
3db796
+      end program
3db796
+
3db796
diff --git a/gcc/testsuite/gfortran.dg/hollerith-int-comparison.f90 b/gcc/testsuite/gfortran.dg/hollerith-int-comparison.f90
3db796
new file mode 100644
3db796
index 0000000..f44c1f8
3db796
--- /dev/null
3db796
+++ b/gcc/testsuite/gfortran.dg/hollerith-int-comparison.f90
3db796
@@ -0,0 +1,11 @@
3db796
+       ! { dg-options "-std=extra-legacy" }
3db796
+
3db796
+      program convert
3db796
+      INTEGER*4 b
3db796
+      b = 5HRIVET ! { dg-warning "Legacy Extension: Hollerith constant|Conversion from HOLLERITH to INTEGER|too long to convert" }
3db796
+      print *, 4HJMAC.eq.400 ! { dg-warning "Legacy Extension: Hollerith constant|Promoting argument for comparison from character|Conversion from HOLLERITH to INTEGER" }
3db796
+      print *, 4HRIVE.eq.1163282770 ! { dg-warning "Legacy Extension: Hollerith constant|Promoting argument for comparison from character|Conversion from HOLLERITH to INTEGER" }
3db796
+      print *, b
3db796
+      print *, 1163282770.eq.4HRIVE ! { dg-warning "Legacy Extension: Hollerith constant|Promoting argument for comparison from character|Conversion from HOLLERITH to INTEGER" }
3db796
+      end program
3db796
+