+2017-10-25  Ulrich Weigand  <uweigand@de.ibm.com>
+
+       * doublest.c (floatformat_from_string): New function.
+       * doublest.h (floatformat_from_string): Add prototype.
+
+       * std-operator.def (OP_DOUBLE, OP_DECFLOAT): Remove, replace by ...
+       (OP_FLOAT): ... this.
+       * expression.h: Do not include "doublest.h".
+       (union exp_element): Replace doubleconst and decfloatconst by
+       new element floatconst.
+       * ada-lang.c (resolve_subexp): Handle OP_FLOAT instead of OP_DOUBLE.
+       (ada_evaluate_subexp): Likewise.
+       * eval.c (evaluate_subexp_standard): Handle OP_FLOAT instead of
+       OP_DOUBLE and OP_DECFLOAT.
+       * expprint.c (print_subexp_standard): Likewise.
+       (dump_subexp_body_standard): Likewise.
+       * breakpoint.c (watchpoint_exp_is_const): Likewise.
+
+       * parse.c: Include "dfp.h".
+       (write_exp_elt_dblcst, write_exp_elt_decfloatcst): Remove.
+       (write_exp_elt_floatcst): New function.
+       (operator_length_standard): Handle OP_FLOAT instead of OP_DOUBLE
+       and OP_DECFLOAT.
+       (operator_check_standard): Likewise.
+       (parse_float): Do not accept suffix.  Take type as input.  Return bool.
+       Return target format buffer instead of host DOUBLEST.
+       Use floatformat_from_string and decimal_from_string to parse
+       either binary or decimal floating-point types.
+       (parse_c_float): Remove.
+       * parser-defs.h: Do not include "doublest.h".
+       (write_exp_elt_dblcst, write_exp_elt_decfloatcst): Remove.
+       (write_exp_elt_floatcst): Add prototype.
+       (parse_float): Update prototype.
+       (parse_c_float): Remove.
+
+       * c-exp.y: Do not include "dfp.h".
+       (typed_val_float): Use byte buffer instead of DOUBLEST.
+       (typed_val_decfloat): Remove.
+       (DECFLOAT): Remove.
+       (FLOAT): Use OP_FLOAT and write_exp_elt_floatcst.
+       (parse_number): Update to new parse_float interface.
+       Parse suffixes and determine type before calling parse_float.
+       Handle decimal and binary FP types the same way.
+
+       * d-exp.y (typed_val_float): Use byte buffer instead of DOUBLEST.
+       (FLOAT_LITERAL): Use OP_FLOAT and write_exp_elt_floatcst.
+       (parse_number): Update to new parse_float interface.
+       Parse suffixes and determine type before calling parse_float.
+
+       * f-exp.y: Replace dval by typed_val_float.
+       (FLOAT): Use OP_FLOAT and write_exp_elt_floatcst.
+       (parse_number): Use parse_float instead of atof.
+
+       * go-exp.y (typed_val_float): Use byte buffer instead of DOUBLEST.
+       (parse_go_float): Remove.
+       (FLOAT): Use OP_FLOAT and write_exp_elt_floatcst.
+       (parse_number): Call parse_float instead of parse_go_float.
+       Parse suffixes and determine type before calling parse_float.
+
+       * p-exp.y (typed_val_float): Use byte buffer instead of DOUBLEST.
+       (FLOAT): Use OP_FLOAT and write_exp_elt_floatcst.
+       (parse_number): Update to new parse_float interface.
+       Parse suffixes and determine type before calling parse_float.
+
+       * m2-exp.y: Replace dval by byte buffer val.
+       (FLOAT): Use OP_FLOAT and write_exp_elt_floatcst.
+       (parse_number): Call parse_float instead of atof.
+
+       * rust-exp.y (typed_val_float): Use byte buffer instead of DOUBLEST.
+       (lex_number): Call parse_float instead of strtod.
+       (ast_dliteral): Use OP_FLOAT instead of OP_DOUBLE.
+       (convert_ast_to_expression): Handle OP_FLOAT instead of OP_DOUBLE.
+       Use write_exp_elt_floatcst.
+       (unit_testing): Remove static variable.
+       (rust_type): Do not check unit_testing.
+       (rust_lex_tests): Do not set uint_testing.  Set up dummy rust_parser.
+
+       * ada-exp.y (type_float, type_double): Remove.
+       (typed_val_float): Use byte buffer instead of DOUBLEST.
+       (FLOAT): Use OP_FLOAT and write_exp_elt_floatcst.
+       * ada-lex.l (processReal): Use parse_float instead of sscanf.
+
 2017-10-25  Alan Hayward  <alan.hayward@arm.com>
 
        * aarch64-tdep.h (enum aarch64_regnum): Remove.
 
 
 static struct type *type_long_long (struct parser_state *);
 
