diff options
Diffstat (limited to 'gcc/go/gofrontend/expressions.cc')
-rw-r--r-- | gcc/go/gofrontend/expressions.cc | 158 |
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"); } |