diff mbox

Go patch committed: Use backend interface for slice info

Message ID mcra9f449tq.fsf@iant-glaptop.roam.corp.google.com
State New
Headers show

Commit Message

Ian Lance Taylor Jan. 10, 2014, 6:42 a.m. UTC
This patch from Chris Manghane changes gccgo to use the backend
interface for slice info.  Bootstrapped and ran Go testsuite on
x86_64-unknown-linux-gnu.  Committed to mainline.

Ian
diff mbox

Patch

diff -r 44fc257ad7f2 go/expressions.cc
--- a/go/expressions.cc	Thu Jan 09 15:25:44 2014 -0800
+++ b/go/expressions.cc	Thu Jan 09 22:31:00 2014 -0800
@@ -3060,6 +3060,9 @@ 
   Expression*
   do_lower(Gogo*, Named_object*, Statement_inserter*, int);
 
+  Expression*
+  do_flatten(Gogo*, Named_object*, Statement_inserter*);
+
   bool
   do_is_constant() const;
 
@@ -3203,6 +3206,25 @@ 
   return this;
 }
 
+// Flatten a type conversion by using a temporary variable for the slice
+// in slice to string conversions.
+
+Expression*
+Type_conversion_expression::do_flatten(Gogo*, Named_object*,
+                                       Statement_inserter* inserter)
+{
+  if (this->type()->is_string_type()
+      && this->expr_->type()->is_slice_type()
+      && !this->expr_->is_variable())
+    {
+      Temporary_statement* temp =
+          Statement::make_temporary(NULL, this->expr_, this->location());
+      inserter->insert(temp);
+      this->expr_ = Expression::make_temporary_reference(temp, this->location());
+    }
+  return this;
+}
+
 // Return whether a type conversion is a constant.
 
 bool
@@ -3361,47 +3383,24 @@ 
     }
   else if (type->is_string_type() && expr_type->is_slice_type())
     {
-      if (!DECL_P(expr_tree))
-	expr_tree = save_expr(expr_tree);
-
-      Type* int_type = Type::lookup_integer_type("int");
-      tree int_type_tree = type_to_tree(int_type->get_backend(gogo));
-
+      Location location = this->location();
       Array_type* a = expr_type->array_type();
       Type* e = a->element_type()->forwarded();
       go_assert(e->integer_type() != NULL);
-      tree valptr = fold_convert(const_ptr_type_node,
-				 a->value_pointer_tree(gogo, expr_tree));
-      tree len = a->length_tree(gogo, expr_tree);
-      len = fold_convert_loc(this->location().gcc_location(), int_type_tree,
-                             len);
+      go_assert(this->expr_->is_variable());
+
+      Runtime::Function code;
       if (e->integer_type()->is_byte())
-	{
-	  static tree byte_array_to_string_fndecl;
-	  ret = Gogo::call_builtin(&byte_array_to_string_fndecl,
-				   this->location(),
-				   "__go_byte_array_to_string",
-				   2,
-				   type_tree,
-				   const_ptr_type_node,
-				   valptr,
-				   int_type_tree,
-				   len);
-	}
+        code = Runtime::BYTE_ARRAY_TO_STRING;
       else
-	{
-	  go_assert(e->integer_type()->is_rune());
-	  static tree int_array_to_string_fndecl;
-	  ret = Gogo::call_builtin(&int_array_to_string_fndecl,
-				   this->location(),
-				   "__go_int_array_to_string",
-				   2,
-				   type_tree,
-				   const_ptr_type_node,
-				   valptr,
-				   int_type_tree,
-				   len);
-	}
+        {
+          go_assert(e->integer_type()->is_rune());
+          code = Runtime::INT_ARRAY_TO_STRING;
+        }
+      Expression* valptr = a->get_value_pointer(gogo, this->expr_);
+      Expression* len = a->get_length(gogo, this->expr_);
+      Expression* a2s_expr = Runtime::make_call(code, location, 2, valptr, len);
+      ret = a2s_expr->get_tree(context);
     }
   else if (type->is_slice_type() && expr_type->is_string_type())
     {
@@ -6595,6 +6594,7 @@ 
     {
       std::swap(left_type, right_type);
       std::swap(left_tree, right_tree);
+      std::swap(left_expr, right_expr);
     }
 
   if (right_type->is_nil_type())
@@ -6603,7 +6603,8 @@ 
 	  && left_type->array_type()->length() == NULL)
 	{
 	  Array_type* at = left_type->array_type();
-	  left_tree = at->value_pointer_tree(context->gogo(), left_tree);
+          left_expr = at->get_value_pointer(context->gogo(), left_expr);
+          left_tree = left_expr->get_tree(context);
 	  right_tree = fold_convert(TREE_TYPE(left_tree), null_pointer_node);
 	}
       else if (left_type->interface_type() != NULL)