-static struct type *type_float (struct parser_state *);
-
-static struct type *type_double (struct parser_state *);
-
 static struct type *type_long_double (struct parser_state *);
 
 static struct type *type_char (struct parser_state *);
       struct type *type;
     } typed_val;
     struct {
-      DOUBLEST dval;
+      gdb_byte val[16];
       struct type *type;
     } typed_val_float;
     struct type *tval;
        ;
 
 primary        :       FLOAT
-                       { write_exp_elt_opcode (pstate, OP_DOUBLE);
+                       { write_exp_elt_opcode (pstate, OP_FLOAT);
                          write_exp_elt_type (pstate, $1.type);
-                         write_exp_elt_dblcst (pstate, $1.dval);
-                         write_exp_elt_opcode (pstate, OP_DOUBLE);
+                         write_exp_elt_floatcst (pstate, $1.val);
+                         write_exp_elt_opcode (pstate, OP_FLOAT);
                        }
        ;
 
   return parse_type (par_state)->builtin_long_long;
 }
 
-static struct type *
-type_float (struct parser_state *par_state)
-{
-  return parse_type (par_state)->builtin_float;
-}
-
-static struct type *
-type_double (struct parser_state *par_state)
-{
-  return parse_type (par_state)->builtin_double;
-}
-
 static struct type *
 type_long_double (struct parser_state *par_state)
 {
 
       break;
 
     case OP_LONG:
-    case OP_DOUBLE:
+    case OP_FLOAT:
     case OP_VAR_VALUE:
     case OP_VAR_MSYM_VALUE:
       *pos += 4;
       if (noside == EVAL_NORMAL)
        arg1 = unwrap_value (arg1);
 
-      /* If evaluating an OP_DOUBLE and an EXPECT_TYPE was provided,
+      /* If evaluating an OP_FLOAT and an EXPECT_TYPE was provided,
          then we need to perform the conversion manually, because
          evaluate_subexp_standard doesn't do it.  This conversion is
          necessary in Ada because the different kinds of float/fixed
 
          Similarly, we need to perform the conversion from OP_LONG
          ourselves.  */
-      if ((op == OP_DOUBLE || op == OP_LONG) && expect_type != NULL)
+      if ((op == OP_FLOAT || op == OP_LONG) && expect_type != NULL)
         arg1 = ada_value_cast (expect_type, arg1, noside);
 
       return arg1;
 
 static int
 processReal (struct parser_state *par_state, const char *num0)
 {
-  sscanf (num0, "%" DOUBLEST_SCAN_FORMAT, &yylval.typed_val_float.dval);
-
-  yylval.typed_val_float.type = type_float (par_state);
-  if (sizeof(DOUBLEST) >= gdbarch_double_bit (parse_gdbarch (par_state))
-                           / TARGET_CHAR_BIT)
-    yylval.typed_val_float.type = type_double (par_state);
-  if (sizeof(DOUBLEST) >= gdbarch_long_double_bit (parse_gdbarch (par_state))
-                           / TARGET_CHAR_BIT)
-    yylval.typed_val_float.type = type_long_double (par_state);
+  yylval.typed_val_float.type = type_long_double (par_state);
 
+  bool parsed = parse_float (num0, strlen (num0),
+                            yylval.typed_val_float.type,
+                            yylval.typed_val_float.val);
+  gdb_assert (parsed);
   return FLOAT;
 }
 
 
        case TERNOP_SLICE:
 
        case OP_LONG:
-       case OP_DOUBLE:
-       case OP_DECFLOAT:
+       case OP_FLOAT:
        case OP_LAST:
        case OP_COMPLEX:
        case OP_STRING:
 
 #include "charset.h"
 #include "block.h"
 #include "cp-support.h"
-#include "dfp.h"
 #include "macroscope.h"
 #include "objc-lang.h"
 #include "typeprint.h"
       LONGEST val;
       struct type *type;
     } typed_val_int;
-    struct {
-      DOUBLEST dval;
-      struct type *type;
-    } typed_val_float;
     struct {
       gdb_byte val[16];
       struct type *type;
-    } typed_val_decfloat;
+    } typed_val_float;
     struct type *tval;
     struct stoken sval;
     struct typed_stoken tsval;
 
 %token <typed_val_int> INT
 %token <typed_val_float> FLOAT
