compiler: introduce size threshold for nil checks
authorThan McIntosh <thanm@google.com>
Fri, 1 Dec 2017 23:12:13 +0000 (23:12 +0000)
committerIan Lance Taylor <ian@gcc.gnu.org>
Fri, 1 Dec 2017 23:12:13 +0000 (23:12 +0000)
    Add a new control variable to the Gogo class that stores the size
    threshold for nil checks. This value can be used to control the
    policy for deciding when a given deference operation needs a check and
    when it does not. A size threshold of -1 means that every potentially
    faulting dereference needs an explicit check (and branch to error
    call). A size threshold of K (where K > 0) means that if the size of
    the object being dereferenced is >= K, then we need a check.

    Reviewed-on: https://go-review.googlesource.com/80996

* go-c.h (go_create_gogo_args): Add nil_check_size_threshold
field.
* go-lang.c (go_langhook_init): Set nil_check_size_threshold.

From-SVN: r255340

13 files changed:
gcc/go/ChangeLog
gcc/go/go-c.h
gcc/go/go-lang.c
gcc/go/gofrontend/MERGE
gcc/go/gofrontend/expressions.cc
gcc/go/gofrontend/expressions.h
gcc/go/gofrontend/go.cc
gcc/go/gofrontend/gogo.cc
gcc/go/gofrontend/gogo.h
gcc/go/gofrontend/parse.cc
gcc/go/gofrontend/statements.cc
gcc/go/gofrontend/types.cc
gcc/go/gofrontend/wb.cc

index 01af4678684ab862efa8c0f4e74e996ecc553cd6..26f823e0442d0522ba800cb6abc4da2dc8d333fb 100644 (file)
@@ -1,3 +1,9 @@
+2017-12-01  Than McIntosh  <thanm@google.com>
+
+       * go-c.h (go_create_gogo_args): Add nil_check_size_threshold
+       field.
+       * go-lang.c (go_langhook_init): Set nil_check_size_threshold.
+
 2017-11-28  Jakub Jelinek  <jakub@redhat.com>
 
        * go-gcc.cc (Gcc_backend::switch_statement): Build SWITCH_EXPR using
index 029b5d5f6bd4f6b5f9a220578dd49fd497e0dbb3..f5a1bde51b26b856ce5d7eb371bd1dcd56200f7b 100644 (file)
@@ -47,6 +47,7 @@ struct go_create_gogo_args
   bool check_divide_overflow;
   bool compiling_runtime;
   int debug_escape_level;
+  int64_t nil_check_size_threshold;
 };
 
 extern void go_create_gogo (const struct go_create_gogo_args*);
index 81eeb5c9cdcea54709470635463d843a3c0ce400..fda069aee6dbe0f823e33d8b590531339a11fa03 100644 (file)
@@ -112,6 +112,7 @@ go_langhook_init (void)
   args.check_divide_overflow = go_check_divide_overflow;
   args.compiling_runtime = go_compiling_runtime;
   args.debug_escape_level = go_debug_escape_level;
+  args.nil_check_size_threshold = 4096;
   args.linemap = go_get_linemap();
   args.backend = go_get_backend();
   go_create_gogo (&args);
index 9aee310c9b8164543f0c531a2ff2ede02f01dad2..ca329c2de32be8da9bdb6dde81a77e64cb1c5279 100644 (file)
@@ -1,4 +1,4 @@
-0d6b3abcbfe04949db947081651a503ceb12fe6e
+8cd42a3e9e0e618bb09e67be73f7d2f2477a0faa
 
 The first line of this file holds the git revision number of the last
 merge done from the gofrontend repository.
index 7f816110d6264b167bccd90c81221fb9dee3a30c..e9b86831dc9a8db5edb2a4b829cd2df3334b3384 100644 (file)
@@ -290,7 +290,7 @@ Expression::get_interface_type_descriptor(Expression* rhs)
       Expression::make_interface_info(rhs, INTERFACE_INFO_METHODS, location);
 
   Expression* descriptor =
-      Expression::make_unary(OPERATOR_MULT, mtable, location);
+      Expression::make_dereference(mtable, NIL_CHECK_NOT_NEEDED, location);
   descriptor = Expression::make_field_reference(descriptor, 0, location);
   Expression* nil = Expression::make_nil(location);
 