@@ -7037,6 +7038,9 @@ 
   Expression*
   do_lower(Gogo*, Named_object*, Statement_inserter*, int);
 
+  Expression*
+  do_flatten(Gogo*, Named_object*, Statement_inserter*);
+
   bool
   do_is_constant() const;
 
@@ -7367,6 +7371,36 @@ 
   return this;
 }
 
+// Flatten a builtin call expression.  This turns the arguments of copy and
+// append into temporary expressions.
+
+Expression*
+Builtin_call_expression::do_flatten(Gogo*, Named_object*,
+                                    Statement_inserter* inserter)
+{
+  if (this->code_ == BUILTIN_APPEND
+      || this->code_ == BUILTIN_COPY)
+    {
+      Location loc = this->location();
+      Type* at = this->args()->front()->type();
+      for (Expression_list::iterator pa = this->args()->begin();
+           pa != this->args()->end();
+           ++pa)
+        {
+          if ((*pa)->is_nil_expression())
+            *pa = Expression::make_slice_composite_literal(at, NULL, loc);
+          if (!(*pa)->is_variable())
+            {
+              Temporary_statement* temp =
+                  Statement::make_temporary(NULL, *pa, loc);
+              inserter->insert(temp);
+              *pa = Expression::make_temporary_reference(temp, loc);
+            }
+        }
+    }
+  return this;
+}
+
 // Lower a make expression.
 
 Expression*
@@ -8503,7 +8537,8 @@ 
 		    return error_mark_node;
 		  }
 		this->seen_ = true;
-		val_tree = arg_type->array_type()->length_tree(gogo, arg_tree);
+		Expression* len = arg_type->array_type()->get_length(gogo, arg);
+		val_tree = len->get_tree(context);
 		this->seen_ = false;
 	      }
 	    else if (arg_type->map_type() != NULL)
@@ -8543,8 +8578,9 @@ 
 		    return error_mark_node;
 		  }
 		this->seen_ = true;
-		val_tree = arg_type->array_type()->capacity_tree(gogo,
-								 arg_tree);
+		Expression* cap =
+		    arg_type->array_type()->get_capacity(gogo, arg);
+		val_tree = cap->get_tree(context);
 		this->seen_ = false;
 	      }
 	    else if (arg_type->channel_type() != NULL)
@@ -8848,9 +8884,11 @@ 
 
 	Type* arg1_type = arg1->type();
 	Array_type* at = arg1_type->array_type();
-	arg1_tree = save_expr(arg1_tree);
-	tree arg1_val = at->value_pointer_tree(gogo, arg1_tree);
-	tree arg1_len = at->length_tree(gogo, arg1_tree);
+	go_assert(arg1->is_variable());
+	Expression* arg1_valptr = at->get_value_pointer(gogo, arg1);
+	Expression* arg1_len_expr = at->get_length(gogo, arg1);
+	tree arg1_val = arg1_valptr->get_tree(context);
+	tree arg1_len = arg1_len_expr->get_tree(context);
 	if (arg1_val == error_mark_node || arg1_len == error_mark_node)
 	  return error_mark_node;
 