-%token <typed_val_decfloat> DECFLOAT
 
 /* Both NAME and TYPENAME tokens represent symbols in the input,
    and both convey their data as strings.
 
 
 exp    :       FLOAT
-                       { write_exp_elt_opcode (pstate, OP_DOUBLE);
+                       { write_exp_elt_opcode (pstate, OP_FLOAT);
                          write_exp_elt_type (pstate, $1.type);
-                         write_exp_elt_dblcst (pstate, $1.dval);
-                         write_exp_elt_opcode (pstate, OP_DOUBLE); }
-       ;
-
-exp    :       DECFLOAT
-                       { write_exp_elt_opcode (pstate, OP_DECFLOAT);
-                         write_exp_elt_type (pstate, $1.type);
-                         write_exp_elt_decfloatcst (pstate, $1.val);
-                         write_exp_elt_opcode (pstate, OP_DECFLOAT); }
+                         write_exp_elt_floatcst (pstate, $1.val);
+                         write_exp_elt_opcode (pstate, OP_FLOAT); }
        ;
 
 exp    :       variable
 
   if (parsed_float)
     {
-      /* If it ends at "df", "dd" or "dl", take it as type of decimal floating
-         point.  Return DECFLOAT.  */
-
+      /* Handle suffixes for decimal floating-point: "df", "dd" or "dl".  */
       if (len >= 2 && p[len - 2] == 'd' && p[len - 1] == 'f')
        {
-         putithere->typed_val_decfloat.type
+         putithere->typed_val_float.type
            = parse_type (par_state)->builtin_decfloat;
-         decimal_from_string (putithere->typed_val_decfloat.val, 4,
-                              gdbarch_byte_order (parse_gdbarch (par_state)),
-                              std::string (p, len - 2));
-         return DECFLOAT;
+         len -= 2;
        }
-
-      if (len >= 2 && p[len - 2] == 'd' && p[len - 1] == 'd')
+      else if (len >= 2 && p[len - 2] == 'd' && p[len - 1] == 'd')
        {
-         putithere->typed_val_decfloat.type
+         putithere->typed_val_float.type
            = parse_type (par_state)->builtin_decdouble;
-         decimal_from_string (putithere->typed_val_decfloat.val, 8,
-                              gdbarch_byte_order (parse_gdbarch (par_state)),
-                              std::string (p, len - 2));
-         return DECFLOAT;
+         len -= 2;
        }
-
-      if (len >= 2 && p[len - 2] == 'd' && p[len - 1] == 'l')
+      else if (len >= 2 && p[len - 2] == 'd' && p[len - 1] == 'l')
        {
-         putithere->typed_val_decfloat.type
+         putithere->typed_val_float.type
            = parse_type (par_state)->builtin_declong;
-         decimal_from_string (putithere->typed_val_decfloat.val, 16,
-                              gdbarch_byte_order (parse_gdbarch (par_state)),
-                              std::string (p, len - 2));
-         return DECFLOAT;
+         len -= 2;
+       }
+      /* Handle suffixes: 'f' for float, 'l' for long double.  */
+      else if (len >= 1 && tolower (p[len - 1]) == 'f')
+       {
+         putithere->typed_val_float.type
+           = parse_type (par_state)->builtin_float;
+         len -= 1;
+       }
+      else if (len >= 1 && tolower (p[len - 1]) == 'l')
+       {
+         putithere->typed_val_float.type
+           = parse_type (par_state)->builtin_long_double;
+         len -= 1;
+       }
+      /* Default type for floating-point literals is double.  */
+      else
+       {
+         putithere->typed_val_float.type
+           = parse_type (par_state)->builtin_double;
        }
 
-      if (! parse_c_float (parse_gdbarch (par_state), p, len,
-                          &putithere->typed_val_float.dval,
-                          &putithere->typed_val_float.type))
-       return ERROR;
+      if (!parse_float (p, len,
+                       putithere->typed_val_float.type,
+                       putithere->typed_val_float.val))
+        return ERROR;
       return FLOAT;
     }
 
 
       struct type *type;
     } typed_val_int;
     struct {
-      DOUBLEST dval;
+      gdb_byte val[16];
       struct type *type;
     } typed_val_float;
     struct symbol *sym;
                  write_exp_elt_longcst (pstate, (LONGEST)($1.val));
                  write_exp_elt_opcode (pstate, OP_LONG); }
 |      FLOAT_LITERAL
