compiler: Fix nil func panics, constant type conversions.
authorIan Lance Taylor <ian@gcc.gnu.org>
Mon, 3 Dec 2012 03:25:18 +0000 (03:25 +0000)
committerIan Lance Taylor <ian@gcc.gnu.org>
Mon, 3 Dec 2012 03:25:18 +0000 (03:25 +0000)
From-SVN: r194064

gcc/go/gofrontend/expressions.cc
gcc/go/gofrontend/expressions.h

index 571aa02..5fee256 100644 (file)
@@ -2965,46 +2965,6 @@ Type_conversion_expression::do_lower(Gogo*, Named_object*,
        {
          if (!nc.set_type(type, true, location))
            return Expression::make_error(location);
-
-         // Don't simply convert to or from a float or complex type
-         // with a different size.  That may change the value.
-         Type* vtype = val->type();
-         if (vtype->is_abstract())
-           ;
-         else if (type->float_type() != NULL)
-           {
-             if (vtype->float_type() != NULL)
-               {
-                 if (type->float_type()->bits() != vtype->float_type()->bits())
-                   return this;
-               }
-             else if (vtype->complex_type() != NULL)
-               {
-                 if (type->float_type()->bits() * 2
-                     != vtype->complex_type()->bits())
-                   return this;
-               }
-           }
-         else if (type->complex_type() != NULL)
-           {
-             if (vtype->complex_type() != NULL)
-               {
-                 if (type->complex_type()->bits()
-                     != vtype->complex_type()->bits())
-                   return this;
-               }
-             else if (vtype->float_type() != NULL)
-               {
-                 if (type->complex_type()->bits()
-                     != vtype->float_type()->bits() * 2)
-                   return this;
-               }
-           }
-         else if (vtype->float_type() != NULL)
-           return this;
-         else if (vtype->complex_type() != NULL)
-           return this;
-
          return nc.expression(location);
        }
     }
@@ -9239,6 +9199,9 @@ Call_expression::do_get_tree(Translate_context* context)
        }
     }
 
+  if (func == NULL)
+    fn = save_expr(fn);
+
   tree ret = build_call_array(excess_type != NULL_TREE ? excess_type : rettype,
                              fn, nargs, args);
   delete[] args;
@@ -9272,6 +9235,24 @@ Call_expression::do_get_tree(Translate_context* context)
   if (this->results_ != NULL)
     ret = this->set_results(context, ret);
 
+  // We can't unwind the stack past a call to nil, so we need to
+  // insert an explicit check so that the panic can be recovered.
+  if (func == NULL)
+    {
+      tree compare = fold_build2_loc(location.gcc_location(), EQ_EXPR,
+                                    boolean_type_node, fn,
+                                    fold_convert_loc(location.gcc_location(),
+                                                     TREE_TYPE(fn),
+                                                     null_pointer_node));
+      tree crash = build3_loc(location.gcc_location(), COND_EXPR,
+                             void_type_node, compare,
+                             gogo->runtime_error(RUNTIME_ERROR_NIL_DEREFERENCE,
+                                                 location),
+                             NULL_TREE);
+      ret = fold_build2_loc(location.gcc_location(), COMPOUND_EXPR,
+                           TREE_TYPE(ret), crash, ret);
+    }
+
   this->tree_ = ret;
 
   return ret;
@@ -14229,7 +14210,7 @@ Numeric_constant::check_int_type(Integer_type* type, bool issue_error,
 
 bool
 Numeric_constant::check_float_type(Float_type* type, bool issue_error,
-                                  Location location) const
+                                  Location location)
 {
   mpfr_t val;
   switch (this->classification_)
@@ -14282,6 +14263,29 @@ Numeric_constant::check_float_type(Float_type* type, bool issue_error,
        }
 
       ret = exp <= max_exp;
+
+      if (ret)
+       {
+         // Round the constant to the desired type.
+         mpfr_t t;
+         mpfr_init(t);
+         switch (type->bits())
+           {
+           case 32:
+             mpfr_set_prec(t, 24);
+             break;
+           case 64:
+             mpfr_set_prec(t, 53);
+             break;
+           default:
+             go_unreachable();
+           }
+         mpfr_set(t, val, GMP_RNDN);
+         mpfr_set(val, t, GMP_RNDN);
+         mpfr_clear(t);
+
+         this->set_float(type, val);
+       }
     }
 
   mpfr_clear(val);