@@ -393,7 +393,8 @@ Expression::convert_interface_to_type(Type *lhs_type, Expression* rhs,
     {
       obj = Expression::make_unsafe_cast(Type::make_pointer_type(lhs_type), obj,
                                          location);
-      obj = Expression::make_unary(OPERATOR_MULT, obj, location);
+      obj = Expression::make_dereference(obj, NIL_CHECK_NOT_NEEDED,
+                                         location);
     }
   return Expression::make_compound(check_iface, obj, location);
 }
@@ -3842,24 +3843,20 @@ Unary_expression::do_flatten(Gogo* gogo, Named_object*,
       && !this->expr_->is_variable())
     {
       go_assert(this->expr_->type()->points_to() != NULL);
-      Type* ptype = this->expr_->type()->points_to();
-      if (!ptype->is_void_type())
+      switch (this->requires_nil_check(gogo))
         {
-          int64_t s;
-          bool ok = ptype->backend_type_size(gogo, &s);
-          if (!ok)
+          case NIL_CHECK_ERROR_ENCOUNTERED:
             {
               go_assert(saw_errors());
               return Expression::make_error(this->location());
             }
-          if (s >= 4096 || this->issue_nil_check_)
-            {
-              Temporary_statement* temp =
-                  Statement::make_temporary(NULL, this->expr_, location);
-              inserter->insert(temp);
-              this->expr_ =
-                  Expression::make_temporary_reference(temp, location);
-            }
+          case NIL_CHECK_NOT_NEEDED:
+            break;
+          case NIL_CHECK_NEEDED:
+            this->create_temp_ = true;
+            break;
+          case NIL_CHECK_DEFAULT:
+            go_unreachable();
         }
     }
 
@@ -3960,6 +3957,41 @@ Unary_expression::base_is_static_initializer(Expression* expr)
   return false;
 }
 
+// Return whether this dereference expression requires an explicit nil
+// check. If we are dereferencing the pointer to a large struct
+// (greater than the specified size threshold), we need to check for
+// nil. We don't bother to check for small structs because we expect
+// the system to crash on a nil pointer dereference. However, if we
+// know the address of this expression is being taken, we must always
+// check for nil.
+Unary_expression::Nil_check_classification
+Unary_expression::requires_nil_check(Gogo* gogo) 
+{
+  go_assert(this->op_ == OPERATOR_MULT);
+  go_assert(this->expr_->type()->points_to() != NULL);
+
+  if (this->issue_nil_check_ == NIL_CHECK_NEEDED)
+    return NIL_CHECK_NEEDED;
+  else if (this->issue_nil_check_ == NIL_CHECK_NOT_NEEDED)
+    return NIL_CHECK_NOT_NEEDED;
+
+  Type* ptype = this->expr_->type()->points_to();
+  int64_t type_size = -1;
+  if (!ptype->is_void_type())
+    {
+      bool ok = ptype->backend_type_size(gogo, &type_size);
+      if (!ok)
+        return NIL_CHECK_ERROR_ENCOUNTERED;
+    }
+
+  int64_t size_cutoff = gogo->nil_check_size_threshold();
+  if (size_cutoff == -1 || (type_size != -1 && type_size >= size_cutoff))
+    this->issue_nil_check_ = NIL_CHECK_NEEDED;
+  else
+    this->issue_nil_check_ = NIL_CHECK_NOT_NEEDED;
+  return this->issue_nil_check_;
+}
+
 // Apply unary opcode OP to UNC, setting NC.  Return true if this
 // could be done, false if not.  On overflow, issues an error and sets
 // *ISSUED_ERROR.