-               { write_exp_elt_opcode (pstate, OP_DOUBLE);
+               { write_exp_elt_opcode (pstate, OP_FLOAT);
                  write_exp_elt_type (pstate, $1.type);
-                 write_exp_elt_dblcst (pstate, $1.dval);
-                 write_exp_elt_opcode (pstate, OP_DOUBLE); }
+                 write_exp_elt_floatcst (pstate, $1.val);
+                 write_exp_elt_opcode (pstate, OP_FLOAT); }
 |      CHARACTER_LITERAL
                { struct stoken_vector vec;
                  vec.len = 1;
 
   if (parsed_float)
     {
-      const char *suffix;
-      int suffix_len;
       char *s, *sp;
 
       /* Strip out all embedded '_' before passing to parse_float.  */
       *sp = '\0';
       len = strlen (s);
 
-      if (! parse_float (s, len, &putithere->typed_val_float.dval, &suffix))
-       return ERROR;
-
-      suffix_len = s + len - suffix;
-
-      if (suffix_len == 0)
-       {
-         putithere->typed_val_float.type
-           = parse_d_type (ps)->builtin_double;
-       }
-      else if (suffix_len == 1)
+      /* Check suffix for `i' , `fi' or `li' (idouble, ifloat or ireal).  */
+      if (len >= 1 && tolower (s[len - 1]) == 'i')
        {
-         /* Check suffix for `f', `l', or `i' (float, real, or idouble).  */
-         if (tolower (*suffix) == 'f')
+         if (len >= 2 && tolower (s[len - 2]) == 'f')
            {
              putithere->typed_val_float.type
-               = parse_d_type (ps)->builtin_float;
+               = parse_d_type (ps)->builtin_ifloat;
+             len -= 2;
            }
-         else if (tolower (*suffix) == 'l')
+         else if (len >= 2 && tolower (s[len - 2]) == 'l')
            {
              putithere->typed_val_float.type
-               = parse_d_type (ps)->builtin_real;
+               = parse_d_type (ps)->builtin_ireal;
+             len -= 2;
            }
-         else if (tolower (*suffix) == 'i')
+         else
            {
              putithere->typed_val_float.type
                = parse_d_type (ps)->builtin_idouble;
+             len -= 1;
            }
-         else
-           return ERROR;
        }
-      else if (suffix_len == 2)
+      /* Check suffix for `f' or `l'' (float or real).  */
+      else if (len >= 1 && tolower (s[len - 1]) == 'f')
        {
-         /* Check suffix for `fi' or `li' (ifloat or ireal).  */
-         if (tolower (suffix[0]) == 'f' && tolower (suffix[1] == 'i'))
-           {
-             putithere->typed_val_float.type
-               = parse_d_type (ps)->builtin_ifloat;
-           }
-         else if (tolower (suffix[0]) == 'l' && tolower (suffix[1] == 'i'))
-           {
-             putithere->typed_val_float.type
-               = parse_d_type (ps)->builtin_ireal;
-           }
-         else
-           return ERROR;
+         putithere->typed_val_float.type
+           = parse_d_type (ps)->builtin_float;
+         len -= 1;
        }
+      else if (len >= 1 && tolower (s[len - 1]) == 'l')
+       {
+         putithere->typed_val_float.type
+           = parse_d_type (ps)->builtin_real;
+         len -= 1;
+       }
+      /* Default type if no suffix.  */
       else
+       {
+         putithere->typed_val_float.type
+           = parse_d_type (ps)->builtin_double;
+       }
+
+      if (!parse_float (s, len,
+                       putithere->typed_val_float.type,
+                       putithere->typed_val_float.val))
        return ERROR;
 
       return FLOAT_LITERAL;
 
   floatformat_to_doublest (fmt, in, &doub);
   return string_printf (host_format.c_str (), doub);
 }
+
+/* Parse string STRING into a target floating-number of format FMT and
+   store it as byte-stream ADDR.  Return whether parsing succeeded.  */
+bool
+floatformat_from_string (const struct floatformat *fmt, gdb_byte *out,
+                        const std::string &in)
+{
+  DOUBLEST doub;
+  int n, num;
+#ifdef HAVE_LONG_DOUBLE
+  const char *scan_format = "%Lg%n";
+#else
+  const char *scan_format = "%lg%n";
+#endif
+  num = sscanf (in.c_str (), scan_format, &doub, &n);
+
+  /* The sscanf man page suggests not making any assumptions on the effect
+     of %n on the result, so we don't.
+     That is why we simply test num == 0.  */
+  if (num == 0)
+    return false;
+
+  /* We only accept the whole string.  */
+  if (in[n])
+    return false;
+
+  floatformat_from_doublest (fmt, &doub, out);
+  return true;
+}
 \f
 /* Extract a floating-point number of type TYPE from a target-order
    byte-stream at ADDR.  Returns the value as type DOUBLEST.  */
 
 extern std::string floatformat_to_string (const struct floatformat *fmt,
                                          const gdb_byte *in,
                                          const char *format = nullptr);
+extern bool floatformat_from_string (const struct floatformat *fmt,
+                                    gdb_byte *out, const std::string &in);
 
 /* Return the floatformat's total size in host bytes.  */
 
 
       return value_from_longest (exp->elts[pc + 1].type,
                                 exp->elts[pc + 2].longconst);
 
-    case OP_DOUBLE:
+    case OP_FLOAT:
       (*pos) += 3;
-      return value_from_double (exp->elts[pc + 1].type,
-                               exp->elts[pc + 2].doubleconst);
-
-    case OP_DECFLOAT:
-      (*pos) += 3;
-      return value_from_decfloat (exp->elts[pc + 1].type,
-                                 exp->elts[pc + 2].decfloatconst);
+      return value_from_contents (exp->elts[pc + 1].type,
+                                 exp->elts[pc + 2].floatconst);
 
     case OP_ADL_FUNC:
     case OP_VAR_VALUE:
 
       }
       return;
 