@@ -14296,7 +14300,7 @@ Numeric_constant::check_float_type(Float_type* type, bool issue_error,
 
 bool
 Numeric_constant::check_complex_type(Complex_type* type, bool issue_error,
-                                    Location location) const
+                                    Location location)
 {
   if (type->is_abstract())
     return true;
@@ -14315,46 +14319,77 @@ Numeric_constant::check_complex_type(Complex_type* type, bool issue_error,
     }
 
   mpfr_t real;
+  mpfr_t imag;
   switch (this->classification_)
     {
     case NC_INT:
     case NC_RUNE:
       mpfr_init_set_z(real, this->u_.int_val, GMP_RNDN);
+      mpfr_init_set_ui(imag, 0, GMP_RNDN);
       break;
 
     case NC_FLOAT:
       mpfr_init_set(real, this->u_.float_val, GMP_RNDN);
+      mpfr_init_set_ui(imag, 0, GMP_RNDN);
       break;
 
     case NC_COMPLEX:
-      if (!mpfr_nan_p(this->u_.complex_val.imag)
-         && !mpfr_inf_p(this->u_.complex_val.imag)
-         && !mpfr_zero_p(this->u_.complex_val.imag))
-       {
-         if (mpfr_get_exp(this->u_.complex_val.imag) > max_exp)
-           {
-             if (issue_error)
-               error_at(location, "complex imaginary part overflow");
-             return false;
-           }
-       }
       mpfr_init_set(real, this->u_.complex_val.real, GMP_RNDN);
+      mpfr_init_set(imag, this->u_.complex_val.imag, GMP_RNDN);
       break;
 
     default:
       go_unreachable();
     }
 
-  bool ret;
-  if (mpfr_nan_p(real) || mpfr_inf_p(real) || mpfr_zero_p(real))
-    ret = true;
-  else
-    ret = mpfr_get_exp(real) <= max_exp;
+  bool ret = true;
+  if (!mpfr_nan_p(real)
+      && !mpfr_inf_p(real)
+      && !mpfr_zero_p(real)
+      && mpfr_get_exp(real) > max_exp)
+    {
+      if (issue_error)
+       error_at(location, "complex real part overflow");
+      ret = false;
+    }
 
-  mpfr_clear(real);
+  if (!mpfr_nan_p(imag)
+      && !mpfr_inf_p(imag)
+      && !mpfr_zero_p(imag)
+      && mpfr_get_exp(imag) > max_exp)
+    {
+      if (issue_error)
+       error_at(location, "complex imaginary part overflow");
+      ret = false;
+    }
 
-  if (!ret && issue_error)
-    error_at(location, "complex real part overflow");
+  if (ret)
+    {
+      // Round the constant to the desired type.
+      mpfr_t t;
+      mpfr_init(t);
+      switch (type->bits())
+       {
+       case 64:
+         mpfr_set_prec(t, 24);
+         break;
+       case 128:
+         mpfr_set_prec(t, 53);
+         break;
+       default:
+         go_unreachable();
+       }
+      mpfr_set(t, real, GMP_RNDN);
+      mpfr_set(real, t, GMP_RNDN);
+      mpfr_set(t, imag, GMP_RNDN);
+      mpfr_set(imag, t, GMP_RNDN);
+      mpfr_clear(t);
+
+      this->set_complex(type, real, imag);
+    }
+
+  mpfr_clear(real);
+  mpfr_clear(imag);
 
   return ret;
 }
index 7bc4242..eb4406d 100644 (file)
@@ -2224,10 +2224,10 @@ class Numeric_constant
   check_int_type(Integer_type*, bool, Location) const;
 
   bool
-  check_float_type(Float_type*, bool, Location) const;
+  check_float_type(Float_type*, bool, Location);
 
   bool
-  check_complex_type(Complex_type*, bool, Location) const;
+  check_complex_type(Complex_type*, bool, Location);
 
   // The kinds of constants.
   enum Classification