@@ -4408,43 +4440,42 @@ Unary_expression::do_get_backend(Translate_context* context)
       {
         go_assert(this->expr_->type()->points_to() != NULL);
 
-       // If we are dereferencing the pointer to a large struct, we
-       // need to check for nil.  We don't bother to check for small
-       // structs because we expect the system to crash on a nil
-       // pointer dereference.  However, if we know the address of this
-       // expression is being taken, we must always check for nil.
-
+        bool known_valid = false;
         Type* ptype = this->expr_->type()->points_to();
         Btype* pbtype = ptype->get_backend(gogo);
-        if (!ptype->is_void_type())
-         {
-            int64_t s;
-            bool ok = ptype->backend_type_size(gogo, &s);
-            if (!ok)
+        switch (this->requires_nil_check(gogo))
+          {
+            case NIL_CHECK_NOT_NEEDED:
+              break;
+            case NIL_CHECK_ERROR_ENCOUNTERED:
               {
                 go_assert(saw_errors());
                 return gogo->backend()->error_expression();
               }
-           if (s >= 4096 || this->issue_nil_check_)
-             {
+            case NIL_CHECK_NEEDED:
+              {
                 go_assert(this->expr_->is_variable());
                 Bexpression* nil =
-                 Expression::make_nil(loc)->get_backend(context);
+                    Expression::make_nil(loc)->get_backend(context);
                 Bexpression* compare =
                     gogo->backend()->binary_expression(OPERATOR_EQEQ, bexpr,
                                                        nil, loc);
                 Bexpression* crash =
-                 gogo->runtime_error(RUNTIME_ERROR_NIL_DEREFERENCE,
-                                     loc)->get_backend(context);
+                    gogo->runtime_error(RUNTIME_ERROR_NIL_DEREFERENCE,
+                                        loc)->get_backend(context);
                 Bfunction* bfn = context->function()->func_value()->get_decl();
                 bexpr = gogo->backend()->conditional_expression(bfn, btype,
                                                                 compare,
                                                                 crash, bexpr,
                                                                 loc);
-
-             }
-         }
-        ret = gogo->backend()->indirect_expression(pbtype, bexpr, false, loc);
+                known_valid = true;
+                break;
+              }
+            case NIL_CHECK_DEFAULT:
+              go_unreachable();
+          }
+        ret = gogo->backend()->indirect_expression(pbtype, bexpr,
+                                                   known_valid, loc);
       }
       break;
 
@@ -4529,6 +4560,19 @@ Expression::make_unary(Operator op, Expression* expr, Location location)
   return new Unary_expression(op, expr, location);
 }
 
+Expression*
+Expression::make_dereference(Expression* ptr,
+                             Nil_check_classification docheck,
+                             Location location)
+{
+  Expression* deref = Expression::make_unary(OPERATOR_MULT, ptr, location);
+  if (docheck == NIL_CHECK_NEEDED)
+    deref->unary_expression()->set_requires_nil_check(true);
+  else if (docheck == NIL_CHECK_NOT_NEEDED)
+    deref->unary_expression()->set_requires_nil_check(false);
+  return deref;
+}
+
 // If this is an indirection through a pointer, return the expression
 // being pointed through.  Otherwise return this.
 
@@ -6829,7 +6873,7 @@ Bound_method_expression::create_thunk(Gogo* gogo, const Method* method,
   // Field 0 of the closure is the function code pointer, field 1 is
   // the value on which to invoke the method.
   Expression* arg = Expression::make_var_reference(cp, loc);
-  arg = Expression::make_unary(OPERATOR_MULT, arg, loc);
+  arg = Expression::make_dereference(arg, NIL_CHECK_NOT_NEEDED, loc);
   arg = Expression::make_field_reference(arg, 1, loc);
 
   Expression* bme = Expression::make_bound_method(arg, method, fn, loc);
@@ -6893,7 +6937,8 @@ bme_check_nil(const Method::Field_indexes* field_indexes, Location loc,
                                              Expression::make_nil(loc),
                                              loc);
       cond = Expression::make_binary(OPERATOR_OROR, cond, n, loc);
-      *ref = Expression::make_unary(OPERATOR_MULT, *ref, loc);
+      *ref = Expression::make_dereference(*ref, Expression::NIL_CHECK_DEFAULT,
+                                          loc);
       go_assert((*ref)->type()->struct_type() == stype);
     }
   *ref = Expression::make_field_reference(*ref, field_indexes->field_index,
@@ -6948,7 +6993,7 @@ Bound_method_expression::do_flatten(Gogo* gogo, Named_object*,
   Expression* val = expr;
   if (fntype->receiver()->type()->points_to() == NULL
       && val->type()->points_to() != NULL)
-    val = Expression::make_unary(OPERATOR_MULT, val, loc);
+    val = Expression::make_dereference(val, NIL_CHECK_DEFAULT, loc);
 
   // Note that we are ignoring this->expr_type_ here.  The thunk will
   // expect a closure whose second field has type this->expr_type_ (if
@@ -8919,7 +8964,8 @@ Builtin_call_expression::do_get_backend(Translate_context* context)
            arg_type = arg_type->points_to();
            go_assert(arg_type->array_type() != NULL
                       && !arg_type->is_slice_type());
-            arg = Expression::make_unary(OPERATOR_MULT, arg, location);
+            arg = Expression::make_dereference(arg, NIL_CHECK_DEFAULT,
+                                               location);
          }
 
        Type* int_type = Type::lookup_integer_type("int");
@@ -8953,8 +8999,9 @@ Builtin_call_expression::do_get_backend(Translate_context* context)
                                                          arg, nil, location);
                Expression* zero = Expression::make_integer_ul(0, int_type,
                                                               location);
