OSDN Git Service

gcc/fortran/:
[pf3gnuchains/gcc-fork.git] / gcc / fortran / arith.c
index f92de48..1e90584 100644 (file)
@@ -1,5 +1,6 @@
 /* Compiler arithmetic
-   Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
+   Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+   2009, 2010
    Free Software Foundation, Inc.
    Contributed by Andy Vaught
 
@@ -7,7 +8,7 @@ This file is part of GCC.
 
 GCC is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 2, or (at your option) any later
+Software Foundation; either version 3, or (at your option) any later
 version.
 
 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
@@ -16,9 +17,8 @@ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 for more details.
 
 You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING.  If not, write to the Free
-Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
-02110-1301, USA.  */
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
 
 /* Since target arithmetic must be done on the host, there has to
    be some way of evaluating arithmetic expressions as the host
@@ -30,20 +30,26 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
 #include "flags.h"
 #include "gfortran.h"
 #include "arith.h"
+#include "target-memory.h"
+#include "constructor.h"
 
 /* MPFR does not have a direct replacement for mpz_set_f() from GMP.
    It's easily implemented with a few calls though.  */
 
 void
-gfc_mpfr_to_mpz (mpz_t z, mpfr_t x)
+gfc_mpfr_to_mpz (mpz_t z, mpfr_t x, locus *where)
 {
   mp_exp_t e;
 
+  if (mpfr_inf_p (x) || mpfr_nan_p (x))
+    {
+      gfc_error ("Conversion of an Infinity or Not-a-Number at %L "
+                "to INTEGER", where);
+      mpz_set_ui (z, 0);
+      return;
+    }
+
   e = mpfr_get_z_exp (z, x);
-  /* MPFR 2.0.1 (included with GMP 4.1) has a bug whereby mpfr_get_z_exp
-     may set the sign of z incorrectly.  Work around that here.  */
-  if (mpfr_sgn (x) != mpz_sgn (z))
-    mpz_neg (z, z);
 
   if (e > 0)
     mpz_mul_2exp (z, z, e);
@@ -123,24 +129,21 @@ gfc_arith_init_1 (void)
 {
   gfc_integer_info *int_info;
   gfc_real_info *real_info;
-  mpfr_t a, b, c;
-  mpz_t r;
+  mpfr_t a, b;
   int i;
 
   mpfr_set_default_prec (128);
   mpfr_init (a);
-  mpz_init (r);
 
   /* Convert the minimum and maximum values for each kind into their
      GNU MP representation.  */
   for (int_info = gfc_integer_kinds; int_info->kind != 0; int_info++)
     {
       /* Huge  */
-      mpz_set_ui (r, int_info->radix);
-      mpz_pow_ui (r, r, int_info->digits);
-
       mpz_init (int_info->huge);
-      mpz_sub_ui (int_info->huge, r, 1);
+      mpz_set_ui (int_info->huge, int_info->radix);
+      mpz_pow_ui (int_info->huge, int_info->huge, int_info->digits);
+      mpz_sub_ui (int_info->huge, int_info->huge, 1);
 
       /* These are the numbers that are actually representable by the
         target.  For bases other than two, this needs to be changed.  */
@@ -164,8 +167,7 @@ gfc_arith_init_1 (void)
       mpfr_set_z (a, int_info->huge, GFC_RND_MODE);
       mpfr_log10 (a, a, GFC_RND_MODE);
       mpfr_trunc (a, a);
-      gfc_mpfr_to_mpz (r, a);
-      int_info->range = mpz_get_si (r);
+      int_info->range = (int) mpfr_get_si (a, GFC_RND_MODE);
     }
 
   mpfr_clear (a);
@@ -176,49 +178,43 @@ gfc_arith_init_1 (void)
 
       mpfr_init (a);
       mpfr_init (b);
-      mpfr_init (c);
 
       /* huge(x) = (1 - b**(-p)) * b**(emax-1) * b  */
-      /* a = 1 - b**(-p)  */
-      mpfr_set_ui (a, 1, GFC_RND_MODE);
-      mpfr_set_ui (b, real_info->radix, GFC_RND_MODE);
-      mpfr_pow_si (b, b, -real_info->digits, GFC_RND_MODE);
-      mpfr_sub (a, a, b, GFC_RND_MODE);
-
-      /* c = b**(emax-1)  */
-      mpfr_set_ui (b, real_info->radix, GFC_RND_MODE);
-      mpfr_pow_ui (c, b, real_info->max_exponent - 1, GFC_RND_MODE);
+      /* 1 - b**(-p)  */
+      mpfr_init (real_info->huge);
+      mpfr_set_ui (real_info->huge, 1, GFC_RND_MODE);
+      mpfr_set_ui (a, real_info->radix, GFC_RND_MODE);
+      mpfr_pow_si (a, a, -real_info->digits, GFC_RND_MODE);
+      mpfr_sub (real_info->huge, real_info->huge, a, GFC_RND_MODE);
 
-      /* a = a * c = (1 - b**(-p)) * b**(emax-1)  */
-      mpfr_mul (a, a, c, GFC_RND_MODE);
+      /* b**(emax-1)  */
+      mpfr_set_ui (a, real_info->radix, GFC_RND_MODE);
+      mpfr_pow_ui (a, a, real_info->max_exponent - 1, GFC_RND_MODE);
 
-      /* a = (1 - b**(-p)) * b**(emax-1) * b  */
-      mpfr_mul_ui (a, a, real_info->radix, GFC_RND_MODE);
+      /* (1 - b**(-p)) * b**(emax-1)  */
+      mpfr_mul (real_info->huge, real_info->huge, a, GFC_RND_MODE);
 
-      mpfr_init (real_info->huge);
-      mpfr_set (real_info->huge, a, GFC_RND_MODE);
+      /* (1 - b**(-p)) * b**(emax-1) * b  */
+      mpfr_mul_ui (real_info->huge, real_info->huge, real_info->radix,
+                  GFC_RND_MODE);
 
       /* tiny(x) = b**(emin-1)  */
-      mpfr_set_ui (b, real_info->radix, GFC_RND_MODE);
-      mpfr_pow_si (b, b, real_info->min_exponent - 1, GFC_RND_MODE);
-
       mpfr_init (real_info->tiny);
-      mpfr_set (real_info->tiny, b, GFC_RND_MODE);
+      mpfr_set_ui (real_info->tiny, real_info->radix, GFC_RND_MODE);
+      mpfr_pow_si (real_info->tiny, real_info->tiny,
+                  real_info->min_exponent - 1, GFC_RND_MODE);
 
       /* subnormal (x) = b**(emin - digit)  */
-      mpfr_set_ui (b, real_info->radix, GFC_RND_MODE);
-      mpfr_pow_si (b, b, real_info->min_exponent - real_info->digits,
-                  GFC_RND_MODE);
-
       mpfr_init (real_info->subnormal);
-      mpfr_set (real_info->subnormal, b, GFC_RND_MODE);
+      mpfr_set_ui (real_info->subnormal, real_info->radix, GFC_RND_MODE);
+      mpfr_pow_si (real_info->subnormal, real_info->subnormal,
+                  real_info->min_exponent - real_info->digits, GFC_RND_MODE);
 
       /* epsilon(x) = b**(1-p)  */
-      mpfr_set_ui (b, real_info->radix, GFC_RND_MODE);
-      mpfr_pow_si (b, b, 1 - real_info->digits, GFC_RND_MODE);
-
       mpfr_init (real_info->epsilon);
-      mpfr_set (real_info->epsilon, b, GFC_RND_MODE);
+      mpfr_set_ui (real_info->epsilon, real_info->radix, GFC_RND_MODE);
+      mpfr_pow_si (real_info->epsilon, real_info->epsilon,
+                  1 - real_info->digits, GFC_RND_MODE);
 
       /* range(x) = int(min(log10(huge(x)), -log10(tiny))  */
       mpfr_log10 (a, real_info->huge, GFC_RND_MODE);
@@ -226,33 +222,24 @@ gfc_arith_init_1 (void)
       mpfr_neg (b, b, GFC_RND_MODE);
 
       /* a = min(a, b)  */
-      if (mpfr_cmp (a, b) > 0)
-       mpfr_set (a, b, GFC_RND_MODE);
-
+      mpfr_min (a, a, b, GFC_RND_MODE);
       mpfr_trunc (a, a);
-      gfc_mpfr_to_mpz (r, a);
-      real_info->range = mpz_get_si (r);
+      real_info->range = (int) mpfr_get_si (a, GFC_RND_MODE);
 
       /* precision(x) = int((p - 1) * log10(b)) + k  */
       mpfr_set_ui (a, real_info->radix, GFC_RND_MODE);
       mpfr_log10 (a, a, GFC_RND_MODE);
-
       mpfr_mul_ui (a, a, real_info->digits - 1, GFC_RND_MODE);
       mpfr_trunc (a, a);
-      gfc_mpfr_to_mpz (r, a);
-      real_info->precision = mpz_get_si (r);
+      real_info->precision = (int) mpfr_get_si (a, GFC_RND_MODE);
 
       /* If the radix is an integral power of 10, add one to the precision.  */
       for (i = 10; i <= real_info->radix; i *= 10)
        if (i == real_info->radix)
          real_info->precision++;
 
-      mpfr_clear (a);
-      mpfr_clear (b);
-      mpfr_clear (c);
+      mpfr_clears (a, b, NULL);
     }
-
-  mpz_clear (r);
 }
 
 
@@ -272,12 +259,24 @@ gfc_arith_done_1 (void)
     }
 
   for (rp = gfc_real_kinds; rp->kind; rp++)
-    {
-      mpfr_clear (rp->epsilon);
-      mpfr_clear (rp->huge);
-      mpfr_clear (rp->tiny);
-      mpfr_clear (rp->subnormal);
-    }
+    mpfr_clears (rp->epsilon, rp->huge, rp->tiny, rp->subnormal, NULL);
+}
+
+
+/* Given a wide character value and a character kind, determine whether
+   the character is representable for that kind.  */
+bool
+gfc_check_character_range (gfc_char_t c, int kind)
+{
+  /* As wide characters are stored as 32-bit values, they're all
+     representable in UCS=4.  */
+  if (kind == 4)
+    return true;
+
+  if (kind == 1)
+    return c <= 255 ? true : false;
+
+  gcc_unreachable ();
 }
 
 
@@ -329,33 +328,43 @@ gfc_check_real_range (mpfr_t p, int kind)
   mpfr_init (q);
   mpfr_abs (q, p, GFC_RND_MODE);
 
+  retval = ARITH_OK;
+
   if (mpfr_inf_p (p))
     {
-      if (gfc_option.flag_range_check == 0)
-       retval = ARITH_OK;
-      else
+      if (gfc_option.flag_range_check != 0)
        retval = ARITH_OVERFLOW;
     }
   else if (mpfr_nan_p (p))
     {
-      if (gfc_option.flag_range_check == 0)
-       retval = ARITH_OK;
-      else
+      if (gfc_option.flag_range_check != 0)
        retval = ARITH_NAN;
     }
   else if (mpfr_sgn (q) == 0)