@@ -8860,9 +8898,11 @@ 
 	if (arg2_type->is_slice_type())
 	  {
 	    at = arg2_type->array_type();
-	    arg2_tree = save_expr(arg2_tree);
-	    arg2_val = at->value_pointer_tree(gogo, arg2_tree);
-	    arg2_len = at->length_tree(gogo, arg2_tree);
+	    go_assert(arg2->is_variable());
+	    Expression* arg2_valptr = at->get_value_pointer(gogo, arg2);
+	    Expression* arg2_len_expr = at->get_length(gogo, arg2);
+	    arg2_val = arg2_valptr->get_tree(context);
+	    arg2_len = arg2_len_expr->get_tree(context);
 	  }
 	else
 	  {
@@ -8950,23 +8990,15 @@ 
 	  }
 	else
 	  {
-	    arg2_tree = Expression::convert_for_assignment(context, at,
-							   arg2->type(),
-							   arg2_tree,
-							   location);
-	    if (arg2_tree == error_mark_node)
+	    go_assert(arg2->is_variable());
+	    arg2_val =
+		at->get_value_pointer(gogo, arg2)->get_tree(context);
+	    arg2_len = at->get_length(gogo, arg2)->get_tree(context);
+	    Btype* element_btype = element_type->get_backend(gogo);
+	    tree element_type_tree = type_to_tree(element_btype);
+	    if (element_type_tree == error_mark_node)
 	      return error_mark_node;
-
-	    arg2_tree = save_expr(arg2_tree);
-
-	     arg2_val = at->value_pointer_tree(gogo, arg2_tree);
-	     arg2_len = at->length_tree(gogo, arg2_tree);
-
-	     Btype* element_btype = element_type->get_backend(gogo);
-	     tree element_type_tree = type_to_tree(element_btype);
-	     if (element_type_tree == error_mark_node)
-	       return error_mark_node;
-	     element_size = TYPE_SIZE_UNIT(element_type_tree);
+	    element_size = TYPE_SIZE_UNIT(element_type_tree);
 	  }
 
 	arg2_val = fold_convert_loc(location.gcc_location(), ptr_type_node,
@@ -10371,6 +10403,9 @@ 
   do_check_types(Gogo*);
 
   Expression*
+  do_flatten(Gogo*, Named_object*, Statement_inserter*);
+
+  Expression*
   do_copy()
   {
     return Expression::make_array_index(this->array_->copy(),
@@ -10611,6 +10646,22 @@ 
     }
 }
 
+// Flatten array indexing by using a temporary variable for slices.
+
+Expression*
+Array_index_expression::do_flatten(Gogo*, Named_object*,
+                                   Statement_inserter* inserter)
+{
+  Location loc = this->location();
+  if (this->array_->type()->is_slice_type() && !this->array_->is_variable())
+    {
+      Temporary_statement* temp = Statement::make_temporary(NULL, this->array_, loc);
+      inserter->insert(temp);
+      this->array_ = Expression::make_temporary_reference(temp, loc);
+    }
+  return this;
+}
+
 // Return whether this expression is addressable.
 
 bool
@@ -10643,22 +10694,17 @@ 
       go_assert(this->array_->type()->is_error());
       return error_mark_node;
     }
+  go_assert(!array_type->is_slice_type() || this->array_->is_variable());
 
   tree type_tree = type_to_tree(array_type->get_backend(gogo));
   if (type_tree == error_mark_node)
     return error_mark_node;
 
-  tree array_tree = this->array_->get_tree(context);
-  if (array_tree == error_mark_node)
-    return error_mark_node;
-
-  if (array_type->length() == NULL && !DECL_P(array_tree))
-    array_tree = save_expr(array_tree);
-
   tree length_tree = NULL_TREE;
   if (this->end_ == NULL || this->end_->is_nil_expression())
     {
-      length_tree = array_type->length_tree(gogo, array_tree);
+      Expression* len = array_type->get_length(gogo, this->array_);
+      length_tree = len->get_tree(context);
       if (length_tree == error_mark_node)
 	return error_mark_node;
       length_tree = save_expr(length_tree);
@@ -10667,7 +10713,8 @@ 
   tree capacity_tree = NULL_TREE;
   if (this->end_ != NULL)
     {
-      capacity_tree = array_type->capacity_tree(gogo, array_tree);
+      Expression* cap = array_type->get_capacity(gogo, this->array_);
+      capacity_tree = cap->get_tree(context);
       if (capacity_tree == error_mark_node)
 	return error_mark_node;
       capacity_tree = save_expr(capacity_tree);
@@ -10732,13 +10779,18 @@ 
       if (array_type->length() != NULL)
 	{
 	  // Fixed array.
+	  tree array_tree = this->array_->get_tree(context);
+	  if (array_tree == error_mark_node)
+	    return error_mark_node;
 	  return build4(ARRAY_REF, TREE_TYPE(type_tree), array_tree,
 			start_tree, NULL_TREE, NULL_TREE);
 	}
       else
 	{
 	  // Open array.
-	  tree values = array_type->value_pointer_tree(gogo, array_tree);
+          Expression* valptr =
+              array_type->get_value_pointer(gogo, this->array_);
+	  tree values = valptr->get_tree(context);
 	  Type* element_type = array_type->element_type();
 	  Btype* belement_type = element_type->get_backend(gogo);
 	  tree element_type_tree = type_to_tree(belement_type);
@@ -10820,7 +10872,8 @@ 
                                                  start_tree),
 				element_size);
 
-  tree value_pointer = array_type->value_pointer_tree(gogo, array_tree);
+  Expression* valptr = array_type->get_value_pointer(gogo, this->array_);
+  tree value_pointer = valptr->get_tree(context);
   if (value_pointer == error_mark_node)
     return error_mark_node;
 
@@ -14133,6 +14186,22 @@ 
     }
 }
 