-               Expression* indir = Expression::make_unary(OPERATOR_MULT,
-                                                          arg, location);
+                Expression* indir =
+                    Expression::make_dereference(arg, NIL_CHECK_NOT_NEEDED,
+                                                 location);
                val = Expression::make_conditional(cmp, zero, indir, location);
              }
            else
@@ -8995,8 +9042,9 @@ Builtin_call_expression::do_get_backend(Translate_context* context)
                                                          arg, nil, location);
                Expression* zero = Expression::make_integer_ul(0, int_type,
                                                               location);
-               Expression* indir = Expression::make_unary(OPERATOR_MULT,
-                                                          parg, location);
+                Expression* indir =
+                    Expression::make_dereference(parg, NIL_CHECK_NOT_NEEDED,
+                                                 location);
                val = Expression::make_conditional(cmp, zero, indir, location);
              }
            else
@@ -10274,7 +10322,7 @@ Call_expression::do_get_backend(Translate_context* context)
           Type::make_pointer_type(
               Type::make_pointer_type(Type::make_void_type()));
       fn = Expression::make_unsafe_cast(pfntype, this->fn_, location);
-      fn = Expression::make_unary(OPERATOR_MULT, fn, location);
+      fn = Expression::make_dereference(fn, NIL_CHECK_NOT_NEEDED, location);
     }
   else
     {
@@ -10532,8 +10580,8 @@ Index_expression::do_lower(Gogo*, Named_object*, Statement_inserter*, int)
           && type->points_to()->array_type() != NULL
           && !type->points_to()->is_slice_type())
     {
-      Expression* deref = Expression::make_unary(OPERATOR_MULT, left,
-                                                location);
+      Expression* deref =
+          Expression::make_dereference(left, NIL_CHECK_DEFAULT, location);
 
       // For an ordinary index into the array, the pointer will be
       // dereferenced.  For a slice it will not--the resulting slice
@@ -11297,7 +11345,8 @@ String_index_expression::do_get_backend(Translate_context* context)
   Location loc = this->location();
   Expression* string_arg = this->string_;
   if (this->string_->type()->points_to() != NULL)
-    string_arg = Expression::make_unary(OPERATOR_MULT, this->string_, loc);
+    string_arg = Expression::make_dereference(this->string_,
+                                              NIL_CHECK_NOT_NEEDED, loc);
 
   Expression* bad_index = Expression::check_bounds(this->start_, loc);
 
@@ -11531,8 +11580,9 @@ Map_index_expression::do_get_backend(Translate_context* context)
   go_assert(this->value_pointer_ != NULL
             && this->value_pointer_->is_variable());
 
-  Expression* val = Expression::make_unary(OPERATOR_MULT, this->value_pointer_,
-                                          this->location());
+  Expression* val = Expression::make_dereference(this->value_pointer_,
+                                                 NIL_CHECK_NOT_NEEDED,
+                                                 this->location());
   return val->get_backend(context);
 }
 
@@ -11768,7 +11818,7 @@ Interface_field_reference_expression::get_function()
   Expression* ref = this->expr_;
   Location loc = this->location();
   if (ref->type()->points_to() != NULL)
-    ref = Expression::make_unary(OPERATOR_MULT, ref, loc);
+    ref = Expression::make_dereference(ref, NIL_CHECK_DEFAULT, loc);
 
   Expression* mtable =
       Expression::make_interface_info(ref, INTERFACE_INFO_METHODS, loc);
@@ -11778,7 +11828,8 @@ Interface_field_reference_expression::get_function()
   unsigned int index;
   const Struct_field* field = mtable_type->find_local_field(name, &index);
   go_assert(field != NULL);
-  mtable = Expression::make_unary(OPERATOR_MULT, mtable, loc);
+
+  mtable = Expression::make_dereference(mtable, NIL_CHECK_NOT_NEEDED, loc);
   return Expression::make_field_reference(mtable, index, loc);
 }
 
@@ -11790,7 +11841,8 @@ Interface_field_reference_expression::get_underlying_object()
 {
   Expression* expr = this->expr_;
   if (expr->type()->points_to() != NULL)
-    expr = Expression::make_unary(OPERATOR_MULT, expr, this->location());
+    expr = Expression::make_dereference(expr, NIL_CHECK_DEFAULT,
+                                        this->location());
   return Expression::make_interface_info(expr, INTERFACE_INFO_OBJECT,
                                          this->location());
 }