-    retval = ARITH_OK;
+    {
+      mpfr_clear (q);
+      return retval;
+    }
   else if (mpfr_cmp (q, gfc_real_kinds[i].huge) > 0)
     {
       if (gfc_option.flag_range_check == 0)
-       retval = ARITH_OK;
+       mpfr_set_inf (p, mpfr_sgn (p));
       else
        retval = ARITH_OVERFLOW;
     }
   else if (mpfr_cmp (q, gfc_real_kinds[i].subnormal) < 0)
     {
       if (gfc_option.flag_range_check == 0)
-       retval = ARITH_OK;
+       {
+         if (mpfr_sgn (p) < 0)
+           {
+             mpfr_set_ui (p, 0, GFC_RND_MODE);
+             mpfr_set_si (q, -1, GFC_RND_MODE);
+             mpfr_copysign (p, p, q, GFC_RND_MODE);
+           }
+         else
+           mpfr_set_ui (p, 0, GFC_RND_MODE);
+       }
       else
        retval = ARITH_UNDERFLOW;
     }
@@ -372,6 +381,7 @@ gfc_check_real_range (mpfr_t p, int kind)
       en = gfc_real_kinds[i].min_exponent - gfc_real_kinds[i].digits + 1;
       mpfr_set_emin ((mp_exp_t) en);
       mpfr_set_emax ((mp_exp_t) gfc_real_kinds[i].max_exponent);
+      mpfr_check_range (q, 0, GFC_RND_MODE);
       mpfr_subnormalize (q, 0, GFC_RND_MODE);
 
       /* Reset emin and emax.  */
@@ -383,11 +393,7 @@ gfc_check_real_range (mpfr_t p, int kind)
        mpfr_neg (p, q, GMP_RNDN);
       else
        mpfr_set (p, q, GMP_RNDN);
-
-      retval = ARITH_OK;
     }
-  else
-    retval = ARITH_OK;
 
   mpfr_clear (q);
 
@@ -395,48 +401,6 @@ gfc_check_real_range (mpfr_t p, int kind)
 }
 
 
-/* Function to return a constant expression node of a given type and kind.  */
-
-gfc_expr *
-gfc_constant_result (bt type, int kind, locus *where)
-{
-  gfc_expr *result;
-
-  if (!where)
-    gfc_internal_error ("gfc_constant_result(): locus 'where' cannot be NULL");
-
-  result = gfc_get_expr ();
-
-  result->expr_type = EXPR_CONSTANT;
-  result->ts.type = type;
-  result->ts.kind = kind;
-  result->where = *where;
-
-  switch (type)
-    {
-    case BT_INTEGER:
-      mpz_init (result->value.integer);
-      break;
-
-    case BT_REAL:
-      gfc_set_model_kind (kind);
-      mpfr_init (result->value.real);
-      break;
-
-    case BT_COMPLEX:
-      gfc_set_model_kind (kind);
-      mpfr_init (result->value.complex.r);
-      mpfr_init (result->value.complex.i);
-      break;
-
-    default:
-      break;
-    }
-
-  return result;
-}
-
-
 /* Low-level arithmetic functions.  All of these subroutines assume
    that all operands are of the same type and return an operand of the
    same type.  The other thing about these subroutines is that they
@@ -448,7 +412,7 @@ gfc_arith_not (gfc_expr *op1, gfc_expr **resultp)
 {
   gfc_expr *result;
 
-  result = gfc_constant_result (BT_LOGICAL, op1->ts.kind, &op1->where);
+  result = gfc_get_constant_expr (BT_LOGICAL, op1->ts.kind, &op1->where);
   result->value.logical = !op1->value.logical;
   *resultp = result;
 
@@ -461,8 +425,8 @@ gfc_arith_and (gfc_expr *op1, gfc_expr *op2, gfc_expr **resultp)
 {
   gfc_expr *result;
 
-  result = gfc_constant_result (BT_LOGICAL, gfc_kind_max (op1, op2),
-                               &op1->where);
+  result = gfc_get_constant_expr (BT_LOGICAL, gfc_kind_max (op1, op2),
+                                 &op1->where);
   result->value.logical = op1->value.logical && op2->value.logical;
   *resultp = result;
 
@@ -475,8 +439,8 @@ gfc_arith_or (gfc_expr *op1, gfc_expr *op2, gfc_expr **resultp)
 {
   gfc_expr *result;
 
-  result = gfc_constant_result (BT_LOGICAL, gfc_kind_max (op1, op2),
-                               &op1->where);
+  result = gfc_get_constant_expr (BT_LOGICAL, gfc_kind_max (op1, op2),
+                                 &op1->where);
   result->value.logical = op1->value.logical || op2->value.logical;
   *resultp = result;
 
@@ -489,8 +453,8 @@ gfc_arith_eqv (gfc_expr *op1, gfc_expr *op2, gfc_expr **resultp)
 {
   gfc_expr *result;
 
-  result = gfc_constant_result (BT_LOGICAL, gfc_kind_max (op1, op2),
-                               &op1->where);
+  result = gfc_get_constant_expr (BT_LOGICAL, gfc_kind_max (op1, op2),
+                                 &op1->where);
   result->value.logical = op1->value.logical == op2->value.logical;
   *resultp = result;
 
@@ -503,8 +467,8 @@ gfc_arith_neqv (gfc_expr *op1, gfc_expr *op2, gfc_expr **resultp)
 {
   gfc_expr *result;
 
-  result = gfc_constant_result (BT_LOGICAL, gfc_kind_max (op1, op2),
-                               &op1->where);
+  result = gfc_get_constant_expr (BT_LOGICAL, gfc_kind_max (op1, op2),
+                                 &op1->where);
   result->value.logical = op1->value.logical != op2->value.logical;
   *resultp = result;
 
@@ -520,6 +484,7 @@ arith
 gfc_range_check (gfc_expr *e)
 {
   arith rc;
+  arith rc2;
 
   switch (e->ts.type)
     {
@@ -538,21 +503,26 @@ gfc_range_check (gfc_expr *e)
       break;
 
     case BT_COMPLEX:
-      rc = gfc_check_real_range (e->value.complex.r, e->ts.kind);
+      rc = gfc_check_real_range (mpc_realref (e->value.complex), e->ts.kind);
       if (rc == ARITH_UNDERFLOW)
-       mpfr_set_ui (e->value.complex.r, 0, GFC_RND_MODE);
+       mpfr_set_ui (mpc_realref (e->value.complex), 0, GFC_RND_MODE);
       if (rc == ARITH_OVERFLOW)
-       mpfr_set_inf (e->value.complex.r, mpfr_sgn (e->value.complex.r));
+       mpfr_set_inf (mpc_realref (e->value.complex),
+                     mpfr_sgn (mpc_realref (e->value.complex)));
       if (rc == ARITH_NAN)
-       mpfr_set_nan (e->value.complex.r);
+       mpfr_set_nan (mpc_realref (e->value.complex));
 
-      rc = gfc_check_real_range (e->value.complex.i, e->ts.kind);
+      rc2 = gfc_check_real_range (mpc_imagref (e->value.complex), e->ts.kind);
       if (rc == ARITH_UNDERFLOW)
-       mpfr_set_ui (e->value.complex.i, 0, GFC_RND_MODE);
+       mpfr_set_ui (mpc_imagref (e->value.complex), 0, GFC_RND_MODE);
       if (rc == ARITH_OVERFLOW)
-       mpfr_set_inf (e->value.complex.i, mpfr_sgn (e->value.complex.i));
+       mpfr_set_inf (mpc_imagref (e->value.complex), 
+                     mpfr_sgn (mpc_imagref (e->value.complex)));
       if (rc == ARITH_NAN)
-       mpfr_set_nan (e->value.complex.i);
+       mpfr_set_nan (mpc_imagref (e->value.complex));
+
+      if (rc == ARITH_OK)
+       rc = rc2;
       break;
 
     default:
@@ -595,10 +565,11 @@ check_result (arith rc, gfc_expr *x, gfc_expr *r, gfc_expr **rp)
 
 /* It may seem silly to have a subroutine that actually computes the
    unary plus of a constant, but it prevents us from making exceptions
-   in the code elsewhere.  */
+   in the code elsewhere.  Used for unary plus and parenthesized
+   expressions.  */
 
 static arith