+// Return true if this is a variable or temporary_variable.
+
+bool
+Expression::is_variable() const
+{
+  switch (this->classification_)
+    {
+    case EXPRESSION_VAR_REFERENCE:
+    case EXPRESSION_TEMPORARY_REFERENCE:
+    case EXPRESSION_SET_AND_USE_TEMPORARY:
+      return true;
+    default:
+      return false;
+    }
+}
+
 // Return true if this is a reference to a local variable.
 
 bool
@@ -14574,6 +14643,117 @@ 
   return new Type_info_expression(type, type_info);
 }
 
+// An expression that evaluates to some characteristic of a slice.
+// This is used when indexing, bound-checking, or nil checking a slice.
+
+class Slice_info_expression : public Expression
+{
+ public:
+  Slice_info_expression(Expression* slice, Slice_info slice_info,
+                        Location location)
+    : Expression(EXPRESSION_SLICE_INFO, location),
+      slice_(slice), slice_info_(slice_info)
+  { }
+
+ protected:
+  Type*
+  do_type();
+
+  void
+  do_determine_type(const Type_context*)
+  { }
+
+  Expression*
+  do_copy()
+  {
+    return new Slice_info_expression(this->slice_->copy(), this->slice_info_,
+                                     this->location());
+  }
+
+  tree
+  do_get_tree(Translate_context* context);
+
+  void
+  do_dump_expression(Ast_dump_context*) const;
+
+  void
+  do_issue_nil_check()
+  { this->slice_->issue_nil_check(); }
+
+ private:
+  // The slice for which we are getting information.
+  Expression* slice_;
+  // What information we want.
+  Slice_info slice_info_;
+};
+
+// Return the type of the slice info.
+
+Type*
+Slice_info_expression::do_type()
+{
+  switch (this->slice_info_)
+    {
+    case SLICE_INFO_VALUE_POINTER:
+      return Type::make_pointer_type(
+          this->slice_->type()->array_type()->element_type());
+    case SLICE_INFO_LENGTH:
+    case SLICE_INFO_CAPACITY:
+        return Type::lookup_integer_type("int");
+    default:
+      go_unreachable();
+    }
+}
+
+// Return slice information in GENERIC.
+
+tree
+Slice_info_expression::do_get_tree(Translate_context* context)
+{
+  Gogo* gogo = context->gogo();
+
+  Bexpression* bslice = tree_to_expr(this->slice_->get_tree(context));
+  Bexpression* ret;
+  switch (this->slice_info_)
+    {
+    case SLICE_INFO_VALUE_POINTER:
+    case SLICE_INFO_LENGTH:
+    case SLICE_INFO_CAPACITY:
+      ret = gogo->backend()->struct_field_expression(bslice, this->slice_info_,
+                                                     this->location());
+      break;
+    default:
+      go_unreachable();
+    }
+  return expr_to_tree(ret);
+}
+
+// Dump ast representation for a type info expression.
+
+void
+Slice_info_expression::do_dump_expression(
+    Ast_dump_context* ast_dump_context) const
+{
+  ast_dump_context->ostream() << "sliceinfo(";
+  this->slice_->dump_expression(ast_dump_context);
+  ast_dump_context->ostream() << ",";
+  ast_dump_context->ostream() << 
+      (this->slice_info_ == SLICE_INFO_VALUE_POINTER ? "values" 
+    : this->slice_info_ == SLICE_INFO_LENGTH ? "length"
+    : this->slice_info_ == SLICE_INFO_CAPACITY ? "capacity "
+    : "unknown");
+  ast_dump_context->ostream() << ")";
+}
+
+// Make a slice info expression.
+
+Expression*
+Expression::make_slice_info(Expression* slice, Slice_info slice_info,
+                            Location location)
+{
+  return new Slice_info_expression(slice, slice_info, location);
+}
+
 // An expression which evaluates to the offset of a field within a
 // struct.  This, like Type_info_expression, q.v., is only used to
 // initialize fields of a type descriptor.