@@ -11963,7 +12015,7 @@ Interface_field_reference_expression::create_thunk(Gogo* gogo,
   // Field 0 of the closure is the function code pointer, field 1 is
   // the value on which to invoke the method.
   Expression* arg = Expression::make_var_reference(cp, loc);
-  arg = Expression::make_unary(OPERATOR_MULT, arg, loc);
+  arg = Expression::make_dereference(arg, NIL_CHECK_NOT_NEEDED, loc);
   arg = Expression::make_field_reference(arg, 1, loc);
 
   Expression *ifre = Expression::make_interface_field_reference(arg, name,
index 9f58f497f8e48885d25dc9be573d1157ac0cb278..9de734e636f342fba3d4c9606f5364dffe5a6598 100644 (file)
@@ -506,6 +506,23 @@ class Expression
   static Expression*
   make_backend(Bexpression*, Type*, Location);
 
+  enum Nil_check_classification
+    {
+      // Use the default policy for deciding if this deref needs a check.
+      NIL_CHECK_DEFAULT,
+      // An explicit check is required for this dereference operation.
+      NIL_CHECK_NEEDED,
+      // No check needed for this dereference operation.
+      NIL_CHECK_NOT_NEEDED,
+      // A type error or error construct was encountered when determining
+      // whether this deref needs an explicit check.
+      NIL_CHECK_ERROR_ENCOUNTERED
+    };
+
+  // Make a dereference expression.
+  static Expression*
+  make_dereference(Expression*, Nil_check_classification, Location);
+
   // Return the expression classification.
   Expression_classification
   classification() const
@@ -1730,7 +1747,8 @@ class Unary_expression : public Expression
   Unary_expression(Operator op, Expression* expr, Location location)
     : Expression(EXPRESSION_UNARY, location),
       op_(op), escapes_(true), create_temp_(false), is_gc_root_(false),
-      is_slice_init_(false), expr_(expr), issue_nil_check_(false)
+      is_slice_init_(false), expr_(expr),
+      issue_nil_check_(NIL_CHECK_DEFAULT)
   { }
 
   // Return the operator.
@@ -1792,6 +1810,17 @@ class Unary_expression : public Expression
   static Expression*
   do_import(Import*);
 
+  // Declare that this deref does or does not require an explicit nil check.
+  void
+  set_requires_nil_check(bool needed)
+  {
+    go_assert(this->op_ == OPERATOR_MULT);
+    if (needed)
+      this->issue_nil_check_ = NIL_CHECK_NEEDED;
+    else
+      this->issue_nil_check_ = NIL_CHECK_NOT_NEEDED;
+  }
+
  protected:
   int
   do_traverse(Traverse* traverse)
@@ -1847,12 +1876,20 @@ class Unary_expression : public Expression
 
   void
   do_issue_nil_check()
-  { this->issue_nil_check_ = (this->op_ == OPERATOR_MULT); }
+  {
+    if (this->op_ == OPERATOR_MULT)
+      this->set_requires_nil_check(true);
+  }
 
  private:
   static bool
   base_is_static_initializer(Expression*);
 
+  // Return a determination as to whether this dereference expression
+  // requires a nil check.
+  Nil_check_classification
+  requires_nil_check(Gogo*);
+
   // The unary operator to apply.
   Operator op_;
   // Normally true.  False if this is an address expression which does
@@ -1874,7 +1911,7 @@ class Unary_expression : public Expression
   Expression* expr_;
   // Whether or not to issue a nil check for this expression if its address
   // is being taken.
-  bool issue_nil_check_;
+  Nil_check_classification issue_nil_check_;
 };
 
 // A binary expression.
index e3f17bccbefc8d99983eba6084579de2488f8904..a2b8cecb3fe9eab2b54c99ea74249c0d5098dbe3 100644 (file)
@@ -41,6 +41,7 @@ go_create_gogo(const struct go_create_gogo_args* args)
   if (args->c_header != NULL)
     ::gogo->set_c_header(args->c_header);
   ::gogo->set_debug_escape_level(args->debug_escape_level);
+  ::gogo->set_nil_check_size_threshold(args->nil_check_size_threshold);
 }
 
 // Parse the input files.
index 54617360060022b163c2d90b8c50c8227620938f..74b45958f619fe0a42379de7868e045569aaef7f 100644 (file)
@@ -55,6 +55,7 @@ Gogo::Gogo(Backend* backend, Linemap* linemap, int, int pointer_size)
     check_divide_overflow_(true),
     compiling_runtime_(false),
     debug_escape_level_(0),
