summaryrefslogtreecommitdiff
path: root/gcc/go/gofrontend/expressions.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/go/gofrontend/expressions.cc')
-rw-r--r--gcc/go/gofrontend/expressions.cc158
1 files changed, 56 insertions, 102 deletions
diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc
index b1d9bcc9839..9381764e143 100644
--- a/gcc/go/gofrontend/expressions.cc
+++ b/gcc/go/gofrontend/expressions.cc
@@ -4113,20 +4113,47 @@ Unary_expression::do_get_tree(Translate_context* context)
}
}
- if (this->is_gc_root_)
+ static unsigned int counter;
+ char buf[100];
+ if (this->is_gc_root_ || this->is_slice_init_)
{
- // Build a decl for a GC root variable. GC roots are mutable, so they
- // cannot be represented as an immutable_struct in the backend.
- Bvariable* gc_root = gogo->backend()->gc_root_variable(btype, bexpr);
- bexpr = gogo->backend()->var_expression(gc_root, loc);
+ bool copy_to_heap = false;
+ if (this->is_gc_root_)
+ {
+ // Build a decl for a GC root variable. GC roots are mutable, so
+ // they cannot be represented as an immutable_struct in the
+ // backend.
+ static unsigned int root_counter;
+ snprintf(buf, sizeof buf, "gc%u", root_counter);
+ ++root_counter;
+ }
+ else
+ {
+ // Build a decl for a slice value initializer. An immutable slice
+ // value initializer may have to be copied to the heap if it
+ // contains pointers in a non-constant context.
+ snprintf(buf, sizeof buf, "C%u", counter);
+ ++counter;
+
+ Array_type* at = this->expr_->type()->array_type();
+ go_assert(at != NULL);
+
+ // If we are not copying the value to the heap, we will only
+ // initialize the value once, so we can use this directly
+ // rather than copying it. In that case we can't make it
+ // read-only, because the program is permitted to change it.
+ copy_to_heap = (at->element_type()->has_pointer()
+ && !context->is_const());
+ }
+ Bvariable* implicit =
+ gogo->backend()->implicit_variable(buf, btype, bexpr, copy_to_heap);
+ bexpr = gogo->backend()->var_expression(implicit, loc);
}
else if ((this->expr_->is_composite_literal()
|| this->expr_->string_expression() != NULL)
&& this->expr_->is_immutable())
{
// Build a decl for a constant constructor.
- static unsigned int counter;
- char buf[100];
snprintf(buf, sizeof buf, "C%u", counter);
++counter;
@@ -12450,6 +12477,7 @@ Slice_construction_expression::do_get_tree(Translate_context* context)
return error_mark_node;
}
+ Location loc = this->location();
Type* element_type = array_type->element_type();
if (this->valtype_ == NULL)
{
@@ -12464,35 +12492,24 @@ Slice_construction_expression::do_get_tree(Translate_context* context)
else
mpz_init_set_ui(lenval, this->indexes()->back() + 1);
}
- Location loc = this->location();
Type* int_type = Type::lookup_integer_type("int");
length = Expression::make_integer(&lenval, int_type, loc);
mpz_clear(lenval);
this->valtype_ = Type::make_array_type(element_type, length);
}
- tree values;
- Gogo* gogo = context->gogo();
- Btype* val_btype = this->valtype_->get_backend(gogo);
+ Expression_list* vals = this->vals();
if (this->vals() == NULL || this->vals()->empty())
{
- // We need to create a unique value.
- Btype* int_btype = Type::lookup_integer_type("int")->get_backend(gogo);
- Bexpression* zero = gogo->backend()->zero_expression(int_btype);
- std::vector<unsigned long> index(1, 0);
- std::vector<Bexpression*> val(1, zero);
- Bexpression* ctor =
- gogo->backend()->array_constructor_expression(val_btype, index, val,
- this->location());
- values = expr_to_tree(ctor);
+ // We need to create a unique value for the empty array literal.
+ vals = new Expression_list;
+ vals->push_back(NULL);
}
- else
- values = expr_to_tree(this->get_constructor(context, val_btype));
-
- if (values == error_mark_node)
- return error_mark_node;
+ Expression* array_val =
+ new Fixed_array_construction_expression(this->valtype_, this->indexes(),
+ vals, loc);
- bool is_constant_initializer = TREE_CONSTANT(values);
+ bool is_constant_initializer = array_val->is_immutable();
// We have to copy the initial values into heap memory if we are in
// a function or if the values are not constants. We also have to
@@ -12503,89 +12520,22 @@ Slice_construction_expression::do_get_tree(Translate_context* context)
|| (element_type->has_pointer()
&& !context->is_const()));
- if (is_constant_initializer)
- {
- tree tmp = build_decl(this->location().gcc_location(), VAR_DECL,
- create_tmp_var_name("C"), TREE_TYPE(values));
- DECL_EXTERNAL(tmp) = 0;
- TREE_PUBLIC(tmp) = 0;
- TREE_STATIC(tmp) = 1;
- DECL_ARTIFICIAL(tmp) = 1;
- if (copy_to_heap)
- {
- // If we are not copying the value to the heap, we will only
- // initialize the value once, so we can use this directly
- // rather than copying it. In that case we can't make it
- // read-only, because the program is permitted to change it.
- TREE_READONLY(tmp) = 1;
- TREE_CONSTANT(tmp) = 1;
- }
- DECL_INITIAL(tmp) = values;
- rest_of_decl_compilation(tmp, 1, 0);
- values = tmp;
- }
-
- tree space;
- tree set;
+ Expression* space;
if (!copy_to_heap)
{
- // the initializer will only run once.
- space = build_fold_addr_expr(values);
- set = NULL_TREE;
+ // The initializer will only run once.
+ space = Expression::make_unary(OPERATOR_AND, array_val, loc);
+ space->unary_expression()->set_is_slice_init();
}
else
- {
- Expression* alloc =
- context->gogo()->allocate_memory(this->valtype_, this->location());
- space = save_expr(alloc->get_tree(context));
-
- tree s = fold_convert(build_pointer_type(TREE_TYPE(values)), space);
- tree ref = build_fold_indirect_ref_loc(this->location().gcc_location(),
- s);
- TREE_THIS_NOTRAP(ref) = 1;
- set = build2(MODIFY_EXPR, void_type_node, ref, values);
- }
+ space = Expression::make_heap_expression(array_val, loc);
// Build a constructor for the slice.
- tree type_tree = type_to_tree(this->type()->get_backend(context->gogo()));
- if (type_tree == error_mark_node)
- return error_mark_node;
- go_assert(TREE_CODE(type_tree) == RECORD_TYPE);
-
- vec<constructor_elt, va_gc> *init;
- vec_alloc(init, 3);
-
- constructor_elt empty = {NULL, NULL};
- constructor_elt* elt = init->quick_push(empty);
- tree field = TYPE_FIELDS(type_tree);
- go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__values") == 0);
- elt->index = field;
- elt->value = fold_convert(TREE_TYPE(field), space);
-
- tree length_tree = this->valtype_->array_type()->length()->get_tree(context);
- elt = init->quick_push(empty);
- field = DECL_CHAIN(field);
- go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__count") == 0);
- elt->index = field;
- elt->value = fold_convert(TREE_TYPE(field), length_tree);
-
- elt = init->quick_push(empty);
- field = DECL_CHAIN(field);
- go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)),"__capacity") == 0);
- elt->index = field;
- elt->value = fold_convert(TREE_TYPE(field), length_tree);
-
- tree constructor = build_constructor(type_tree, init);
- if (constructor == error_mark_node)
- return error_mark_node;
- if (!copy_to_heap)
- TREE_CONSTANT(constructor) = 1;
-
- if (set == NULL_TREE)
- return constructor;
- else
- return build2(COMPOUND_EXPR, type_tree, set, constructor);
+ Expression* len = this->valtype_->array_type()->length();
+ Expression* slice_val =
+ Expression::make_slice_value(this->type(), space, len, len, loc);
+ return slice_val->get_tree(context);
}
// Make a slice composite literal. This is used by the type
@@ -14802,6 +14752,10 @@ class Struct_field_offset_expression : public Expression
{ }
protected:
+ bool
+ do_is_immutable() const
+ { return true; }
+
Type*
do_type()
{ return Type::lookup_integer_type("uintptr"); }