-    case OP_DOUBLE:
+    case OP_FLOAT:
       {
        struct value_print_options opts;
 
        get_no_prettyformat_print_options (&opts);
        (*pos) += 3;
-       value_print (value_from_double (exp->elts[pc + 1].type,
-                                       exp->elts[pc + 2].doubleconst),
+       value_print (value_from_contents (exp->elts[pc + 1].type,
+                                         exp->elts[pc + 2].floatconst),
                     stream, &opts);
       }
       return;
                        (long) exp->elts[elt + 1].longconst);
       elt += 3;
       break;
-    case OP_DOUBLE:
+    case OP_FLOAT:
       fprintf_filtered (stream, "Type @");
       gdb_print_host_address (exp->elts[elt].type, stream);
       fprintf_filtered (stream, " (");
       type_print (exp->elts[elt].type, NULL, stream, 0);
-      fprintf_filtered (stream, "), value %g",
-                       (double) exp->elts[elt + 1].doubleconst);
+      fprintf_filtered (stream, "), value ");
+      print_floating (exp->elts[elt + 1].floatconst,
+                     exp->elts[elt].type, stream);
       elt += 3;
       break;
     case OP_VAR_VALUE:
 
 
 
 #include "symtab.h"            /* Needed for "struct block" type.  */
-#include "doublest.h"          /* Needed for DOUBLEST.  */
 
 
 /* Definitions for saved C expressions.  */
     struct symbol *symbol;
     struct minimal_symbol *msymbol;
     LONGEST longconst;
-    DOUBLEST doubleconst;
-    gdb_byte decfloatconst[16];
+    gdb_byte floatconst[16];
     /* Really sizeof (union exp_element) characters (or less for the last
        element of a string).  */
     char string;
 
       LONGEST val;
       struct type *type;
     } typed_val;
-    DOUBLEST dval;
+    struct {
+      gdb_byte val[16];
+      struct type *type;
+    } typed_val_float;
     struct symbol *sym;
     struct type *tval;
     struct stoken sval;
 %type <tval> ptype
 
 %token <typed_val> INT
-%token <dval> FLOAT
+%token <typed_val_float> FLOAT
 
 /* Both NAME and TYPENAME tokens represent symbols in the input,
    and both convey their data as strings.
        ;
 
 exp    :       FLOAT
-                       { write_exp_elt_opcode (pstate, OP_DOUBLE);
-                         write_exp_elt_type (pstate,
-                                             parse_f_type (pstate)
-                                             ->builtin_real_s8);
-                         write_exp_elt_dblcst (pstate, $1);
-                         write_exp_elt_opcode (pstate, OP_DOUBLE); }
+                       { write_exp_elt_opcode (pstate, OP_FLOAT);
+                         write_exp_elt_type (pstate, $1.type);
+                         write_exp_elt_floatcst (pstate, $1.val);
+                         write_exp_elt_opcode (pstate, OP_FLOAT); }
        ;
 
 exp    :       variable
   if (parsed_float)
     {
       /* It's a float since it contains a point or an exponent.  */
-      /* [dD] is not understood as an exponent by atof, change it to 'e'.  */
+      /* [dD] is not understood as an exponent by parse_float,
+        change it to 'e'.  */
       char *tmp, *tmp2;
 
       tmp = xstrdup (p);
       for (tmp2 = tmp; *tmp2; ++tmp2)
        if (*tmp2 == 'd' || *tmp2 == 'D')
          *tmp2 = 'e';
-      putithere->dval = atof (tmp);
+
+      /* FIXME: Should this use different types?  */
+      putithere->typed_val_float.type = parse_f_type (pstate)->builtin_real_s8;
+      bool parsed = parse_float (tmp, len,
+                                putithere->typed_val_float.type,
+                                putithere->typed_val_float.val);
       free (tmp);
-      return FLOAT;
+      return parsed? FLOAT : ERROR;
     }
 
   /* Handle base-switching prefixes 0x, 0t, 0d, 0 */
 
       struct type *type;
     } typed_val_int;
     struct {
-      DOUBLEST dval;
+      gdb_byte val[16];
       struct type *type;
     } typed_val_float;
     struct stoken sval;
 /* YYSTYPE gets defined by %union.  */
 static int parse_number (struct parser_state *,
                         const char *, int, int, YYSTYPE *);
-static int parse_go_float (struct gdbarch *gdbarch, const char *p, int len,
-                          DOUBLEST *d, struct type **t);
 %}
 
 %type <voidval> exp exp1 type_exp start variable lcurly
 
 
 exp    :       FLOAT
-                       { write_exp_elt_opcode (pstate, OP_DOUBLE);
+                       { write_exp_elt_opcode (pstate, OP_FLOAT);
                          write_exp_elt_type (pstate, $1.type);
-                         write_exp_elt_dblcst (pstate, $1.dval);
-                         write_exp_elt_opcode (pstate, OP_DOUBLE); }
+                         write_exp_elt_floatcst (pstate, $1.val);
+                         write_exp_elt_opcode (pstate, OP_FLOAT); }
        ;
 
 exp    :       variable
 
 %%
 