+    nil_check_size_threshold_(4096),
     verify_types_(),
     interface_types_(),
     specific_type_functions_(),
@@ -5567,7 +5568,10 @@ Function::build(Gogo* gogo, Named_object* named_function)
               vars.push_back(bvar);
              Expression* parm_ref =
                   Expression::make_var_reference(parm_no, loc);
-             parm_ref = Expression::make_unary(OPERATOR_MULT, parm_ref, loc);
+              parm_ref =
+                  Expression::make_dereference(parm_ref,
+                                               Expression::NIL_CHECK_DEFAULT,
+                                               loc);
              if ((*p)->var_value()->is_in_heap())
                parm_ref = Expression::make_heap_expression(parm_ref, loc);
               var_inits.push_back(parm_ref->get_backend(&context));
index 338770f5c3c0ebaf15614d71f95af7fe3a13a0cf..e48a89926c888e6f8f7564e5acccba59d0fa08f9 100644 (file)
@@ -318,6 +318,20 @@ class Gogo
   set_debug_escape_level(int level)
   { this->debug_escape_level_ = level; }
 
+  // Return the size threshold used to determine whether to issue
+  // a nil-check for a given pointer dereference. A threshold of -1
+  // implies that all potentially faulting dereference ops should
+  // be nil-checked. A positive threshold of N implies that a deref
+  // of *P where P has size less than N doesn't need a nil check.
+  int64_t
+  nil_check_size_threshold() const
+  { return this->nil_check_size_threshold_; }
+
+  // Set the nil-check size threshold, as described above.
+  void
+  set_nil_check_size_threshold(int64_t bytes)
+  { this->nil_check_size_threshold_ = bytes; }
+
   // Import a package.  FILENAME is the file name argument, LOCAL_NAME
   // is the local name to give to the package.  If LOCAL_NAME is empty
   // the declarations are added to the global scope.
@@ -1025,6 +1039,8 @@ class Gogo
   // The level of escape analysis debug information to emit, from the
   // -fgo-debug-escape option.
   int debug_escape_level_;
+  // Nil-check size threshhold.
+  int64_t nil_check_size_threshold_;
   // A list of types to verify.
   std::vector<Type*> verify_types_;
   // A list of interface types defined while parsing.
index f7d53af6e2131b980711299c27d3cabc632388cf..be6f3f163391911e33fe5df998e504acbabe1f5d 100644 (file)
@@ -2745,14 +2745,17 @@ Parse::enclosing_var_reference(Named_object* in_function, Named_object* var,
 
   Expression* closure_ref = Expression::make_var_reference(closure,
                                                           location);
-  closure_ref = Expression::make_unary(OPERATOR_MULT, closure_ref, location);
+  closure_ref =
+      Expression::make_dereference(closure_ref,
+                                   Expression::NIL_CHECK_DEFAULT,
+                                   location);
 
   // The closure structure holds pointers to the variables, so we need
   // to introduce an indirection.
   Expression* e = Expression::make_field_reference(closure_ref,
                                                   ins.first->index(),
                                                   location);
-  e = Expression::make_unary(OPERATOR_MULT, e, location);
+  e = Expression::make_dereference(e, Expression::NIL_CHECK_DEFAULT, location);
   return Expression::make_enclosing_var_reference(e, var, location);
 }
 
index e97798008ea6408c234390156646c2b624fc243f..d3878a6ba0561c4e41ae7bdcb85b5786b5e65d5e 100644 (file)
@@ -315,7 +315,8 @@ Variable_declaration_statement::do_get_backend(Translate_context* context)
   if (binit != NULL)
     {
       Expression* e = Expression::make_temporary_reference(temp, loc);
-      e = Expression::make_unary(OPERATOR_MULT, e, loc);
+      e = Expression::make_dereference(e, Expression::NIL_CHECK_NOT_NEEDED,
+                                       loc);
       Bexpression* be = e->get_backend(context);
       set = context->backend()->assignment_statement(bfunction, be, binit, loc);
     }
@@ -740,7 +741,9 @@ Assignment_statement::do_lower(Gogo*, Named_object*, Block* enclosing,
                                            a1, a2, a3);
       Type* ptrval_type = Type::make_pointer_type(mt->val_type());
       call = Expression::make_cast(ptrval_type, call, loc);
-      Expression* indir = Expression::make_unary(OPERATOR_MULT, call, loc);
+      Expression* indir =
+          Expression::make_dereference(call, Expression::NIL_CHECK_NOT_NEEDED,
+                                       loc);
       ref = Expression::make_temporary_reference(val_temp, loc);
       b->add_statement(Statement::make_assignment(indir, ref, loc));
 