-gfc_arith_uplus (gfc_expr *op1, gfc_expr **resultp)
+gfc_arith_identity (gfc_expr *op1, gfc_expr **resultp)
 {
   *resultp = gfc_copy_expr (op1);
   return ARITH_OK;
@@ -611,7 +582,7 @@ gfc_arith_uminus (gfc_expr *op1, gfc_expr **resultp)
   gfc_expr *result;
   arith rc;
 
-  result = gfc_constant_result (op1->ts.type, op1->ts.kind, &op1->where);
+  result = gfc_get_constant_expr (op1->ts.type, op1->ts.kind, &op1->where);
 
   switch (op1->ts.type)
     {
@@ -624,8 +595,7 @@ gfc_arith_uminus (gfc_expr *op1, gfc_expr **resultp)
       break;
 
     case BT_COMPLEX:
-      mpfr_neg (result->value.complex.r, op1->value.complex.r, GFC_RND_MODE);
-      mpfr_neg (result->value.complex.i, op1->value.complex.i, GFC_RND_MODE);
+      mpc_neg (result->value.complex, op1->value.complex, GFC_MPC_RND_MODE);
       break;
 
     default:
@@ -644,7 +614,7 @@ gfc_arith_plus (gfc_expr *op1, gfc_expr *op2, gfc_expr **resultp)
   gfc_expr *result;
   arith rc;
 
-  result = gfc_constant_result (op1->ts.type, op1->ts.kind, &op1->where);
+  result = gfc_get_constant_expr (op1->ts.type, op1->ts.kind, &op1->where);
 
   switch (op1->ts.type)
     {
@@ -658,11 +628,8 @@ gfc_arith_plus (gfc_expr *op1, gfc_expr *op2, gfc_expr **resultp)
       break;
 
     case BT_COMPLEX:
-      mpfr_add (result->value.complex.r, op1->value.complex.r,
-               op2->value.complex.r, GFC_RND_MODE);
-
-      mpfr_add (result->value.complex.i, op1->value.complex.i,
-               op2->value.complex.i, GFC_RND_MODE);
+      mpc_add (result->value.complex, op1->value.complex, op2->value.complex,
+              GFC_MPC_RND_MODE);
       break;
 
     default:
@@ -681,7 +648,7 @@ gfc_arith_minus (gfc_expr *op1, gfc_expr *op2, gfc_expr **resultp)
   gfc_expr *result;
   arith rc;
 
-  result = gfc_constant_result (op1->ts.type, op1->ts.kind, &op1->where);
+  result = gfc_get_constant_expr (op1->ts.type, op1->ts.kind, &op1->where);
 
   switch (op1->ts.type)
     {
@@ -695,11 +662,8 @@ gfc_arith_minus (gfc_expr *op1, gfc_expr *op2, gfc_expr **resultp)
       break;
 
     case BT_COMPLEX:
-      mpfr_sub (result->value.complex.r, op1->value.complex.r,
-               op2->value.complex.r, GFC_RND_MODE);
-
-      mpfr_sub (result->value.complex.i, op1->value.complex.i,
-               op2->value.complex.i, GFC_RND_MODE);
+      mpc_sub (result->value.complex, op1->value.complex,
+              op2->value.complex, GFC_MPC_RND_MODE);
       break;
 
     default:
@@ -716,10 +680,9 @@ static arith
 gfc_arith_times (gfc_expr *op1, gfc_expr *op2, gfc_expr **resultp)
 {
   gfc_expr *result;
-  mpfr_t x, y;
   arith rc;
 
-  result = gfc_constant_result (op1->ts.type, op1->ts.kind, &op1->where);
+  result = gfc_get_constant_expr (op1->ts.type, op1->ts.kind, &op1->where);
 
   switch (op1->ts.type)
     {
@@ -733,20 +696,9 @@ gfc_arith_times (gfc_expr *op1, gfc_expr *op2, gfc_expr **resultp)
       break;
 
     case BT_COMPLEX:
-      gfc_set_model (op1->value.complex.r);
-      mpfr_init (x);
-      mpfr_init (y);
-
-      mpfr_mul (x, op1->value.complex.r, op2->value.complex.r, GFC_RND_MODE);
-      mpfr_mul (y, op1->value.complex.i, op2->value.complex.i, GFC_RND_MODE);
-      mpfr_sub (result->value.complex.r, x, y, GFC_RND_MODE);
-
-      mpfr_mul (x, op1->value.complex.r, op2->value.complex.i, GFC_RND_MODE);
-      mpfr_mul (y, op1->value.complex.i, op2->value.complex.r, GFC_RND_MODE);
-      mpfr_add (result->value.complex.i, x, y, GFC_RND_MODE);
-
-      mpfr_clear (x);
-      mpfr_clear (y);
+      gfc_set_model (mpc_realref (op1->value.complex));
+      mpc_mul (result->value.complex, op1->value.complex, op2->value.complex,
+              GFC_MPC_RND_MODE);
       break;
 
     default:
@@ -763,12 +715,11 @@ static arith
 gfc_arith_divide (gfc_expr *op1, gfc_expr *op2, gfc_expr **resultp)
 {
   gfc_expr *result;
-  mpfr_t x, y, div;
   arith rc;
 
   rc = ARITH_OK;
 
-  result = gfc_constant_result (op1->ts.type, op1->ts.kind, &op1->where);
+  result = gfc_get_constant_expr (op1->ts.type, op1->ts.kind, &op1->where);
 
   switch (op1->ts.type)
     {
@@ -795,38 +746,24 @@ gfc_arith_divide (gfc_expr *op1, gfc_expr *op2, gfc_expr **resultp)
       break;
 
     case BT_COMPLEX:
-      if (mpfr_sgn (op2->value.complex.r) == 0
-         && mpfr_sgn (op2->value.complex.i) == 0
+      if (mpc_cmp_si_si (op2->value.complex, 0, 0) == 0
          && gfc_option.flag_range_check == 1)
        {
          rc = ARITH_DIV0;
          break;
        }
 
-      gfc_set_model (op1->value.complex.r);
-      mpfr_init (x);
-      mpfr_init (y);
-      mpfr_init (div);
-
-      mpfr_mul (x, op2->value.complex.r, op2->value.complex.r, GFC_RND_MODE);
-      mpfr_mul (y, op2->value.complex.i, op2->value.complex.i, GFC_RND_MODE);
-      mpfr_add (div, x, y, GFC_RND_MODE);
-
-      mpfr_mul (x, op1->value.complex.r, op2->value.complex.r, GFC_RND_MODE);
-      mpfr_mul (y, op1->value.complex.i, op2->value.complex.i, GFC_RND_MODE);
-      mpfr_add (result->value.complex.r, x, y, GFC_RND_MODE);
-      mpfr_div (result->value.complex.r, result->value.complex.r, div,
-               GFC_RND_MODE);
-
-      mpfr_mul (x, op1->value.complex.i, op2->value.complex.r, GFC_RND_MODE);
-      mpfr_mul (y, op1->value.complex.r, op2->value.complex.i, GFC_RND_MODE);
-      mpfr_sub (result->value.complex.i, x, y, GFC_RND_MODE);
-      mpfr_div (result->value.complex.i, result->value.complex.i, div,
-               GFC_RND_MODE);
-
-      mpfr_clear (x);
-      mpfr_clear (y);
-      mpfr_clear (div);
+      gfc_set_model (mpc_realref (op1->value.complex));
+      if (mpc_cmp_si_si (op2->value.complex, 0, 0) == 0)
+      {
+       /* In Fortran, return (NaN + NaN I) for any zero divisor.  See
+          PR 40318. */
+       mpfr_set_nan (mpc_realref (result->value.complex));
+       mpfr_set_nan (mpc_imagref (result->value.complex));
+      }
+      else
+       mpc_div (result->value.complex, op1->value.complex, op2->value.complex,
+                GFC_MPC_RND_MODE);
       break;
 
     default:
@@ -839,164 +776,164 @@ gfc_arith_divide (gfc_expr *op1, gfc_expr *op2, gfc_expr **resultp)
   return check_result (rc, op1, result, resultp);
 }
 
-
-/* Compute the reciprocal of a complex number (guaranteed nonzero).  */
-
-static void
-complex_reciprocal (gfc_expr *op)
-{
-  mpfr_t mod, a, re, im;
-
-  gfc_set_model (op->value.complex.r);
-  mpfr_init (mod);
-  mpfr_init (a);
-  mpfr_init (re);
-  mpfr_init (im);
-
-  mpfr_mul (mod, op->value.complex.r, op->value.complex.r, GFC_RND_MODE);
-  mpfr_mul (a, op->value.complex.i, op->value.complex.i, GFC_RND_MODE);
-  mpfr_add (mod, mod, a, GFC_RND_MODE);
-
-  mpfr_div (re, op->value.complex.r, mod, GFC_RND_MODE);
-
-  mpfr_neg (im, op->value.complex.i, GFC_RND_MODE);
-  mpfr_div (im, im, mod, GFC_RND_MODE);
-
-  mpfr_set (op->value.complex.r, re, GFC_RND_MODE);
-  mpfr_set (op->value.complex.i, im, GFC_RND_MODE);
-
-  mpfr_clear (re);
-  mpfr_clear (im);
-  mpfr_clear (mod);
-  mpfr_clear (a);
-}
-
-
-/* Raise a complex number to positive power.  */
-
-static void
-complex_pow_ui (gfc_expr *base, int power, gfc_expr *result)
-{
-  mpfr_t re, im, a;
-
-  gfc_set_model (base->value.complex.r);
-  mpfr_init (re);
-  mpfr_init (im);
-  mpfr_init (a);
-
-  mpfr_set_ui (result->value.complex.r, 1, GFC_RND_MODE);
-  mpfr_set_ui (result->value.complex.i, 0, GFC_RND_MODE);
-
-  for (; power > 0; power--)
-    {
-      mpfr_mul (re, base->value.complex.r, result->value.complex.r,
-               GFC_RND_MODE);
-      mpfr_mul (a, base->value.complex.i, result->value.complex.i,
-               GFC_RND_MODE);
-      mpfr_sub (re, re, a, GFC_RND_MODE);
-
-      mpfr_mul (im, base->value.complex.r, result->value.complex.i,
-               GFC_RND_MODE);
-      mpfr_mul (a, base->value.complex.i, result->value.complex.r,
-               GFC_RND_MODE);
-      mpfr_add (im, im, a, GFC_RND_MODE);
-
-      mpfr_set (result->value.complex.r, re, GFC_RND_MODE);
-      mpfr_set (result->value.complex.i, im, GFC_RND_MODE);
-    }
-
-  mpfr_clear (re);
-  mpfr_clear (im);
-  mpfr_clear (a);
-}
-
-
-/* Raise a number to an integer power.  */
+/* Raise a number to a power.  */
 
 static arith
-gfc_arith_power (gfc_expr *op1, gfc_expr *op2, gfc_expr **resultp)
+arith_power (gfc_expr *op1, gfc_expr *op2, gfc_expr **resultp)
 {
-  int power, apower;
+  int power_sign;
   gfc_expr *result;
-  mpz_t unity_z;
-  mpfr_t unity_f;
   arith rc;
 
   rc = ARITH_OK;
+  result = gfc_get_constant_expr (op1->ts.type, op1->ts.kind, &op1->where);
 
-  if (gfc_extract_int (op2, &power) != NULL)
-    gfc_internal_error ("gfc_arith_power(): Bad exponent");
-
-  result = gfc_constant_result (op1->ts.type, op1->ts.kind, &op1->where);
-
-  if (power == 0)
+  switch (op2->ts.type)
     {
-      /* Handle something to the zeroth power.  Since we're dealing
-        with integral exponents, there is no ambiguity in the
-        limiting procedure used to determine the value of 0**0.  */
-      switch (op1->ts.type)
+    case BT_INTEGER:
+      power_sign = mpz_sgn (op2->value.integer);
+
+      if (power_sign == 0)
        {
-       case BT_INTEGER:
-         mpz_set_ui (result->value.integer, 1);
-         break;
+         /* Handle something to the zeroth power.  Since we're dealing
+            with integral exponents, there is no ambiguity in the
+            limiting procedure used to determine the value of 0**0.  */
+         switch (op1->ts.type)
+           {
+           case BT_INTEGER:
+             mpz_set_ui (result->value.integer, 1);
+             break;
 
-       case BT_REAL:
-         mpfr_set_ui (result->value.real, 1, GFC_RND_MODE);
-         break;
+           case BT_REAL:
+             mpfr_set_ui (result->value.real, 1, GFC_RND_MODE);
+             break;
 
-       case BT_COMPLEX:
-         mpfr_set_ui (result->value.complex.r, 1, GFC_RND_MODE);
-         mpfr_set_ui (result->value.complex.i, 0, GFC_RND_MODE);
-         break;
+           case BT_COMPLEX:
+             mpc_set_ui (result->value.complex, 1, GFC_MPC_RND_MODE);
+             break;
 
-       default:
-         gfc_internal_error ("gfc_arith_power(): Bad base");
+           default:
+             gfc_internal_error ("arith_power(): Bad base");
+           }
        }
-    }
-  else
-    {
-      apower = power;
-      if (power < 0)
-       apower = -power;
-
-      switch (op1->ts.type)
+      else
        {
-       case BT_INTEGER:
-         mpz_pow_ui (result->value.integer, op1->value.integer, apower);
-
-         if (power < 0)
+         switch (op1->ts.type)
            {
-             mpz_init_set_ui (unity_z, 1);
-             mpz_tdiv_q (result->value.integer, unity_z,
-                         result->value.integer);
-             mpz_clear (unity_z);
-           }
-         break;
+           case BT_INTEGER:
+             {
+               int power;
+
+               /* First, we simplify the cases of op1 == 1, 0 or -1.  */
+               if (mpz_cmp_si (op1->value.integer, 1) == 0)
+                 {
+                   /* 1**op2 == 1 */
+                   mpz_set_si (result->value.integer, 1);
+                 }
+               else if (mpz_cmp_si (op1->value.integer, 0) == 0)
+                 {
+                   /* 0**op2 == 0, if op2 > 0
+                      0**op2 overflow, if op2 < 0 ; in that case, we
+                      set the result to 0 and return ARITH_DIV0.  */
+                   mpz_set_si (result->value.integer, 0);
+                   if (mpz_cmp_si (op2->value.integer, 0) < 0)
+                     rc = ARITH_DIV0;
+                 }
+               else if (mpz_cmp_si (op1->value.integer, -1) == 0)
+                 {
+                   /* (-1)**op2 == (-1)**(mod(op2,2)) */
+                   unsigned int odd = mpz_fdiv_ui (op2->value.integer, 2);
+                   if (odd)
+                     mpz_set_si (result->value.integer, -1);
+                   else
+                     mpz_set_si (result->value.integer, 1);
+                 }
+               /* Then, we take care of op2 < 0.  */
+               else if (mpz_cmp_si (op2->value.integer, 0) < 0)
+                 {
+                   /* if op2 < 0, op1**op2 == 0  because abs(op1) > 1.  */
+                   mpz_set_si (result->value.integer, 0);
+                 }
+               else if (gfc_extract_int (op2, &power) != NULL)
+                 {
+                   /* If op2 doesn't fit in an int, the exponentiation will
+                      overflow, because op2 > 0 and abs(op1) > 1.  */
+                   mpz_t max;
+                   int i;
+                   i = gfc_validate_kind (BT_INTEGER, result->ts.kind, false);
+
+                   if (gfc_option.flag_range_check)
+                     rc = ARITH_OVERFLOW;
+
+                   /* Still, we want to give the same value as the
+                      processor.  */
+                   mpz_init (max);
+                   mpz_add_ui (max, gfc_integer_kinds[i].huge, 1);
+                   mpz_mul_ui (max, max, 2);
+                   mpz_powm (result->value.integer, op1->value.integer,
+                             op2->value.integer, max);
+                   mpz_clear (max);
+                 }
+               else
+                 mpz_pow_ui (result->value.integer, op1->value.integer,
+                             power);
+             }
+             break;
 
-       case BT_REAL:
-         mpfr_pow_ui (result->value.real, op1->value.real, apower,
-                      GFC_RND_MODE);
+           case BT_REAL:
+             mpfr_pow_z (result->value.real, op1->value.real,
+                         op2->value.integer, GFC_RND_MODE);
+             break;
 
-         if (power < 0)
-           {
-             gfc_set_model (op1->value.real);
-             mpfr_init (unity_f);
-             mpfr_set_ui (unity_f, 1, GFC_RND_MODE);
-             mpfr_div (result->value.real, unity_f, result->value.real,
-                       GFC_RND_MODE);
-             mpfr_clear (unity_f);
+           case BT_COMPLEX:
+             mpc_pow_z (result->value.complex, op1->value.complex,
+                        op2->value.integer, GFC_MPC_RND_MODE);
+             break;
+
+           default:
+             break;
            }
-         break;
+       }
+      break;
 
-       case BT_COMPLEX:
-         complex_pow_ui (op1, apower, result);
-         if (power < 0)
-           complex_reciprocal (result);
-         break;
+    case BT_REAL:
 
-       default:
-         break;
+      if (gfc_init_expr_flag)
+       {
+         if (gfc_notify_std (GFC_STD_F2003,"Fortran 2003: Noninteger "
+                             "exponent in an initialization "
+                             "expression at %L", &op2->where) == FAILURE)
+           return ARITH_PROHIBIT;
        }
+
+      if (mpfr_cmp_si (op1->value.real, 0) < 0)
+       {
+         gfc_error ("Raising a negative REAL at %L to "
+                    "a REAL power is prohibited", &op1->where);
+         gfc_free (result);
+         return ARITH_PROHIBIT;
+       }
+
+       mpfr_pow (result->value.real, op1->value.real, op2->value.real,
+                 GFC_RND_MODE);
+      break;
+
+    case BT_COMPLEX:
+      {
+       if (gfc_init_expr_flag)
+         {
+           if (gfc_notify_std (GFC_STD_F2003,"Fortran 2003: Noninteger "
+                               "exponent in an initialization "
+                               "expression at %L", &op2->where) == FAILURE)
+             return ARITH_PROHIBIT;
+         }
+
+       mpc_pow (result->value.complex, op1->value.complex,
+                op2->value.complex, GFC_MPC_RND_MODE);
+      }
+      break;
+    default:
+      gfc_internal_error ("arith_power(): unknown type");
     }
 
   if (rc == ARITH_OK)
@@ -1014,19 +951,21 @@ gfc_arith_concat (gfc_expr *op1, gfc_expr *op2, gfc_expr **resultp)
   gfc_expr *result;
   int len;
 
-  result = gfc_constant_result (BT_CHARACTER, gfc_default_character_kind,
-                               &op1->where);
+  gcc_assert (op1->ts.kind == op2->ts.kind);
+  result = gfc_get_constant_expr (BT_CHARACTER, op1->ts.kind,
+                                 &op1->where);
 
   len = op1->value.character.length + op2->value.character.length;
 
-  result->value.character.string = gfc_getmem (len + 1);
+  result->value.character.string = gfc_get_wide_string (len + 1);
   result->value.character.length = len;
 
   memcpy (result->value.character.string, op1->value.character.string,
-         op1->value.character.length);
+         op1->value.character.length * sizeof (gfc_char_t));
 
-  memcpy (result->value.character.string + op1->value.character.length,
-         op2->value.character.string, op2->value.character.length);
+  memcpy (&result->value.character.string[op1->value.character.length],
+         op2->value.character.string,
+         op2->value.character.length * sizeof (gfc_char_t));
 
   result->value.character.string[len] = '\0';
 
@@ -1035,12 +974,43 @@ gfc_arith_concat (gfc_expr *op1, gfc_expr *op2, gfc_expr **resultp)
   return ARITH_OK;
 }
 
+/* Comparison between real values; returns 0 if (op1 .op. op2) is true.
+   This function mimics mpfr_cmp but takes NaN into account.  */
+
+static int
+compare_real (gfc_expr *op1, gfc_expr *op2, gfc_intrinsic_op op)
+{
+  int rc;
+  switch (op)
+    {
+      case INTRINSIC_EQ:
+       rc = mpfr_equal_p (op1->value.real, op2->value.real) ? 0 : 1;
+       break;
+      case INTRINSIC_GT:
+       rc = mpfr_greater_p (op1->value.real, op2->value.real) ? 1 : -1;
+       break;
+      case INTRINSIC_GE:
+       rc = mpfr_greaterequal_p (op1->value.real, op2->value.real) ? 1 : -1;
+       break;
+      case INTRINSIC_LT:
+       rc = mpfr_less_p (op1->value.real, op2->value.real) ? -1 : 1;
+       break;
+      case INTRINSIC_LE:
+       rc = mpfr_lessequal_p (op1->value.real, op2->value.real) ? -1 : 1;
+       break;
+      default:
+       gfc_internal_error ("compare_real(): Bad operator");
+    }
+
+  return rc;
+}
 
 /* Comparison operators.  Assumes that the two expression nodes
-   contain two constants of the same type.  */
+   contain two constants of the same type. The op argument is
+   needed to handle NaN correctly.  */
 
 int
-gfc_compare_expr (gfc_expr *op1, gfc_expr *op2)
+gfc_compare_expr (gfc_expr *op1, gfc_expr *op2, gfc_intrinsic_op op)
 {
   int rc;
 
@@ -1051,11 +1021,11 @@ gfc_compare_expr (gfc_expr *op1, gfc_expr *op2)
       break;
 
     case BT_REAL:
-      rc = mpfr_cmp (op1->value.real, op2->value.real);
+      rc = compare_real (op1, op2, op);
       break;
 
     case BT_CHARACTER:
-      rc = gfc_compare_string (op1, op2, NULL);
+      rc = gfc_compare_string (op1, op2);
       break;
 
     case BT_LOGICAL:
@@ -1072,41 +1042,66 @@ gfc_compare_expr (gfc_expr *op1, gfc_expr *op2)
 
 
 /* Compare a pair of complex numbers.  Naturally, this is only for
-   equality and nonequality.  */
+   equality and inequality.  */
 
 static int
 compare_complex (gfc_expr *op1, gfc_expr *op2)
 {
-  return (mpfr_cmp (op1->value.complex.r, op2->value.complex.r) == 0
-         && mpfr_cmp (op1->value.complex.i, op2->value.complex.i) == 0);
+  return mpc_cmp (op1->value.complex, op2->value.complex) == 0;
 }
 
 
 /* Given two constant strings and the inverse collating sequence, compare the
-   strings.  We return -1 for a < b, 0 for a == b and 1 for a > b.  If the
-   xcoll_table is NULL, we use the processor's default collating sequence.  */
+   strings.  We return -1 for a < b, 0 for a == b and 1 for a > b. 
+   We use the processor's default collating sequence.  */
 
 int
-gfc_compare_string (gfc_expr *a, gfc_expr *b, const int *xcoll_table)
+gfc_compare_string (gfc_expr *a, gfc_expr *b)
 {
-  int len, alen, blen, i, ac, bc;
+  int len, alen, blen, i;
+  gfc_char_t ac, bc;
 
   alen = a->value.character.length;
   blen = b->value.character.length;
 
-  len = (alen > blen) ? alen : blen;
+  len = MAX(alen, blen);
+
+  for (i = 0; i < len; i++)
+    {
+      ac = ((i < alen) ? a->value.character.string[i] : ' ');
+      bc = ((i < blen) ? b->value.character.string[i] : ' ');
+
+      if (ac < bc)
+       return -1;
+      if (ac > bc)
+       return 1;
+    }
+
+  /* Strings are equal */
+  return 0;
+}
+
+
+int
+gfc_compare_with_Cstring (gfc_expr *a, const char *b, bool case_sensitive)
+{
+  int len, alen, blen, i;
+  gfc_char_t ac, bc;
+
+  alen = a->value.character.length;
+  blen = strlen (b);
+
+  len = MAX(alen, blen);
 
   for (i = 0; i < len; i++)
     {
-      /* We cast to unsigned char because default char, if it is signed,
-        would lead to ac < 0 for string[i] > 127.  */
-      ac = (unsigned char) ((i < alen) ? a->value.character.string[i] : ' ');
-      bc = (unsigned char) ((i < blen) ? b->value.character.string[i] : ' ');
+      ac = ((i < alen) ? a->value.character.string[i] : ' ');
+      bc = ((i < blen) ? b[i] : ' ');
 
-      if (xcoll_table != NULL)
+      if (!case_sensitive)
        {
-         ac = xcoll_table[ac];
-         bc = xcoll_table[bc];
+         ac = TOLOWER (ac);
+         bc = TOLOWER (bc);
        }
 
       if (ac < bc)
@@ -1116,7 +1111,6 @@ gfc_compare_string (gfc_expr *a, gfc_expr *b, const int *xcoll_table)
     }
 
   /* Strings are equal */
-
   return 0;
 }
 
@@ -1128,11 +1122,11 @@ gfc_arith_eq (gfc_expr *op1, gfc_expr *op2, gfc_expr **resultp)
 {
   gfc_expr *result;
 
-  result = gfc_constant_result (BT_LOGICAL, gfc_default_logical_kind,
-                               &op1->where);
+  result = gfc_get_constant_expr (BT_LOGICAL, gfc_default_logical_kind,
+                                 &op1->where);
   result->value.logical = (op1->ts.type == BT_COMPLEX)
                        ? compare_complex (op1, op2)
-                       : (gfc_compare_expr (op1, op2) == 0);
+                       : (gfc_compare_expr (op1, op2, INTRINSIC_EQ) == 0);
 
   *resultp = result;
   return ARITH_OK;
@@ -1144,11 +1138,11 @@ gfc_arith_ne (gfc_expr *op1, gfc_expr *op2, gfc_expr **resultp)
 {
   gfc_expr *result;
 
-  result = gfc_constant_result (BT_LOGICAL, gfc_default_logical_kind,
-                               &op1->where);
+  result = gfc_get_constant_expr (BT_LOGICAL, gfc_default_logical_kind,
+                                 &op1->where);
   result->value.logical = (op1->ts.type == BT_COMPLEX)
                        ? !compare_complex (op1, op2)
-                       : (gfc_compare_expr (op1, op2) != 0);
+                       : (gfc_compare_expr (op1, op2, INTRINSIC_EQ) != 0);
 
   *resultp = result;
   return ARITH_OK;
@@ -1160,9 +1154,9 @@ gfc_arith_gt (gfc_expr *op1, gfc_expr *op2, gfc_expr **resultp)
 {
   gfc_expr *result;
 
-  result = gfc_constant_result (BT_LOGICAL, gfc_default_logical_kind,
-                               &op1->where);
-  result->value.logical = (gfc_compare_expr (op1, op2) > 0);
+  result = gfc_get_constant_expr (BT_LOGICAL, gfc_default_logical_kind,
+                                 &op1->where);
+  result->value.logical = (gfc_compare_expr (op1, op2, INTRINSIC_GT) > 0);
   *resultp = result;
 
   return ARITH_OK;
@@ -1174,9 +1168,9 @@ gfc_arith_ge (gfc_expr *op1, gfc_expr *op2, gfc_expr **resultp)
 {
   gfc_expr *result;
 
-  result = gfc_constant_result (BT_LOGICAL, gfc_default_logical_kind,
-                               &op1->where);
-  result->value.logical = (gfc_compare_expr (op1, op2) >= 0);
+  result = gfc_get_constant_expr (BT_LOGICAL, gfc_default_logical_kind,
+                                 &op1->where);
+  result->value.logical = (gfc_compare_expr (op1, op2, INTRINSIC_GE) >= 0);
   *resultp = result;
 
   return ARITH_OK;
@@ -1188,9 +1182,9 @@ gfc_arith_lt (gfc_expr *op1, gfc_expr *op2, gfc_expr **resultp)
 {
   gfc_expr *result;
 
-  result = gfc_constant_result (BT_LOGICAL, gfc_default_logical_kind,
-                               &op1->where);
-  result->value.logical = (gfc_compare_expr (op1, op2) < 0);
+  result = gfc_get_constant_expr (BT_LOGICAL, gfc_default_logical_kind,
+                                 &op1->where);
+  result->value.logical = (gfc_compare_expr (op1, op2, INTRINSIC_LT) < 0);
   *resultp = result;
 
   return ARITH_OK;
@@ -1202,9 +1196,9 @@ gfc_arith_le (gfc_expr *op1, gfc_expr *op2, gfc_expr **resultp)
 {
   gfc_expr *result;
 
-  result = gfc_constant_result (BT_LOGICAL, gfc_default_logical_kind,
-                               &op1->where);
-  result->value.logical = (gfc_compare_expr (op1, op2) <= 0);
+  result = gfc_get_constant_expr (BT_LOGICAL, gfc_default_logical_kind,
+                                 &op1->where);
+  result->value.logical = (gfc_compare_expr (op1, op2, INTRINSIC_LE) <= 0);
   *resultp = result;
 
   return ARITH_OK;
@@ -1215,7 +1209,8 @@ static arith
 reduce_unary (arith (*eval) (gfc_expr *, gfc_expr **), gfc_expr *op,
              gfc_expr **result)
 {
-  gfc_constructor *c, *head;
+  gfc_constructor_base head;
+  gfc_constructor *c;
   gfc_expr *r;
   arith rc;
 
@@ -1223,11 +1218,11 @@ reduce_unary (arith (*eval) (gfc_expr *, gfc_expr **), gfc_expr *op,
     return eval (op, result);
 
   rc = ARITH_OK;
-  head = gfc_copy_constructor (op->value.constructor);
-
-  for (c = head; c; c = c->next)
+  head = gfc_constructor_copy (op->value.constructor);
+  for (c = gfc_constructor_first (head); c; c = gfc_constructor_next (c))
     {
-      rc = eval (c->expr, &r);
+      rc = reduce_unary (eval, c->expr, &r);
+
       if (rc != ARITH_OK)
        break;
 
@@ -1235,18 +1230,15 @@ reduce_unary (arith (*eval) (gfc_expr *, gfc_expr **), gfc_expr *op,
     }
 
   if (rc != ARITH_OK)
-    gfc_free_constructor (head);
+    gfc_constructor_free (head);
   else
     {
-      r = gfc_get_expr ();
-      r->expr_type = EXPR_ARRAY;
-      r->value.constructor = head;
+      gfc_constructor *c = gfc_constructor_first (head);
+      r = gfc_get_array_expr (c->expr->ts.type, c->expr->ts.kind,
+                             &op->where);
       r->shape = gfc_copy_shape (op->shape, op->rank);
-
-      r->ts = head->expr->ts;
-      r->where = op->where;
       r->rank = op->rank;
-
+      r->value.constructor = head;
       *result = r;
     }
 
@@ -1258,16 +1250,19 @@ static arith
 reduce_binary_ac (arith (*eval) (gfc_expr *, gfc_expr *, gfc_expr **),
                  gfc_expr *op1, gfc_expr *op2, gfc_expr **result)
 {
-  gfc_constructor *c, *head;
+  gfc_constructor_base head;
+  gfc_constructor *c;
   gfc_expr *r;
-  arith rc;
-
-  head = gfc_copy_constructor (op1->value.constructor);
-  rc = ARITH_OK;
+  arith rc = ARITH_OK;
 
-  for (c = head; c; c = c->next)
+  head = gfc_constructor_copy (op1->value.constructor);
+  for (c = gfc_constructor_first (head); c; c = gfc_constructor_next (c))
     {
-      rc = eval (c->expr, op2, &r);
+      if (c->expr->expr_type == EXPR_CONSTANT)
+        rc = eval (c->expr, op2, &r);
+      else
+       rc = reduce_binary_ac (eval, c->expr, op2, &r);
+
       if (rc != ARITH_OK)
        break;
 
@@ -1275,18 +1270,15 @@ reduce_binary_ac (arith (*eval) (gfc_expr *, gfc_expr *, gfc_expr **),
     }
 
   if (rc != ARITH_OK)
-    gfc_free_constructor (head);
+    gfc_constructor_free (head);
   else
     {
-      r = gfc_get_expr ();
-      r->expr_type = EXPR_ARRAY;
-      r->value.constructor = head;
+      gfc_constructor *c = gfc_constructor_first (head);
+      r = gfc_get_array_expr (c->expr->ts.type, c->expr->ts.kind,
+                             &op1->where);
       r->shape = gfc_copy_shape (op1->shape, op1->rank);
-
-      r->ts = head->expr->ts;
-      r->where = op1->where;
       r->rank = op1->rank;
-
+      r->value.constructor = head;
       *result = r;
     }
 
@@ -1298,16 +1290,19 @@ static arith
 reduce_binary_ca (arith (*eval) (gfc_expr *, gfc_expr *, gfc_expr **),
                  gfc_expr *op1, gfc_expr *op2, gfc_expr **result)
 {
-  gfc_constructor *c, *head;
+  gfc_constructor_base head;
+  gfc_constructor *c;
   gfc_expr *r;
-  arith rc;
+  arith rc = ARITH_OK;
 
-  head = gfc_copy_constructor (op2->value.constructor);
-  rc = ARITH_OK;
-
-  for (c = head; c; c = c->next)
+  head = gfc_constructor_copy (op2->value.constructor);
+  for (c = gfc_constructor_first (head); c; c = gfc_constructor_next (c))
     {
-      rc = eval (op1, c->expr, &r);
+      if (c->expr->expr_type == EXPR_CONSTANT)
+       rc = eval (op1, c->expr, &r);
+      else
+       rc = reduce_binary_ca (eval, op1, c->expr, &r);
+
       if (rc != ARITH_OK)
        break;
 
@@ -1315,18 +1310,15 @@ reduce_binary_ca (arith (*eval) (gfc_expr *, gfc_expr *, gfc_expr **),
     }
 
   if (rc != ARITH_OK)
-    gfc_free_constructor (head);
+    gfc_constructor_free (head);
   else
     {
-      r = gfc_get_expr ();
-      r->expr_type = EXPR_ARRAY;
-      r->value.constructor = head;
+      gfc_constructor *c = gfc_constructor_first (head);
+      r = gfc_get_array_expr (c->expr->ts.type, c->expr->ts.kind,
+                             &op2->where);
       r->shape = gfc_copy_shape (op2->shape, op2->rank);
-
-      r->ts = head->expr->ts;
-      r->where = op2->where;
       r->rank = op2->rank;
-
+      r->value.constructor = head;
       *result = r;
     }
 
@@ -1334,56 +1326,50 @@ reduce_binary_ca (arith (*eval) (gfc_expr *, gfc_expr *, gfc_expr **),
 }
 
 
+/* We need a forward declaration of reduce_binary.  */
+static arith reduce_binary (arith (*eval) (gfc_expr *, gfc_expr *, gfc_expr **),
+                           gfc_expr *op1, gfc_expr *op2, gfc_expr **result);
+
+
 static arith
 reduce_binary_aa (arith (*eval) (gfc_expr *, gfc_expr *, gfc_expr **),
                  gfc_expr *op1, gfc_expr *op2, gfc_expr **result)
 {
-  gfc_constructor *c, *d, *head;
+  gfc_constructor_base head;
+  gfc_constructor *c, *d;
   gfc_expr *r;
-  arith rc;
-
-  head = gfc_copy_constructor (op1->value.constructor);
+  arith rc = ARITH_OK;
 
-  rc = ARITH_OK;
-  d = op2->value.constructor;
+  if (gfc_check_conformance (op1, op2,
+                            "elemental binary operation") != SUCCESS)
+    return ARITH_INCOMMENSURATE;
 
-  if (gfc_check_conformance ("Elemental binary operation", op1, op2)
-      != SUCCESS)
-    rc = ARITH_INCOMMENSURATE;
-  else
+  head = gfc_constructor_copy (op1->value.constructor);
+  for (c = gfc_constructor_first (head),
+       d = gfc_constructor_first (op2->value.constructor);
+       c && d;
+       c = gfc_constructor_next (c), d = gfc_constructor_next (d))
     {
-      for (c = head; c; c = c->next, d = d->next)
-       {
-         if (d == NULL)
-           {
-             rc = ARITH_INCOMMENSURATE;
-             break;
-           }
-
-         rc = eval (c->expr, d->expr, &r);
-         if (rc != ARITH_OK)
-           break;
-
-         gfc_replace_expr (c->expr, r);
-       }
+       rc = reduce_binary (eval, c->expr, d->expr, &r);
+       if (rc != ARITH_OK)
+         break;
 
-      if (d != NULL)
-       rc = ARITH_INCOMMENSURATE;
+       gfc_replace_expr (c->expr, r);
     }
 
+  if (c || d)
+    rc = ARITH_INCOMMENSURATE;
+
   if (rc != ARITH_OK)
-    gfc_free_constructor (head);
+    gfc_constructor_free (head);
   else
     {
-      r = gfc_get_expr ();
-      r->expr_type = EXPR_ARRAY;
-      r->value.constructor = head;
+      gfc_constructor *c = gfc_constructor_first (head);
+      r = gfc_get_array_expr (c->expr->ts.type, c->expr->ts.kind,
+                             &op1->where);
       r->shape = gfc_copy_shape (op1->shape, op1->rank);
-
-      r->ts = head->expr->ts;
-      r->where = op1->where;
       r->rank = op1->rank;
-
+      r->value.constructor = head;
       *result = r;
     }
 
@@ -1426,7 +1412,7 @@ eval_f;
    operands are array constructors.  */
 
 static gfc_expr *
-eval_intrinsic (gfc_intrinsic_op operator,
+eval_intrinsic (gfc_intrinsic_op op,
                eval_f eval, gfc_expr *op1, gfc_expr *op2)
 {
   gfc_expr temp, *result;
@@ -1435,7 +1421,7 @@ eval_intrinsic (gfc_intrinsic_op operator,
 
   gfc_clear_ts (&temp.ts);
 
-  switch (operator)
+  switch (op)
     {
     /* Logical unary  */
     case INTRINSIC_NOT:
@@ -1477,9 +1463,13 @@ eval_intrinsic (gfc_intrinsic_op operator,
 
     /* Additional restrictions for ordering relations.  */
     case INTRINSIC_GE:
+    case INTRINSIC_GE_OS:
     case INTRINSIC_LT:
+    case INTRINSIC_LT_OS:
     case INTRINSIC_LE:
+    case INTRINSIC_LE_OS:
     case INTRINSIC_GT:
+    case INTRINSIC_GT_OS:
       if (op1->ts.type == BT_COMPLEX || op2->ts.type == BT_COMPLEX)
        {
          temp.ts.type = BT_LOGICAL;
@@ -1489,12 +1479,19 @@ eval_intrinsic (gfc_intrinsic_op operator,
 
     /* Fall through  */
     case INTRINSIC_EQ:
+    case INTRINSIC_EQ_OS:
     case INTRINSIC_NE:
+    case INTRINSIC_NE_OS:
       if (op1->ts.type == BT_CHARACTER && op2->ts.type == BT_CHARACTER)
        {
          unary = 0;
          temp.ts.type = BT_LOGICAL;
          temp.ts.kind = gfc_default_logical_kind;
+
+         /* If kind mismatch, exit and we'll error out later.  */
+         if (op1->ts.kind != op2->ts.kind)
+           goto runtime;
+
          break;
        }
 
@@ -1513,16 +1510,19 @@ eval_intrinsic (gfc_intrinsic_op operator,
 
       temp.expr_type = EXPR_OP;
       gfc_clear_ts (&temp.ts);
-      temp.value.op.operator = operator;
+      temp.value.op.op = op;
 
       temp.value.op.op1 = op1;
       temp.value.op.op2 = op2;
 
-      gfc_type_convert_binary (&temp);
+      gfc_type_convert_binary (&temp, 0);
 
-      if (operator == INTRINSIC_EQ || operator == INTRINSIC_NE
-         || operator == INTRINSIC_GE || operator == INTRINSIC_GT
-         || operator == INTRINSIC_LE || operator == INTRINSIC_LT)
+      if (op == INTRINSIC_EQ || op == INTRINSIC_NE
+         || op == INTRINSIC_GE || op == INTRINSIC_GT
+         || op == INTRINSIC_LE || op == INTRINSIC_LT
+         || op == INTRINSIC_EQ_OS || op == INTRINSIC_NE_OS
+         || op == INTRINSIC_GE_OS || op == INTRINSIC_GT_OS
+         || op == INTRINSIC_LE_OS || op == INTRINSIC_LT_OS)
        {
          temp.ts.type = BT_LOGICAL;
          temp.ts.kind = gfc_default_logical_kind;
@@ -1533,11 +1533,12 @@ eval_intrinsic (gfc_intrinsic_op operator,
 
     /* Character binary  */
     case INTRINSIC_CONCAT:
-      if (op1->ts.type != BT_CHARACTER || op2->ts.type != BT_CHARACTER)
+      if (op1->ts.type != BT_CHARACTER || op2->ts.type != BT_CHARACTER
+         || op1->ts.kind != op2->ts.kind)
        goto runtime;
 
       temp.ts.type = BT_CHARACTER;
-      temp.ts.kind = gfc_default_character_kind;
+      temp.ts.kind = op1->ts.kind;
       unary = 0;
       break;
 
@@ -1548,21 +1549,15 @@ eval_intrinsic (gfc_intrinsic_op operator,
       gfc_internal_error ("eval_intrinsic(): Bad operator");
     }
 
-  /* Try to combine the operators.  */
-  if (operator == INTRINSIC_POWER && op2->ts.type != BT_INTEGER)
-    goto runtime;
-
-  if (op1->from_H
-      || (op1->expr_type != EXPR_CONSTANT
-         && (op1->expr_type != EXPR_ARRAY
-             || !gfc_is_constant_expr (op1) || !gfc_expanded_ac (op1))))
+  if (op1->expr_type != EXPR_CONSTANT
+      && (op1->expr_type != EXPR_ARRAY
+         || !gfc_is_constant_expr (op1) || !gfc_expanded_ac (op1)))
     goto runtime;
 
   if (op2 != NULL
-      && (op2->from_H
-         || (op2->expr_type != EXPR_CONSTANT
-             && (op2->expr_type != EXPR_ARRAY
-                 || !gfc_is_constant_expr (op2) || !gfc_expanded_ac (op2)))))
+      && op2->expr_type != EXPR_CONSTANT
+        && (op2->expr_type != EXPR_ARRAY
+            || !gfc_is_constant_expr (op2) || !gfc_expanded_ac (op2)))
     goto runtime;
 
   if (unary)
@@ -1570,8 +1565,13 @@ eval_intrinsic (gfc_intrinsic_op operator,
   else
     rc = reduce_binary (eval.f3, op1, op2, &result);
 
+
+  /* Something went wrong.  */
+  if (op == INTRINSIC_POWER && rc == ARITH_PROHIBIT)
+    return NULL;
+
   if (rc != ARITH_OK)
-    { /* Something went wrong.  */
+    {
       gfc_error (gfc_arith_error (rc), &op1->where);
       return NULL;
     }
@@ -1582,17 +1582,9 @@ eval_intrinsic (gfc_intrinsic_op operator,
 
 runtime:
   /* Create a run-time expression.  */
-  result = gfc_get_expr ();
+  result = gfc_get_operator_expr (&op1->where, op, op1, op2);
   result->ts = temp.ts;
 
-  result->expr_type = EXPR_OP;
-  result->value.op.operator = operator;
-
-  result->value.op.op1 = op1;
-  result->value.op.op2 = op2;
-
-  result->where = op1->where;
-
   return result;
 }
 
@@ -1600,19 +1592,25 @@ runtime:
 /* Modify type of expression for zero size array.  */
 
 static gfc_expr *
-eval_type_intrinsic0 (gfc_intrinsic_op operator, gfc_expr *op)
+eval_type_intrinsic0 (gfc_intrinsic_op iop, gfc_expr *op)
 {
   if (op == NULL)
     gfc_internal_error ("eval_type_intrinsic0(): op NULL");
 
-  switch (operator)
+  switch (iop)
     {
     case INTRINSIC_GE:
+    case INTRINSIC_GE_OS:
     case INTRINSIC_LT:
+    case INTRINSIC_LT_OS:
     case INTRINSIC_LE:
+    case INTRINSIC_LE_OS:
     case INTRINSIC_GT:
+    case INTRINSIC_GT_OS:
     case INTRINSIC_EQ:
+    case INTRINSIC_EQ_OS:
     case INTRINSIC_NE:
+    case INTRINSIC_NE_OS:
       op->ts.type = BT_LOGICAL;
       op->ts.kind = gfc_default_logical_kind;
       break;
@@ -1661,7 +1659,7 @@ reduce_binary0 (gfc_expr *op1, gfc_expr *op2)
 
 
 static gfc_expr *
-eval_intrinsic_f2 (gfc_intrinsic_op operator,
+eval_intrinsic_f2 (gfc_intrinsic_op op,
                   arith (*eval) (gfc_expr *, gfc_expr **),
                   gfc_expr *op1, gfc_expr *op2)
 {
@@ -1671,22 +1669,22 @@ eval_intrinsic_f2 (gfc_intrinsic_op operator,
   if (op2 == NULL)
     {
       if (gfc_zero_size_array (op1))
-       return eval_type_intrinsic0 (operator, op1);
+       return eval_type_intrinsic0 (op, op1);
     }
   else
     {
       result = reduce_binary0 (op1, op2);
       if (result != NULL)
-       return eval_type_intrinsic0 (operator, result);
+       return eval_type_intrinsic0 (op, result);
     }
 
   f.f2 = eval;
-  return eval_intrinsic (operator, f, op1, op2);
+  return eval_intrinsic (op, f, op1, op2);
 }
 
 
 static gfc_expr *
-eval_intrinsic_f3 (gfc_intrinsic_op operator,
+eval_intrinsic_f3 (gfc_intrinsic_op op,
                   arith (*eval) (gfc_expr *, gfc_expr *, gfc_expr **),
                   gfc_expr *op1, gfc_expr *op2)
 {
@@ -1695,17 +1693,27 @@ eval_intrinsic_f3 (gfc_intrinsic_op operator,
 
   result = reduce_binary0 (op1, op2);
   if (result != NULL)
-    return eval_type_intrinsic0(operator, result);
+    return eval_type_intrinsic0(op, result);
 
   f.f3 = eval;
-  return eval_intrinsic (operator, f, op1, op2);
+  return eval_intrinsic (op, f, op1, op2);
 }
 
 
 gfc_expr *
+gfc_parentheses (gfc_expr *op)
+{
+  if (gfc_is_constant_expr (op))
+    return op;
+
+  return eval_intrinsic_f2 (INTRINSIC_PARENTHESES, gfc_arith_identity,
+                           op, NULL);
+}
+
+gfc_expr *
 gfc_uplus (gfc_expr *op)
 {
-  return eval_intrinsic_f2 (INTRINSIC_UPLUS, gfc_arith_uplus, op, NULL);
+  return eval_intrinsic_f2 (INTRINSIC_UPLUS, gfc_arith_identity, op, NULL);
 }
 
 
@@ -1747,7 +1755,7 @@ gfc_divide (gfc_expr *op1, gfc_expr *op2)
 gfc_expr *
 gfc_power (gfc_expr *op1, gfc_expr *op2)
 {
-  return eval_intrinsic_f3 (INTRINSIC_POWER, gfc_arith_power, op1, op2);
+  return eval_intrinsic_f3 (INTRINSIC_POWER, arith_power, op1, op2);
 }
 
 
@@ -1794,44 +1802,44 @@ gfc_neqv (gfc_expr *op1, gfc_expr *op2)
 
 
 gfc_expr *
-gfc_eq (gfc_expr *op1, gfc_expr *op2)
+gfc_eq (gfc_expr *op1, gfc_expr *op2, gfc_intrinsic_op op)
 {
-  return eval_intrinsic_f3 (INTRINSIC_EQ, gfc_arith_eq, op1, op2);
+  return eval_intrinsic_f3 (op, gfc_arith_eq, op1, op2);
 }
 
 
 gfc_expr *
-gfc_ne (gfc_expr *op1, gfc_expr *op2)
+gfc_ne (gfc_expr *op1, gfc_expr *op2, gfc_intrinsic_op op)
 {
-  return eval_intrinsic_f3 (INTRINSIC_NE, gfc_arith_ne, op1, op2);
+  return eval_intrinsic_f3 (op, gfc_arith_ne, op1, op2);
 }
 
 
 gfc_expr *
-gfc_gt (gfc_expr *op1, gfc_expr *op2)
+gfc_gt (gfc_expr *op1, gfc_expr *op2, gfc_intrinsic_op op)
 {
-  return eval_intrinsic_f3 (INTRINSIC_GT, gfc_arith_gt, op1, op2);
+  return eval_intrinsic_f3 (op, gfc_arith_gt, op1, op2);
 }
 
 
 gfc_expr *
-gfc_ge (gfc_expr *op1, gfc_expr *op2)
+gfc_ge (gfc_expr *op1, gfc_expr *op2, gfc_intrinsic_op op)
 {
-  return eval_intrinsic_f3 (INTRINSIC_GE, gfc_arith_ge, op1, op2);
+  return eval_intrinsic_f3 (op, gfc_arith_ge, op1, op2);
 }
 
 
 gfc_expr *
-gfc_lt (gfc_expr *op1, gfc_expr *op2)
+gfc_lt (gfc_expr *op1, gfc_expr *op2, gfc_intrinsic_op op)
 {
-  return eval_intrinsic_f3 (INTRINSIC_LT, gfc_arith_lt, op1, op2);
+  return eval_intrinsic_f3 (op, gfc_arith_lt, op1, op2);
 }
 
 
 gfc_expr *
-gfc_le (gfc_expr *op1, gfc_expr *op2)
+gfc_le (gfc_expr *op1, gfc_expr *op2, gfc_intrinsic_op op)
 {
-  return eval_intrinsic_f3 (INTRINSIC_LE, gfc_arith_le, op1, op2);
+  return eval_intrinsic_f3 (op, gfc_arith_le, op1, op2);
 }
 
 
@@ -1843,7 +1851,7 @@ gfc_convert_integer (const char *buffer, int kind, int radix, locus *where)
   gfc_expr *e;
   const char *t;
 
-  e = gfc_constant_result (BT_INTEGER, kind, where);
+  e = gfc_get_constant_expr (BT_INTEGER, kind, where);
   /* A leading plus is allowed, but not by mpz_set_str.  */
   if (buffer[0] == '+')
     t = buffer + 1;
@@ -1862,7 +1870,7 @@ gfc_convert_real (const char *buffer, int kind, locus *where)
 {
   gfc_expr *e;
 
-  e = gfc_constant_result (BT_REAL, kind, where);
+  e = gfc_get_constant_expr (BT_REAL, kind, where);
   mpfr_set_str (e->value.real, buffer, 10, GFC_RND_MODE);
 
   return e;
@@ -1877,9 +1885,9 @@ gfc_convert_complex (gfc_expr *real, gfc_expr *imag, int kind)
 {
   gfc_expr *e;
 
-  e = gfc_constant_result (BT_COMPLEX, kind, &real->where);
-  mpfr_set (e->value.complex.r, real->value.real, GFC_RND_MODE);
-  mpfr_set (e->value.complex.i, imag->value.real, GFC_RND_MODE);
+  e = gfc_get_constant_expr (BT_COMPLEX, kind, &real->where);
+  mpc_set_fr_fr (e->value.complex, real->value.real, imag->value.real,
+                GFC_MPC_RND_MODE);
 
   return e;
 }
@@ -1900,15 +1908,18 @@ arith_error (arith rc, gfc_typespec *from, gfc_typespec *to, locus *where)
                 gfc_typename (from), gfc_typename (to), where);
       break;
     case ARITH_OVERFLOW:
-      gfc_error ("Arithmetic overflow converting %s to %s at %L",
+      gfc_error ("Arithmetic overflow converting %s to %s at %L. This check "
+                "can be disabled with the option -fno-range-check",
                 gfc_typename (from), gfc_typename (to), where);
       break;
     case ARITH_UNDERFLOW:
-      gfc_error ("Arithmetic underflow converting %s to %s at %L",
+      gfc_error ("Arithmetic underflow converting %s to %s at %L. This check "
+                "can be disabled with the option -fno-range-check",
                 gfc_typename (from), gfc_typename (to), where);
       break;
     case ARITH_NAN:
-      gfc_error ("Arithmetic NaN converting %s to %s at %L",
+      gfc_error ("Arithmetic NaN converting %s to %s at %L. This check "
+                "can be disabled with the option -fno-range-check",
                 gfc_typename (from), gfc_typename (to), where);
       break;
     case ARITH_DIV0:
@@ -1928,7 +1939,7 @@ arith_error (arith rc, gfc_typespec *from, gfc_typespec *to, locus *where)
       gfc_internal_error ("gfc_arith_error(): Bad error code");
     }
 
-  /* TODO: Do something about the error, ie, throw exception, return
+  /* TODO: Do something about the error, i.e., throw exception, return
      NaN, etc.  */
 }
 
@@ -1941,7 +1952,7 @@ gfc_int2int (gfc_expr *src, int kind)
   gfc_expr *result;
   arith rc;
 
-  result = gfc_constant_result (BT_INTEGER, kind, &src->where);
+  result = gfc_get_constant_expr (BT_INTEGER, kind, &src->where);
 
   mpz_set (result->value.integer, src->value.integer);
 
@@ -1971,7 +1982,7 @@ gfc_int2real (gfc_expr *src, int kind)
   gfc_expr *result;
   arith rc;
 
-  result = gfc_constant_result (BT_REAL, kind, &src->where);
+  result = gfc_get_constant_expr (BT_REAL, kind, &src->where);
 
   mpfr_set_z (result->value.real, src->value.integer, GFC_RND_MODE);
 
@@ -1994,12 +2005,12 @@ gfc_int2complex (gfc_expr *src, int kind)
   gfc_expr *result;
   arith rc;
 
-  result = gfc_constant_result (BT_COMPLEX, kind, &src->where);
+  result = gfc_get_constant_expr (BT_COMPLEX, kind, &src->where);
 
-  mpfr_set_z (result->value.complex.r, src->value.integer, GFC_RND_MODE);
-  mpfr_set_ui (result->value.complex.i, 0, GFC_RND_MODE);
+  mpc_set_z (result->value.complex, src->value.integer, GFC_MPC_RND_MODE);
 
-  if ((rc = gfc_check_real_range (result->value.complex.r, kind)) != ARITH_OK)
+  if ((rc = gfc_check_real_range (mpc_realref (result->value.complex), kind))
+      != ARITH_OK)
     {
       arith_error (rc, &src->ts, &result->ts, &src->where);
       gfc_free_expr (result);
@@ -2018,9 +2029,9 @@ gfc_real2int (gfc_expr *src, int kind)
   gfc_expr *result;
   arith rc;
 
-  result = gfc_constant_result (BT_INTEGER, kind, &src->where);
+  result = gfc_get_constant_expr (BT_INTEGER, kind, &src->where);
 
-  gfc_mpfr_to_mpz (result->value.integer, src->value.real);
+  gfc_mpfr_to_mpz (result->value.integer, src->value.real, &src->where);
 
   if ((rc = gfc_check_integer_range (result->value.integer, kind)) != ARITH_OK)
     {
@@ -2041,7 +2052,7 @@ gfc_real2real (gfc_expr *src, int kind)
   gfc_expr *result;
   arith rc;
 
-  result = gfc_constant_result (BT_REAL, kind, &src->where);
+  result = gfc_get_constant_expr (BT_REAL, kind, &src->where);
 
   mpfr_set (result->value.real, src->value.real, GFC_RND_MODE);
 
@@ -2072,18 +2083,17 @@ gfc_real2complex (gfc_expr *src, int kind)
   gfc_expr *result;
   arith rc;
 
-  result = gfc_constant_result (BT_COMPLEX, kind, &src->where);
+  result = gfc_get_constant_expr (BT_COMPLEX, kind, &src->where);
 
-  mpfr_set (result->value.complex.r, src->value.real, GFC_RND_MODE);
-  mpfr_set_ui (result->value.complex.i, 0, GFC_RND_MODE);
+  mpc_set_fr (result->value.complex, src->value.real, GFC_MPC_RND_MODE);
 
-  rc = gfc_check_real_range (result->value.complex.r, kind);
+  rc = gfc_check_real_range (mpc_realref (result->value.complex), kind);
 
   if (rc == ARITH_UNDERFLOW)
     {
       if (gfc_option.warn_underflow)
        gfc_warning (gfc_arith_error (rc), &src->where);
-      mpfr_set_ui (result->value.complex.r, 0, GFC_RND_MODE);
+      mpfr_set_ui (mpc_realref (result->value.complex), 0, GFC_RND_MODE);
     }
   else if (rc != ARITH_OK)
     {
@@ -2104,9 +2114,10 @@ gfc_complex2int (gfc_expr *src, int kind)
   gfc_expr *result;
   arith rc;
 
-  result = gfc_constant_result (BT_INTEGER, kind, &src->where);
+  result = gfc_get_constant_expr (BT_INTEGER, kind, &src->where);
 
-  gfc_mpfr_to_mpz (result->value.integer, src->value.complex.r);
+  gfc_mpfr_to_mpz (result->value.integer, mpc_realref (src->value.complex),
+                  &src->where);
 
   if ((rc = gfc_check_integer_range (result->value.integer, kind)) != ARITH_OK)
     {
@@ -2127,9 +2138,9 @@ gfc_complex2real (gfc_expr *src, int kind)
   gfc_expr *result;
   arith rc;
 
-  result = gfc_constant_result (BT_REAL, kind, &src->where);
+  result = gfc_get_constant_expr (BT_REAL, kind, &src->where);
 
-  mpfr_set (result->value.real, src->value.complex.r, GFC_RND_MODE);
+  mpc_real (result->value.real, src->value.complex, GFC_RND_MODE);
 
   rc = gfc_check_real_range (result->value.real, kind);
 
@@ -2158,18 +2169,17 @@ gfc_complex2complex (gfc_expr *src, int kind)
   gfc_expr *result;
   arith rc;
 
-  result = gfc_constant_result (BT_COMPLEX, kind, &src->where);
+  result = gfc_get_constant_expr (BT_COMPLEX, kind, &src->where);
 
-  mpfr_set (result->value.complex.r, src->value.complex.r, GFC_RND_MODE);
-  mpfr_set (result->value.complex.i, src->value.complex.i, GFC_RND_MODE);
+  mpc_set (result->value.complex, src->value.complex, GFC_MPC_RND_MODE);
 
-  rc = gfc_check_real_range (result->value.complex.r, kind);
+  rc = gfc_check_real_range (mpc_realref (result->value.complex), kind);
 
   if (rc == ARITH_UNDERFLOW)
     {
       if (gfc_option.warn_underflow)
        gfc_warning (gfc_arith_error (rc), &src->where);
-      mpfr_set_ui (result->value.complex.r, 0, GFC_RND_MODE);
+      mpfr_set_ui (mpc_realref (result->value.complex), 0, GFC_RND_MODE);
     }
   else if (rc != ARITH_OK)
     {
@@ -2178,13 +2188,13 @@ gfc_complex2complex (gfc_expr *src, int kind)
       return NULL;
     }
 
-  rc = gfc_check_real_range (result->value.complex.i, kind);
+  rc = gfc_check_real_range (mpc_imagref (result->value.complex), kind);
 
   if (rc == ARITH_UNDERFLOW)
     {
       if (gfc_option.warn_underflow)
        gfc_warning (gfc_arith_error (rc), &src->where);
-      mpfr_set_ui (result->value.complex.i, 0, GFC_RND_MODE);
+      mpfr_set_ui (mpc_imagref (result->value.complex), 0, GFC_RND_MODE);
     }
   else if (rc != ARITH_OK)
     {
@@ -2204,7 +2214,7 @@ gfc_log2log (gfc_expr *src, int kind)
 {
   gfc_expr *result;
 
-  result = gfc_constant_result (BT_LOGICAL, kind, &src->where);
+  result = gfc_get_constant_expr (BT_LOGICAL, kind, &src->where);
   result->value.logical = src->value.logical;
 
   return result;
@@ -2218,7 +2228,7 @@ gfc_log2int (gfc_expr *src, int kind)
 {
   gfc_expr *result;
 
-  result = gfc_constant_result (BT_INTEGER, kind, &src->where);
+  result = gfc_get_constant_expr (BT_INTEGER, kind, &src->where);
   mpz_set_si (result->value.integer, src->value.logical);
 
   return result;
@@ -2232,80 +2242,70 @@ gfc_int2log (gfc_expr *src, int kind)
 {
   gfc_expr *result;
 
-  result = gfc_constant_result (BT_LOGICAL, kind, &src->where);
+  result = gfc_get_constant_expr (BT_LOGICAL, kind, &src->where);
   result->value.logical = (mpz_cmp_si (src->value.integer, 0) != 0);
 
   return result;
 }
 
 
-/* Convert Hollerith to integer. The constant will be padded or truncated.  */
+/* Helper function to set the representation in a Hollerith conversion.  
+   This assumes that the ts.type and ts.kind of the result have already
+   been set.  */
 
-gfc_expr *
-gfc_hollerith2int (gfc_expr *src, int kind)
+static void
+hollerith2representation (gfc_expr *result, gfc_expr *src)
 {
-  gfc_expr *result;
-  int len;
+  int src_len, result_len;
 
-  len = src->value.character.length;
+  src_len = src->representation.length;
+  result_len = gfc_target_expr_size (result);
 
-  result = gfc_get_expr ();
-  result->expr_type = EXPR_CONSTANT;
-  result->ts.type = BT_INTEGER;
-  result->ts.kind = kind;
-  result->where = src->where;
-  result->from_H = 1;
-
-  if (len > kind)
+  if (src_len > result_len)
     {
       gfc_warning ("The Hollerith constant at %L is too long to convert to %s",
                   &src->where, gfc_typename(&result->ts));
     }
-  result->value.character.string = gfc_getmem (kind + 1);
-  memcpy (result->value.character.string, src->value.character.string,
-       MIN (kind, len));
 
-  if (len < kind)
-    memset (&result->value.character.string[len], ' ', kind - len);
+  result->representation.string = XCNEWVEC (char, result_len + 1);
+  memcpy (result->representation.string, src->representation.string,
+         MIN (result_len, src_len));
 
-  result->value.character.string[kind] = '\0'; /* For debugger  */
-  result->value.character.length = kind;
+  if (src_len < result_len)
+    memset (&result->representation.string[src_len], ' ', result_len - src_len);
 
-  return result;
+  result->representation.string[result_len] = '\0'; /* For debugger  */
+  result->representation.length = result_len;
 }
 
 
-/* Convert Hollerith to real. The constant will be padded or truncated.  */
+/* Convert Hollerith to integer. The constant will be padded or truncated.  */
 
 gfc_expr *
-gfc_hollerith2real (gfc_expr *src, int kind)
+gfc_hollerith2int (gfc_expr *src, int kind)
 {
   gfc_expr *result;
-  int len;
+  result = gfc_get_constant_expr (BT_INTEGER, kind, &src->where);
 
-  len = src->value.character.length;
+  hollerith2representation (result, src);
+  gfc_interpret_integer (kind, (unsigned char *) result->representation.string,
+                        result->representation.length, result->value.integer);
 
-  result = gfc_get_expr ();
-  result->expr_type = EXPR_CONSTANT;
-  result->ts.type = BT_REAL;
-  result->ts.kind = kind;
-  result->where = src->where;
-  result->from_H = 1;
+  return result;
+}
 
-  if (len > kind)
-    {
-      gfc_warning ("The Hollerith constant at %L is too long to convert to %s",
-                  &src->where, gfc_typename(&result->ts));
-    }
-  result->value.character.string = gfc_getmem (kind + 1);
-  memcpy (result->value.character.string, src->value.character.string,
-       MIN (kind, len));
 
-  if (len < kind)
-    memset (&result->value.character.string[len], ' ', kind - len);
+/* Convert Hollerith to real. The constant will be padded or truncated.  */
+
+gfc_expr *
+gfc_hollerith2real (gfc_expr *src, int kind)
+{
+  gfc_expr *result;
+  result = gfc_get_constant_expr (BT_REAL, kind, &src->where);
 
-  result->value.character.string[kind] = '\0'; /* For debugger.  */
-  result->value.character.length = kind;
+  hollerith2representation (result, src);
+  gfc_interpret_float (kind, (unsigned char *) result->representation.string,
+                      result->representation.length, result->value.real);
 
   return result;
 }
@@ -2317,33 +2317,11 @@ gfc_expr *
 gfc_hollerith2complex (gfc_expr *src, int kind)
 {
   gfc_expr *result;
-  int len;
-
-  len = src->value.character.length;
-
-  result = gfc_get_expr ();
-  result->expr_type = EXPR_CONSTANT;
-  result->ts.type = BT_COMPLEX;
-  result->ts.kind = kind;
-  result->where = src->where;
-  result->from_H = 1;
+  result = gfc_get_constant_expr (BT_COMPLEX, kind, &src->where);
 
-  kind = kind * 2;
-
-  if (len > kind)
-    {
-      gfc_warning ("The Hollerith constant at %L is too long to convert to %s",
-                  &src->where, gfc_typename(&result->ts));
-    }
-  result->value.character.string = gfc_getmem (kind + 1);
-  memcpy (result->value.character.string, src->value.character.string,
-         MIN (kind, len));
-
-  if (len < kind)
-    memset (&result->value.character.string[len], ' ', kind - len);
-
-  result->value.character.string[kind] = '\0'; /* For debugger  */
-  result->value.character.length = kind;
+  hollerith2representation (result, src);
+  gfc_interpret_complex (kind, (unsigned char *) result->representation.string,
+                        result->representation.length, result->value.complex);
 
   return result;
 }
@@ -2359,7 +2337,10 @@ gfc_hollerith2character (gfc_expr *src, int kind)
   result = gfc_copy_expr (src);
   result->ts.type = BT_CHARACTER;
   result->ts.kind = kind;
-  result->from_H = 1;
+
+  result->value.character.length = result->representation.length;
+  result->value.character.string
+    = gfc_char_to_widechar (result->representation.string);
 
   return result;
 }
@@ -2371,76 +2352,11 @@ gfc_expr *
 gfc_hollerith2logical (gfc_expr *src, int kind)
 {
   gfc_expr *result;
-  int len;
-
-  len = src->value.character.length;
-
-  result = gfc_get_expr ();
-  result->expr_type = EXPR_CONSTANT;
-  result->ts.type = BT_LOGICAL;
-  result->ts.kind = kind;
-  result->where = src->where;
-  result->from_H = 1;
-
-  if (len > kind)
-    {
-      gfc_warning ("The Hollerith constant at %L is too long to convert to %s",
-                  &src->where, gfc_typename(&result->ts));
-    }
-  result->value.character.string = gfc_getmem (kind + 1);
-  memcpy (result->value.character.string, src->value.character.string,
-       MIN (kind, len));
-
-  if (len < kind)
-    memset (&result->value.character.string[len], ' ', kind - len);
-
-  result->value.character.string[kind] = '\0'; /* For debugger  */
-  result->value.character.length = kind;
-
-  return result;
-}
-
-
-/* Returns an initializer whose value is one higher than the value of the
-   LAST_INITIALIZER argument.  If the argument is NULL, the
-   initializers value will be set to zero.  The initializer's kind
-   will be set to gfc_c_int_kind.
-
-   If -fshort-enums is given, the appropriate kind will be selected
-   later after all enumerators have been parsed.  A warning is issued
-   here if an initializer exceeds gfc_c_int_kind.  */
-
-gfc_expr *
-gfc_enum_initializer (gfc_expr *last_initializer, locus where)
-{
-  gfc_expr *result;
-
-  result = gfc_get_expr ();
-  result->expr_type = EXPR_CONSTANT;
-  result->ts.type = BT_INTEGER;
-  result->ts.kind = gfc_c_int_kind;
-  result->where = where;
+  result = gfc_get_constant_expr (BT_LOGICAL, kind, &src->where);
 
-  mpz_init (result->value.integer);
-
-  if (last_initializer != NULL)
-    {
-      mpz_add_ui (result->value.integer, last_initializer->value.integer, 1);
-      result->where = last_initializer->where;
-
-      if (gfc_check_integer_range (result->value.integer,
-            gfc_c_int_kind) != ARITH_OK)
-       {
-         gfc_error ("Enumerator exceeds the C integer type at %C");
-         return NULL;
-       }
-    }
-  else
-    {
-      /* Control comes here, if it's the very first enumerator and no
-        initializer has been given.  It will be initialized to zero.  */
-      mpz_set_si (result->value.integer, 0);
-    }
+  hollerith2representation (result, src);
+  gfc_interpret_logical (kind, (unsigned char *) result->representation.string,
+                        result->representation.length, &result->value.logical);
 
   return result;
 }