diff -r 44fc257ad7f2 go/expressions.h
--- a/go/expressions.h	Thu Jan 09 15:25:44 2014 -0800
+++ b/go/expressions.h	Thu Jan 09 22:31:00 2014 -0800
@@ -102,6 +102,7 @@ 
     EXPRESSION_RECEIVE,
     EXPRESSION_TYPE_DESCRIPTOR,
     EXPRESSION_TYPE_INFO,
+    EXPRESSION_SLICE_INFO,
     EXPRESSION_STRUCT_FIELD_OFFSET,
     EXPRESSION_MAP_DESCRIPTOR,
     EXPRESSION_LABEL_ADDR
@@ -339,6 +340,22 @@ 
   static Expression*
   make_type_info(Type* type, Type_info);
 
+  // Make an expression that evaluates to some characteristic of a
+  // slice.  For simplicity, the enum values must match the field indexes
+  // in the underlying struct.
+  enum Slice_info
+    {
+      // The underlying data of the slice.
+      SLICE_INFO_VALUE_POINTER,
+      // The length of the slice.
+      SLICE_INFO_LENGTH,
+      // The capacity of the slice.
+      SLICE_INFO_CAPACITY
+    };
+
+  static Expression*
+  make_slice_info(Expression* slice, Slice_info, Location);
+
   // Make an expression which evaluates to the offset of a field in a
   // struct.  This is only used for type descriptors, so there is no
   // location parameter.
@@ -544,6 +561,10 @@ 
   bool
   is_nonconstant_composite_literal() const;
 
+  // Return true if this is a variable or temporary variable.
+  bool
+  is_variable() const;
+
   // Return true if this is a reference to a local variable.
   bool
   is_local_variable() const;
diff -r 44fc257ad7f2 go/gogo.cc
--- a/go/gogo.cc	Thu Jan 09 15:25:44 2014 -0800
+++ b/go/gogo.cc	Thu Jan 09 22:31:00 2014 -0800
@@ -2846,6 +2846,15 @@ 
   return TRAVERSE_SKIP_COMPONENTS;
 }
 
+// Flatten a block.
+
+void
+Gogo::flatten_block(Named_object* function, Block* block)
+{
+  Flatten flatten(this, function);
+  block->traverse(&flatten);
+}
+
 // Flatten an expression.  INSERTER may be NULL, in which case the
 // expression had better not need to create any temporaries.
 
diff -r 44fc257ad7f2 go/gogo.h
--- a/go/gogo.h	Thu Jan 09 15:25:44 2014 -0800
+++ b/go/gogo.h	Thu Jan 09 22:31:00 2014 -0800
@@ -487,6 +487,10 @@ 
   void
   lower_constant(Named_object*);
 
+  // Flatten all the statements in a block.
+  void
+  flatten_block(Named_object* function, Block*);
+
   // Flatten an expression.
   void
   flatten_expression(Named_object* function, Statement_inserter*, Expression**);
diff -r 44fc257ad7f2 go/statements.cc
--- a/go/statements.cc	Thu Jan 09 15:25:44 2014 -0800
+++ b/go/statements.cc	Thu Jan 09 22:31:00 2014 -0800
@@ -2471,6 +2471,7 @@ 
   gogo->add_block(b, location);
 
   gogo->lower_block(function, b);
+  gogo->flatten_block(function, b);
 
   // We already ran the determine_types pass, so we need to run it
   // just for the call statement now.  The other types are known.
diff -r 44fc257ad7f2 go/types.cc
--- a/go/types.cc	Thu Jan 09 15:25:44 2014 -0800
+++ b/go/types.cc	Thu Jan 09 22:31:00 2014 -0800
@@ -6000,84 +6000,53 @@ 
     }
 }
 