@@ -1292,7 +1295,8 @@ Tuple_map_assignment_statement::do_lower(Gogo* gogo, Named_object*,
 
   // val = *val__ptr_temp
   ref = Expression::make_temporary_reference(val_ptr_temp, loc);
-  Expression* ind = Expression::make_unary(OPERATOR_MULT, ref, loc);
+  Expression* ind =
+      Expression::make_dereference(ref, Expression::NIL_CHECK_NOT_NEEDED, loc);
   s = Statement::make_assignment(this->val_, ind, loc);
   b->add_statement(s);
 
@@ -2367,8 +2371,10 @@ Thunk_statement::build_thunk(Gogo* gogo, const std::string& thunk_name)
   // ones used in build_struct.
   Expression* thunk_parameter = Expression::make_var_reference(named_parameter,
                                                               location);
-  thunk_parameter = Expression::make_unary(OPERATOR_MULT, thunk_parameter,
-                                          location);
+  thunk_parameter =
+      Expression::make_dereference(thunk_parameter,
+                                   Expression::NIL_CHECK_NOT_NEEDED,
+                                   location);
 
   Interface_field_reference_expression* interface_method =
     ce->fn()->interface_field_reference_expression();
@@ -2421,8 +2427,10 @@ Thunk_statement::build_thunk(Gogo* gogo, const std::string& thunk_name)
            {
              Expression* thunk_param =
                Expression::make_var_reference(named_parameter, location);
-             thunk_param =
-               Expression::make_unary(OPERATOR_MULT, thunk_param, location);
+             thunk_param =
+                 Expression::make_dereference(thunk_param,
+                                              Expression::NIL_CHECK_NOT_NEEDED,
+                                              location);
              param = Expression::make_field_reference(thunk_param,
                                                       next_index,
                                                       location);
@@ -5837,7 +5845,8 @@ For_range_statement::lower_range_map(Gogo* gogo,
   Expression* lhs = Expression::make_temporary_reference(index_temp, loc);
   Expression* rhs = Expression::make_temporary_reference(hiter, loc);
   rhs = Expression::make_field_reference(ref, 0, loc);
-  rhs = Expression::make_unary(OPERATOR_MULT, ref, loc);
+  rhs = Expression::make_dereference(ref, Expression::NIL_CHECK_NOT_NEEDED,
+                                     loc);
   Statement* set = Statement::make_assignment(lhs, rhs, loc);
   iter_init->add_statement(set);
 
@@ -5846,7 +5855,8 @@ For_range_statement::lower_range_map(Gogo* gogo,
       lhs = Expression::make_temporary_reference(value_temp, loc);
       rhs = Expression::make_temporary_reference(hiter, loc);
       rhs = Expression::make_field_reference(rhs, 1, loc);
-      rhs = Expression::make_unary(OPERATOR_MULT, rhs, loc);
+      rhs = Expression::make_dereference(rhs, Expression::NIL_CHECK_NOT_NEEDED,
+                                         loc);
       set = Statement::make_assignment(lhs, rhs, loc);
       iter_init->add_statement(set);
     }
index 2c8d1437040e32b8d0f53a2d00f3cac89af6b618..2274c3134678d0c6112795fbd21b2374e8a4f0ec 100644 (file)
@@ -2215,10 +2215,10 @@ Type::write_named_equal(Gogo* gogo, Named_type* name)
 
   // Compare the values for equality.
   Expression* t1 = Expression::make_temporary_reference(p1, bloc);
-  t1 = Expression::make_unary(OPERATOR_MULT, t1, bloc);
+  t1 = Expression::make_dereference(t1, Expression::NIL_CHECK_NOT_NEEDED, bloc);
 
   Expression* t2 = Expression::make_temporary_reference(p2, bloc);
-  t2 = Expression::make_unary(OPERATOR_MULT, t2, bloc);
+  t2 = Expression::make_dereference(t2, Expression::NIL_CHECK_NOT_NEEDED, bloc);
 
   Expression* cond = Expression::make_binary(OPERATOR_EQEQ, t1, t2, bloc);
 
@@ -5911,7 +5911,9 @@ Struct_type::field_reference_depth(Expression* struct_expr,
          Expression* here = Expression::make_field_reference(struct_expr, i,
                                                              location);
          if (pf->type()->points_to() != NULL)
-           here = Expression::make_unary(OPERATOR_MULT, here, location);
+            here = Expression::make_dereference(here,
+                                                Expression::NIL_CHECK_DEFAULT,
+                                                location);
          while (sub->expr() != NULL)
            {
              sub = sub->expr()->deref()->field_reference_expression();
@@ -6342,11 +6344,13 @@ Struct_type::write_equal_function(Gogo* gogo, Named_type* name)
 
       // Compare one field in both P1 and P2.
       Expression* f1 = Expression::make_temporary_reference(p1, bloc);
-      f1 = Expression::make_unary(OPERATOR_MULT, f1, bloc);
+      f1 = Expression::make_dereference(f1, Expression::NIL_CHECK_DEFAULT,
+                                        bloc);
       f1 = Expression::make_field_reference(f1, field_index, bloc);
 
       Expression* f2 = Expression::make_temporary_reference(p2, bloc);
-      f2 = Expression::make_unary(OPERATOR_MULT, f2, bloc);
+      f2 = Expression::make_dereference(f2, Expression::NIL_CHECK_DEFAULT,
+                                        bloc);
       f2 = Expression::make_field_reference(f2, field_index, bloc);
 
       Expression* cond = Expression::make_binary(OPERATOR_NOTEQ, f1, f2, bloc);
@@ -7193,12 +7197,12 @@ Array_type::write_equal_function(Gogo* gogo, Named_type* name)
 
   // Compare element in P1 and P2.
   Expression* e1 = Expression::make_temporary_reference(p1, bloc);
-  e1 = Expression::make_unary(OPERATOR_MULT, e1, bloc);
+  e1 = Expression::make_dereference(e1, Expression::NIL_CHECK_DEFAULT, bloc);
   ref = Expression::make_temporary_reference(index, bloc);
   e1 = Expression::make_array_index(e1, ref, NULL, NULL, bloc);
 
   Expression* e2 = Expression::make_temporary_reference(p2, bloc);
-  e2 = Expression::make_unary(OPERATOR_MULT, e2, bloc);
+  e2 = Expression::make_dereference(e2, Expression::NIL_CHECK_DEFAULT, bloc);
   ref = Expression::make_temporary_reference(index, bloc);
   e2 = Expression::make_array_index(e2, ref, NULL, NULL, bloc);
 
@@ -11219,7 +11223,8 @@ Type::apply_field_indexes(Expression* expr,
   if (expr->type()->struct_type() == NULL)
     {
       go_assert(expr->type()->points_to() != NULL);
-      expr = Expression::make_unary(OPERATOR_MULT, expr, location);
+      expr = Expression::make_dereference(expr, Expression::NIL_CHECK_DEFAULT,
+                                          location);
       go_assert(expr->type()->struct_type() == stype);
     }
   return Expression::make_field_reference(expr, field_indexes->field_index,
@@ -11323,7 +11328,8 @@ Type::bind_field_or_method(Gogo* gogo, const Type* type, Expression* expr,
       && type->points_to() != NULL
       && type->points_to()->points_to() != NULL)
     {
-      expr = Expression::make_unary(OPERATOR_MULT, expr, location);
+      expr = Expression::make_dereference(expr, Expression::NIL_CHECK_DEFAULT,
+                                          location);
       type = type->points_to();
       if (type->deref()->is_error_type())
        return Expression::make_error(location);
@@ -11356,8 +11362,9 @@ Type::bind_field_or_method(Gogo* gogo, const Type* type, Expression* expr,
                   return Expression::make_error(location);
                 }
              go_assert(type->points_to() != NULL);
-             expr = Expression::make_unary(OPERATOR_MULT, expr,
-                                           location);
+              expr = Expression::make_dereference(expr,
+                                                  Expression::NIL_CHECK_DEFAULT,
+                                                  location);
              go_assert(expr->type()->struct_type() == st);
            }
          ret = st->field_reference(expr, name, location);
index d0226fca6bb592671a9d71a47a5755c73237dc44..0085667ee046068490fbf25fb094f279e89b6609 100644 (file)
@@ -417,7 +417,8 @@ Gogo::assign_with_write_barrier(Function* function, Block* enclosing,
       rhs = Expression::make_temporary_reference(rhs_temp, loc);
     }
 
-  Expression* indir = Expression::make_unary(OPERATOR_MULT, lhs, loc);
+  Expression* indir =
+      Expression::make_dereference(lhs, Expression::NIL_CHECK_DEFAULT, loc);
   Statement* assign = Statement::make_assignment(indir, rhs, loc);
 
   lhs = Expression::make_temporary_reference(lhs_temp, loc);