-/* Wrapper on parse_c_float to get the type right for Go.  */
-
-static int
-parse_go_float (struct gdbarch *gdbarch, const char *p, int len,
-               DOUBLEST *d, struct type **t)
-{
-  int result = parse_c_float (gdbarch, p, len, d, t);
-  const struct builtin_type *builtin_types = builtin_type (gdbarch);
-  const struct builtin_go_type *builtin_go_types = builtin_go_type (gdbarch);
-
-  if (*t == builtin_types->builtin_float)
-    *t = builtin_go_types->builtin_float32;
-  else if (*t == builtin_types->builtin_double)
-    *t = builtin_go_types->builtin_float64;
-
-  return result;
-}
-
 /* Take care of parsing a number (anything that starts with a digit).
    Set yylval and return the token type; update lexptr.
    LEN is the number of characters in it.  */
 
   if (parsed_float)
     {
-      if (! parse_go_float (parse_gdbarch (par_state), p, len,
-                           &putithere->typed_val_float.dval,
-                           &putithere->typed_val_float.type))
-       return ERROR;
+      const struct builtin_go_type *builtin_go_types
+       = builtin_go_type (parse_gdbarch (par_state));
+
+      /* Handle suffixes: 'f' for float32, 'l' for long double.
+        FIXME: This appears to be an extension -- do we want this?  */
+      if (len >= 1 && tolower (p[len - 1]) == 'f')
+       {
+         putithere->typed_val_float.type
+           = builtin_go_types->builtin_float32;
+         len--;
+       }
+      else if (len >= 1 && tolower (p[len - 1]) == 'l')
+       {
+         putithere->typed_val_float.type
+           = parse_type (par_state)->builtin_long_double;
+         len--;
+       }
+      /* Default type for floating-point literals is float64.  */
+      else
+        {
+         putithere->typed_val_float.type
+           = builtin_go_types->builtin_float64;
+        }
+
+      if (!parse_float (p, len,
+                       putithere->typed_val_float.type,
+                       putithere->typed_val_float.val))
+        return ERROR;
       return FLOAT;
     }
 
 
   {
     LONGEST lval;
     ULONGEST ulval;
-    DOUBLEST dval;
+    gdb_byte val[16];
     struct symbol *sym;
     struct type *tval;
     struct stoken sval;
 
 %token <lval> INT HEX ERROR
 %token <ulval> UINT M2_TRUE M2_FALSE CHAR
-%token <dval> FLOAT
+%token <val> FLOAT
 
 /* Both NAME and TYPENAME tokens represent symbols in the input,
    and both convey their data as strings.
 
 
 exp    :       FLOAT
-                       { write_exp_elt_opcode (pstate, OP_DOUBLE);
+                       { write_exp_elt_opcode (pstate, OP_FLOAT);
                          write_exp_elt_type (pstate,
                                              parse_m2_type (pstate)
                                              ->builtin_real);
-                         write_exp_elt_dblcst (pstate, $1);
-                         write_exp_elt_opcode (pstate, OP_DOUBLE); }
+                         write_exp_elt_floatcst (pstate, $1);
+                         write_exp_elt_opcode (pstate, OP_FLOAT); }
        ;
 
 exp    :       variable
     if (p[c] == '.' && base == 10)
       {
        /* It's a float since it contains a point.  */
-       yylval.dval = atof (p);
+       if (!parse_float (p, len,
+                         parse_m2_type (pstate)->builtin_real,
+                         yylval.val))
+         return ERROR;
+
        lexptr += len;
        return FLOAT;
       }
 
       struct type *type;
     } typed_val_int;
     struct {
-      DOUBLEST dval;
+      gdb_byte val[16];
       struct type *type;
     } typed_val_float;
     struct symbol *sym;
 
 
 exp    :       FLOAT
-                       { write_exp_elt_opcode (pstate, OP_DOUBLE);
+                       { write_exp_elt_opcode (pstate, OP_FLOAT);
                          write_exp_elt_type (pstate, $1.type);
                          current_type = $1.type;
-                         write_exp_elt_dblcst (pstate, $1.dval);
-                         write_exp_elt_opcode (pstate, OP_DOUBLE); }
+                         write_exp_elt_floatcst (pstate, $1.val);
+                         write_exp_elt_opcode (pstate, OP_FLOAT); }
        ;
 
 exp    :       variable
 
   if (parsed_float)
     {
-      if (! parse_c_float (parse_gdbarch (par_state), p, len,
-                          &putithere->typed_val_float.dval,
-                          &putithere->typed_val_float.type))
+      /* Handle suffixes: 'f' for float, 'l' for long double.
+         FIXME: This appears to be an extension -- do we want this?  */
+      if (len >= 1 && tolower (p[len - 1]) == 'f')
+       {
+         putithere->typed_val_float.type
+           = parse_type (par_state)->builtin_float;
+         len--;
+       }
+      else if (len >= 1 && tolower (p[len - 1]) == 'l')
+       {
+         putithere->typed_val_float.type
+           = parse_type (par_state)->builtin_long_double;
+         len--;
+       }
+      /* Default type for floating-point literals is double.  */
+      else
+       {
+         putithere->typed_val_float.type
+           = parse_type (par_state)->builtin_double;
+       }
+
+      if (!parse_float (p, len,
+                       putithere->typed_val_float.type,
+                       putithere->typed_val_float.val))
        return ERROR;
       return FLOAT;
     }
 
 #include "symfile.h"           /* for overlay functions */
 #include "inferior.h"
 #include "doublest.h"