-// Return a tree for a pointer to the values in ARRAY.
-
-tree
-Array_type::value_pointer_tree(Gogo*, tree array) const
-{
-  tree ret;
+// Return an expression for a pointer to the values in ARRAY.
+
+Expression*
+Array_type::get_value_pointer(Gogo*, Expression* array) const
+{
   if (this->length() != NULL)
     {
       // Fixed array.
-      ret = fold_convert(build_pointer_type(TREE_TYPE(TREE_TYPE(array))),
-			 build_fold_addr_expr(array));
-    }
-  else
-    {
-      // Open array.
-      tree field = TYPE_FIELDS(TREE_TYPE(array));
-      go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)),
-			"__values") == 0);
-      ret = fold_build3(COMPONENT_REF, TREE_TYPE(field), array, field,
-			NULL_TREE);
-    }
-  if (TREE_CONSTANT(array))
-    TREE_CONSTANT(ret) = 1;
-  return ret;
-}
-
-// Return a tree for the length of the array ARRAY which has this
+      go_assert(array->type()->array_type() != NULL);
+      Type* etype = array->type()->array_type()->element_type();
+      array = Expression::make_unary(OPERATOR_AND, array, array->location());
+      return Expression::make_cast(Type::make_pointer_type(etype), array,
+                                   array->location());
+    }
+
+  // Open array.
+  return Expression::make_slice_info(array,
+                                     Expression::SLICE_INFO_VALUE_POINTER,
+                                     array->location());
+}
+
+// Return an expression for the length of the array ARRAY which has this
 // type.
 
-tree
-Array_type::length_tree(Gogo* gogo, tree array)
+Expression*
+Array_type::get_length(Gogo*, Expression* array) const
 {
   if (this->length_ != NULL)
-    {
-      if (TREE_CODE(array) == SAVE_EXPR)
-	return this->get_length_tree(gogo);
-      else
-	{
-	  tree len = this->get_length_tree(gogo);
-	  return omit_one_operand(TREE_TYPE(len), len, array);
-	}
-    }
+    return this->length_;
 
   // This is an open array.  We need to read the length field.
-
-  tree type = TREE_TYPE(array);
-  go_assert(TREE_CODE(type) == RECORD_TYPE);
-
-  tree field = DECL_CHAIN(TYPE_FIELDS(type));
-  go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__count") == 0);
-
-  tree ret = build3(COMPONENT_REF, TREE_TYPE(field), array, field, NULL_TREE);
-  if (TREE_CONSTANT(array))
-    TREE_CONSTANT(ret) = 1;
-  return ret;
-}
-
-// Return a tree for the capacity of the array ARRAY which has this
+  return Expression::make_slice_info(array, Expression::SLICE_INFO_LENGTH,
+                                     array->location());
+}
+
+// Return an expression for the capacity of the array ARRAY which has this
 // type.
 
-tree
-Array_type::capacity_tree(Gogo* gogo, tree array)
+Expression*
+Array_type::get_capacity(Gogo*, Expression* array) const
 {
   if (this->length_ != NULL)
-    {
-      tree len = this->get_length_tree(gogo);
-      return omit_one_operand(TREE_TYPE(len), len, array);
-    }
+    return this->length_;
 
   // This is an open array.  We need to read the capacity field.
-
-  tree type = TREE_TYPE(array);
-  go_assert(TREE_CODE(type) == RECORD_TYPE);
-
-  tree field = DECL_CHAIN(DECL_CHAIN(TYPE_FIELDS(type)));
-  go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__capacity") == 0);
-
-  return build3(COMPONENT_REF, TREE_TYPE(field), array, field, NULL_TREE);
+  return Expression::make_slice_info(array, Expression::SLICE_INFO_CAPACITY,
+                                     array->location());
 }
 
 // Export.
diff -r 44fc257ad7f2 go/types.h
--- a/go/types.h	Thu Jan 09 15:25:44 2014 -0800
+++ b/go/types.h	Thu Jan 09 22:31:00 2014 -0800
@@ -2312,17 +2312,17 @@ 
   array_has_hidden_fields(const Named_type* within, std::string* reason) const
   { return this->element_type_->has_hidden_fields(within, reason); }
 
-  // Return a tree for the pointer to the values in an array.
-  tree
-  value_pointer_tree(Gogo*, tree array) const;
-
-  // Return a tree for the length of an array with this type.
-  tree
-  length_tree(Gogo*, tree array);
-
-  // Return a tree for the capacity of an array with this type.
-  tree
-  capacity_tree(Gogo*, tree array);
+  // Return an expression for the pointer to the values in an array.
+  Expression*
+  get_value_pointer(Gogo*, Expression* array) const;
+
+  // Return an expression for the length of an array with this type.
+  Expression*
+  get_length(Gogo*, Expression* array) const;
+
+  // Return an expression for the capacity of an array with this type.
+  Expression*
+  get_capacity(Gogo*, Expression* array) const;
 
   // Import an array type.
   static Array_type*