+#include "dfp.h"
 #include "block.h"
 #include "source.h"
 #include "objfiles.h"
 }
 
 void
-write_exp_elt_dblcst (struct parser_state *ps, DOUBLEST expelt)
-{
-  union exp_element tmp;
-
-  memset (&tmp, 0, sizeof (union exp_element));
-  tmp.doubleconst = expelt;
-  write_exp_elt (ps, &tmp);
-}
-
-void
-write_exp_elt_decfloatcst (struct parser_state *ps, gdb_byte expelt[16])
+write_exp_elt_floatcst (struct parser_state *ps, const gdb_byte expelt[16])
 {
   union exp_element tmp;
   int index;
 
   for (index = 0; index < 16; index++)
-    tmp.decfloatconst[index] = expelt[index];
+    tmp.floatconst[index] = expelt[index];
 
   write_exp_elt (ps, &tmp);
 }
       break;
 
     case OP_LONG:
-    case OP_DOUBLE:
-    case OP_DECFLOAT:
+    case OP_FLOAT:
     case OP_VAR_VALUE:
     case OP_VAR_MSYM_VALUE:
       oplen = 4;
 }
 
 /* Parse floating point value P of length LEN.
-   Return 0 (false) if invalid, 1 (true) if valid.
-   The successfully parsed number is stored in D.
-   *SUFFIX points to the suffix of the number in P.
+   Return false if invalid, true if valid.
+   The successfully parsed number is stored in DATA in
+   target format for floating-point type TYPE.
 
    NOTE: This accepts the floating point syntax that sscanf accepts.  */
 
-int
-parse_float (const char *p, int len, DOUBLEST *d, const char **suffix)
-{
-  char *copy;
-  int n, num;
-
-  copy = (char *) xmalloc (len + 1);
-  memcpy (copy, p, len);
-  copy[len] = 0;
-
-  num = sscanf (copy, "%" DOUBLEST_SCAN_FORMAT "%n", d, &n);
-  xfree (copy);
-
-  /* The sscanf man page suggests not making any assumptions on the effect
-     of %n on the result, so we don't.
-     That is why we simply test num == 0.  */
-  if (num == 0)
-    return 0;
-
-  *suffix = p + n;
-  return 1;
-}
-
-/* Parse floating point value P of length LEN, using the C syntax for floats.
-   Return 0 (false) if invalid, 1 (true) if valid.
-   The successfully parsed number is stored in *D.
-   Its type is taken from builtin_type (gdbarch) and is stored in *T.  */
-
-int
-parse_c_float (struct gdbarch *gdbarch, const char *p, int len,
-              DOUBLEST *d, struct type **t)
+bool
+parse_float (const char *p, int len,
+            const struct type *type, gdb_byte *data)
 {
-  const char *suffix;
-  int suffix_len;
-  const struct builtin_type *builtin_types = builtin_type (gdbarch);
-
-  if (! parse_float (p, len, d, &suffix))
-    return 0;
-
-  suffix_len = p + len - suffix;
-
-  if (suffix_len == 0)
-    *t = builtin_types->builtin_double;
-  else if (suffix_len == 1)
-    {
-      /* Handle suffixes: 'f' for float, 'l' for long double.  */
-      if (tolower (*suffix) == 'f')
-       *t = builtin_types->builtin_float;
-      else if (tolower (*suffix) == 'l')
-       *t = builtin_types->builtin_long_double;
-      else
-       return 0;
-    }
+  if (TYPE_CODE (type) == TYPE_CODE_FLT)
+    return floatformat_from_string (floatformat_from_type (type),
+                                   data, std::string (p, len));
   else
-    return 0;
-
-  return 1;
+    return decimal_from_string (data, TYPE_LENGTH (type),
+                               gdbarch_byte_order (get_type_arch (type)),
+                               std::string (p, len));
 }
 \f
 /* Stuff for maintaining a stack of types.  Currently just used by C, but
     {
     case BINOP_VAL:
     case OP_COMPLEX:
-    case OP_DECFLOAT:
-    case OP_DOUBLE:
+    case OP_FLOAT:
     case OP_LONG:
     case OP_SCOPE:
     case OP_TYPE:
 
 #if !defined (PARSER_DEFS_H)
 #define PARSER_DEFS_H 1
 
-#include "doublest.h"
 #include "vec.h"
 #include "expression.h"
 
 
 extern void write_exp_elt_longcst (struct parser_state *, LONGEST);
 
-extern void write_exp_elt_dblcst (struct parser_state *, DOUBLEST);
-
-extern void write_exp_elt_decfloatcst (struct parser_state *, gdb_byte *);
+extern void write_exp_elt_floatcst (struct parser_state *, const gdb_byte *);
 
 extern void write_exp_elt_type (struct parser_state *, struct type *);
 
 
 extern void null_post_parser (struct expression **, int);
 
-extern int parse_float (const char *p, int len, DOUBLEST *d,
-                       const char **suffix);
-
-extern int parse_c_float (struct gdbarch *gdbarch, const char *p, int len,
-                         DOUBLEST *d, struct type **t);
+extern bool parse_float (const char *p, int len,
+                        const struct type *type, gdb_byte *data);
 
 /* During parsing of a C expression, the pointer to the next character
    is in this variable.  */
 
 
 struct typed_val_float
 {
-  DOUBLEST dval;
+  gdb_byte val[16];
   struct type *type;
 };
 
 
 static regex_t number_regex;
 
-/* True if we're running unit tests.  */
-
-static int unit_testing;
-
 /* Obstack for data temporarily allocated during parsing.  Points to
    the obstack in the rust_parser, or to a temporary obstack during
    unit testing.  */
 {
   struct type *type;
 
-  /* When unit testing, we don't bother checking the types, so avoid a
-     possibly-failing lookup here.  */
-  if (unit_testing)
-    return NULL;
-
   type = language_lookup_primitive_type (current_parser->language (),
                                         current_parser->arch (),
                                         name);
     }
   else
     {
-      rustyylval.typed_val_float.dval = strtod (number.c_str (), NULL);
       rustyylval.typed_val_float.type = type;
+      bool parsed = parse_float (number.c_str (), number.length (),
+                                rustyylval.typed_val_float.type,
+                                rustyylval.typed_val_float.val);
+      gdb_assert (parsed);
     }
 
   return is_integer ? (could_be_decimal ? DECIMAL_INTEGER : INTEGER) : FLOAT;
 {
   struct rust_op *result = OBSTACK_ZALLOC (work_obstack, struct rust_op);
 
-  result->opcode = OP_DOUBLE;
+  result->opcode = OP_FLOAT;
   result->left.typed_val_float = val;
 
   return result;
       write_exp_elt_opcode (state, OP_LONG);
       break;
 
-    case OP_DOUBLE:
-      write_exp_elt_opcode (state, OP_DOUBLE);
+    case OP_FLOAT:
+      write_exp_elt_opcode (state, OP_FLOAT);
       write_exp_elt_type (state, operation->left.typed_val_float.type);
-      write_exp_elt_dblcst (state, operation->left.typed_val_float.dval);
-      write_exp_elt_opcode (state, OP_DOUBLE);
+      write_exp_elt_floatcst (state, operation->left.typed_val_float.val);
+      write_exp_elt_opcode (state, OP_FLOAT);
       break;
 
     case STRUCTOP_STRUCT:
   scoped_restore obstack_holder = make_scoped_restore (&work_obstack,
                                                       &test_obstack);
 
-  unit_testing = 1;
+  // Set up dummy "parser", so that rust_type works.
+  struct parser_state ps;
+  initialize_expout (&ps, 0, &rust_language_defn, target_gdbarch ());
+  rust_parser parser (&ps);
 
   rust_lex_test_one ("", 0);
   rust_lex_test_one ("    \t  \n \r  ", 0);
 
   rust_lex_test_completion ();
   rust_lex_test_push_back ();
-
-  unit_testing = 0;
 }
 
 #endif /* GDB_SELF_TEST */
 
    Thus, the operation occupies four exp_elements.  */
 OP (OP_LONG)
 
-/* OP_DOUBLE is similar but takes a DOUBLEST constant instead of a
-   long.  */
-OP (OP_DOUBLE)
+/* OP_FLOAT is similar but takes a floating-point constant encoded in
+   the target format for the given type instead of a long.  */
+OP (OP_FLOAT)
 
 /* OP_VAR_VALUE takes one struct block * in the following element,
    and one struct symbol * in the following exp_element, followed
    ":exp" and ":").  */
 OP (OP_RANGE)
 
-/* OP_DECFLOAT is followed by a type pointer in the next exp_element
-   and a dec long constant value in the following exp_element.
-   Then comes another OP_DECFLOAT.  */
-OP (OP_DECFLOAT)
-
 /* OP_ADL_FUNC specifies that the function is to be looked up in an
    Argument Dependent manner (Koenig lookup).  */
 OP (OP_ADL_FUNC)