diff options
Diffstat (limited to 'gcc/go/gofrontend/expressions.cc')
-rw-r--r-- | gcc/go/gofrontend/expressions.cc | 2725 |
1 files changed, 1749 insertions, 976 deletions
diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc index 09ab5bf8f7..fee3203714 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -10,6 +10,8 @@ #include "go-c.h" #include "gogo.h" +#include "go-diagnostics.h" +#include "go-encode-id.h" #include "types.h" #include "export.h" #include "import.h" @@ -107,7 +109,7 @@ Expression::set_is_error() void Expression::report_error(const char* msg) { - error_at(this->location_, "%s", msg); + go_error_at(this->location_, "%s", msg); this->set_is_error(); } @@ -252,7 +254,9 @@ Expression::convert_type_to_interface(Type* lhs_type, Expression* rhs, else { // We are assigning a non-pointer value to the interface; the - // interface gets a copy of the value in the heap. + // interface gets a copy of the value in the heap if it escapes. + // TODO(cmang): Associate escape state state of RHS with newly + // created OBJ. obj = Expression::make_heap_expression(rhs, location); } @@ -320,9 +324,8 @@ Expression::convert_interface_to_interface(Type *lhs_type, Expression* rhs, if (for_type_guard) { // A type assertion fails when converting a nil interface. - first_field = - Runtime::make_call(Runtime::ASSERT_INTERFACE, location, 2, - lhs_type_expr, rhs_type_expr); + first_field = Runtime::make_call(Runtime::ASSERTITAB, location, 2, + lhs_type_expr, rhs_type_expr); } else if (lhs_is_empty) { @@ -334,9 +337,8 @@ Expression::convert_interface_to_interface(Type *lhs_type, Expression* rhs, { // A conversion to a non-empty interface may fail, but unlike a // type assertion converting nil will always succeed. - first_field = - Runtime::make_call(Runtime::CONVERT_INTERFACE, location, 2, - lhs_type_expr, rhs_type_expr); + first_field = Runtime::make_call(Runtime::REQUIREITAB, location, 2, + lhs_type_expr, rhs_type_expr); } // The second field is simply the object pointer. @@ -367,7 +369,7 @@ Expression::convert_interface_to_type(Type *lhs_type, Expression* rhs, Expression* rhs_inter_expr = Expression::make_type_descriptor(rhs_type, location); - Expression* check_iface = Runtime::make_call(Runtime::CHECK_INTERFACE_TYPE, + Expression* check_iface = Runtime::make_call(Runtime::ASSERTI2T, location, 3, lhs_type_expr, rhs_descriptor, rhs_inter_expr); @@ -535,10 +537,6 @@ class Error_expression : public Expression { return true; } bool - do_is_immutable() const - { return true; } - - bool do_numeric_constant_value(Numeric_constant* nc) const { nc->set_unsigned_long(NULL, 0); @@ -729,6 +727,13 @@ Var_expression::do_address_taken(bool escapes) else go_unreachable(); } + + if (this->variable_->is_variable() + && this->variable_->var_value()->is_in_heap()) + { + Node::make_node(this)->set_encoding(Node::ESCAPE_HEAP); + Node::make_node(this->variable_)->set_encoding(Node::ESCAPE_HEAP); + } } // Get the backend representation for a reference to a variable. @@ -755,7 +760,8 @@ Var_expression::do_get_backend(Translate_context* context) else go_unreachable(); - Bexpression* ret = context->backend()->var_expression(bvar, loc); + Bexpression* ret = + context->backend()->var_expression(bvar, this->in_lvalue_pos_, loc); if (is_in_heap) ret = context->backend()->indirect_expression(btype, ret, true, loc); return ret; @@ -782,6 +788,78 @@ Expression::make_var_reference(Named_object* var, Location location) return new Var_expression(var, location); } +// Class Enclosed_var_expression. + +int +Enclosed_var_expression::do_traverse(Traverse*) +{ + return TRAVERSE_CONTINUE; +} + +// Lower the reference to the enclosed variable. + +Expression* +Enclosed_var_expression::do_lower(Gogo* gogo, Named_object* function, + Statement_inserter* inserter, int) +{ + gogo->lower_expression(function, inserter, &this->reference_); + return this; +} + +// Flatten the reference to the enclosed variable. + +Expression* +Enclosed_var_expression::do_flatten(Gogo* gogo, Named_object* function, + Statement_inserter* inserter) +{ + gogo->flatten_expression(function, inserter, &this->reference_); + return this; +} + +void +Enclosed_var_expression::do_address_taken(bool escapes) +{ + if (!escapes) + { + if (this->variable_->is_variable()) + this->variable_->var_value()->set_non_escaping_address_taken(); + else if (this->variable_->is_result_variable()) + this->variable_->result_var_value()->set_non_escaping_address_taken(); + else + go_unreachable(); + } + else + { + if (this->variable_->is_variable()) + this->variable_->var_value()->set_address_taken(); + else if (this->variable_->is_result_variable()) + this->variable_->result_var_value()->set_address_taken(); + else + go_unreachable(); + } + + if (this->variable_->is_variable() + && this->variable_->var_value()->is_in_heap()) + Node::make_node(this->variable_)->set_encoding(Node::ESCAPE_HEAP); +} + +// Ast dump for enclosed variable expression. + +void +Enclosed_var_expression::do_dump_expression(Ast_dump_context* adc) const +{ + adc->ostream() << this->variable_->name(); +} + +// Make a reference to a variable within an enclosing function. + +Expression* +Expression::make_enclosing_var_reference(Expression* reference, + Named_object* var, Location location) +{ + return new Enclosed_var_expression(reference, var, location); +} + // Class Temporary_reference_expression. // The type. @@ -810,7 +888,10 @@ Temporary_reference_expression::do_get_backend(Translate_context* context) { Gogo* gogo = context->gogo(); Bvariable* bvar = this->statement_->get_backend_variable(context); - Bexpression* ret = gogo->backend()->var_expression(bvar, this->location()); + Varexpr_context ve_ctxt = (this->is_lvalue_ ? VE_lvalue : VE_rvalue); + + Bexpression* ret = gogo->backend()->var_expression(bvar, ve_ctxt, + this->location()); // The backend can't always represent the same set of recursive types // that the Go frontend can. In some cases this means that a @@ -881,11 +962,15 @@ Set_and_use_temporary_expression::do_get_backend(Translate_context* context) Location loc = this->location(); Gogo* gogo = context->gogo(); Bvariable* bvar = this->statement_->get_backend_variable(context); - Bexpression* var_ref = gogo->backend()->var_expression(bvar, loc); + Bexpression* lvar_ref = gogo->backend()->var_expression(bvar, VE_rvalue, loc); + Named_object* fn = context->function(); + go_assert(fn != NULL); + Bfunction* bfn = fn->func_value()->get_or_make_decl(gogo, fn); Bexpression* bexpr = this->expr_->get_backend(context); - Bstatement* set = gogo->backend()->assignment_statement(var_ref, bexpr, loc); - var_ref = gogo->backend()->var_expression(bvar, loc); + Bstatement* set = gogo->backend()->assignment_statement(bfn, lvar_ref, + bexpr, loc); + Bexpression* var_ref = gogo->backend()->var_expression(bvar, VE_lvalue, loc); Bexpression* ret = gogo->backend()->compound_expression(set, var_ref, loc); return ret; } @@ -988,11 +1073,12 @@ Sink_expression::do_get_backend(Translate_context* context) this->bvar_ = gogo->backend()->temporary_variable(fn_ctx, context->bblock(), bt, NULL, false, loc, &decl); - Bexpression* var_ref = gogo->backend()->var_expression(this->bvar_, loc); + Bexpression* var_ref = + gogo->backend()->var_expression(this->bvar_, VE_lvalue, loc); var_ref = gogo->backend()->compound_expression(decl, var_ref, loc); return var_ref; } - return gogo->backend()->var_expression(this->bvar_, loc); + return gogo->backend()->var_expression(this->bvar_, VE_lvalue, loc); } // Ast dump for sink expression. @@ -1058,9 +1144,9 @@ Func_expression::get_code_pointer(Gogo* gogo, Named_object* no, Location loc) // can't take their address. if (fntype->is_builtin()) { - error_at(loc, - "invalid use of special builtin function %qs; must be called", - no->message_name().c_str()); + go_error_at(loc, + "invalid use of special builtin function %qs; must be called", + no->message_name().c_str()); return gogo->backend()->error_expression(); } @@ -1097,10 +1183,10 @@ Func_expression::do_get_backend(Translate_context* context) { if (no->func_declaration_value()->type()->is_builtin()) { - error_at(this->location(), - ("invalid use of special builtin function %qs; " - "must be called"), - no->message_name().c_str()); + go_error_at(this->location(), + ("invalid use of special builtin function %qs; " + "must be called"), + no->message_name().c_str()); return gogo->backend()->error_expression(); } descriptor = no->func_declaration_value()->descriptor(gogo, no); @@ -1141,7 +1227,13 @@ Expression* Expression::make_func_reference(Named_object* function, Expression* closure, Location location) { - return new Func_expression(function, closure, location); + Func_expression* fe = new Func_expression(function, closure, location); + + // Detect references to builtin functions and set the runtime code if + // appropriate. + if (function->is_function_declaration()) + fe->set_runtime_code(Runtime::name_to_code(function->name())); + return fe; } // Class Func_descriptor_expression. @@ -1193,7 +1285,7 @@ Func_descriptor_expression::do_get_backend(Translate_context* context) Named_object* no = this->fn_; Location loc = no->location(); if (this->dvar_ != NULL) - return context->backend()->var_expression(this->dvar_, loc); + return context->backend()->var_expression(this->dvar_, VE_rvalue, loc); Gogo* gogo = context->gogo(); std::string var_name; @@ -1202,7 +1294,10 @@ Func_descriptor_expression::do_get_backend(Translate_context* context) && !no->func_declaration_value()->asm_name().empty() && Linemap::is_predeclared_location(no->location())) { - var_name = no->func_declaration_value()->asm_name() + "_descriptor"; + if (no->func_declaration_value()->asm_name().substr(0, 8) != "runtime.") + var_name = no->func_declaration_value()->asm_name() + "_descriptor"; + else + var_name = no->func_declaration_value()->asm_name() + "$descriptor"; is_descriptor = true; } else @@ -1219,16 +1314,18 @@ Func_descriptor_expression::do_get_backend(Translate_context* context) Btype* btype = this->type()->get_backend(gogo); Bvariable* bvar; + std::string asm_name(go_selectively_encode_id(var_name)); if (no->package() != NULL || is_descriptor) - bvar = context->backend()->immutable_struct_reference(var_name, btype, - loc); + bvar = context->backend()->immutable_struct_reference(var_name, asm_name, + btype, loc); else { Location bloc = Linemap::predeclared_location(); bool is_hidden = ((no->is_function() && no->func_value()->enclosing() != NULL) || Gogo::is_thunk(no)); - bvar = context->backend()->immutable_struct(var_name, is_hidden, false, + bvar = context->backend()->immutable_struct(var_name, asm_name, + is_hidden, false, btype, bloc); Expression_list* vals = new Expression_list(); vals->push_back(Expression::make_func_code_reference(this->fn_, bloc)); @@ -1242,7 +1339,7 @@ Func_descriptor_expression::do_get_backend(Translate_context* context) } this->dvar_ = bvar; - return gogo->backend()->var_expression(bvar, loc); + return gogo->backend()->var_expression(bvar, VE_rvalue, loc); } // Print a function descriptor expression. @@ -1285,7 +1382,7 @@ class Func_code_reference_expression : public Expression { return TRAVERSE_CONTINUE; } bool - do_is_immutable() const + do_is_static_initializer() const { return true; } Type* @@ -1360,8 +1457,8 @@ Unknown_expression::do_lower(Gogo*, Named_object*, Statement_inserter*, int) if (this->is_composite_literal_key_) return this; if (!this->no_error_message_) - error_at(location, "reference to undefined name %qs", - this->named_object_->message_name().c_str()); + go_error_at(location, "reference to undefined name %qs", + this->named_object_->message_name().c_str()); return Expression::make_error(location); } } @@ -1375,8 +1472,8 @@ Unknown_expression::do_lower(Gogo*, Named_object*, Statement_inserter*, int) if (this->is_composite_literal_key_) return this; if (!this->no_error_message_) - error_at(location, "reference to undefined type %qs", - real->message_name().c_str()); + go_error_at(location, "reference to undefined type %qs", + real->message_name().c_str()); return Expression::make_error(location); case Named_object::NAMED_OBJECT_VAR: real->var_value()->set_is_used(); @@ -1388,7 +1485,7 @@ Unknown_expression::do_lower(Gogo*, Named_object*, Statement_inserter*, int) if (this->is_composite_literal_key_) return this; if (!this->no_error_message_) - error_at(location, "unexpected reference to package"); + go_error_at(location, "unexpected reference to package"); return Expression::make_error(location); default: go_unreachable(); @@ -1431,7 +1528,7 @@ class Boolean_expression : public Expression { return true; } bool - do_is_immutable() const + do_is_static_initializer() const { return true; } Type* @@ -1639,7 +1736,7 @@ String_expression::do_import(Import* imp) } else { - error_at(imp->location(), "bad string constant"); + go_error_at(imp->location(), "bad string constant"); return Expression::make_error(imp->location()); } } @@ -1800,7 +1897,7 @@ class Integer_expression : public Expression { return true; } bool - do_is_immutable() const + do_is_static_initializer() const { return true; } bool @@ -1949,8 +2046,8 @@ Integer_expression::do_get_backend(Translate_context* context) else { if (!saw_errors()) - error_at(this->location(), - "unknown type for large integer constant"); + go_error_at(this->location(), + "unknown type for large integer constant"); return context->gogo()->backend()->error_expression(); } } @@ -2001,8 +2098,8 @@ Integer_expression::do_import(Import* imp) pos = plus_pos; else { - error_at(imp->location(), "bad number in import data: %qs", - num.c_str()); + go_error_at(imp->location(), "bad number in import data: %qs", + num.c_str()); return Expression::make_error(imp->location()); } if (pos == std::string::npos) @@ -2012,8 +2109,8 @@ Integer_expression::do_import(Import* imp) std::string real_str = num.substr(0, pos); if (mpfr_init_set_str(real, real_str.c_str(), 10, GMP_RNDN) != 0) { - error_at(imp->location(), "bad number in import data: %qs", - real_str.c_str()); + go_error_at(imp->location(), "bad number in import data: %qs", + real_str.c_str()); return Expression::make_error(imp->location()); } } @@ -2027,8 +2124,8 @@ Integer_expression::do_import(Import* imp) mpfr_t imag; if (mpfr_init_set_str(imag, imag_str.c_str(), 10, GMP_RNDN) != 0) { - error_at(imp->location(), "bad number in import data: %qs", - imag_str.c_str()); + go_error_at(imp->location(), "bad number in import data: %qs", + imag_str.c_str()); return Expression::make_error(imp->location()); } mpc_t cval; @@ -2050,8 +2147,8 @@ Integer_expression::do_import(Import* imp) mpz_t val; if (mpz_init_set_str(val, num.c_str(), 10) != 0) { - error_at(imp->location(), "bad number in import data: %qs", - num.c_str()); + go_error_at(imp->location(), "bad number in import data: %qs", + num.c_str()); return Expression::make_error(imp->location()); } Expression* ret; @@ -2067,8 +2164,8 @@ Integer_expression::do_import(Import* imp) mpfr_t val; if (mpfr_init_set_str(val, num.c_str(), 10, GMP_RNDN) != 0) { - error_at(imp->location(), "bad number in import data: %qs", - num.c_str()); + go_error_at(imp->location(), "bad number in import data: %qs", + num.c_str()); return Expression::make_error(imp->location()); } Expression* ret = Expression::make_float(&val, NULL, imp->location()); @@ -2196,7 +2293,7 @@ class Float_expression : public Expression { return true; } bool - do_is_immutable() const + do_is_static_initializer() const { return true; } bool @@ -2386,7 +2483,7 @@ class Complex_expression : public Expression { return true; } bool - do_is_immutable() const + do_is_static_initializer() const { return true; } bool @@ -2602,7 +2699,7 @@ class Const_expression : public Expression { return true; } bool - do_is_immutable() const + do_is_static_initializer() const { return true; } bool @@ -2671,8 +2768,8 @@ Const_expression::do_lower(Gogo* gogo, Named_object*, { if (iota_value == -1) { - error_at(this->location(), - "iota is only defined in const declarations"); + go_error_at(this->location(), + "iota is only defined in const declarations"); iota_value = 0; } return Expression::make_integer_ul(iota_value, NULL, this->location()); @@ -2958,7 +3055,7 @@ class Nil_expression : public Expression { return true; } bool - do_is_immutable() const + do_is_static_initializer() const { return true; } Type* @@ -3128,7 +3225,7 @@ Type_conversion_expression::do_lower(Gogo*, Named_object*, int adv = Lex::fetch_char(p, &c); if (adv == 0) { - warning_at(this->location(), 0, + go_warning_at(this->location(), 0, "invalid UTF-8 encoding"); adv = 1; } @@ -3195,10 +3292,11 @@ Type_conversion_expression::do_is_constant() const return true; } -// Return whether a type conversion is immutable. +// Return whether a type conversion can be used in a constant +// initializer. bool -Type_conversion_expression::do_is_immutable() const +Type_conversion_expression::do_is_static_initializer() const { Type* type = this->type_; Type* expr_type = this->expr_->type(); @@ -3207,7 +3305,7 @@ Type_conversion_expression::do_is_immutable() const || expr_type->interface_type() != NULL) return false; - if (!this->expr_->is_immutable()) + if (!this->expr_->is_static_initializer()) return false; if (Type::are_identical(type, expr_type, false, NULL)) @@ -3287,7 +3385,7 @@ Type_conversion_expression::do_check_types(Gogo*) if (Type::are_convertible(type, expr_type, &reason)) return; - error_at(this->location(), "%s", reason.c_str()); + go_error_at(this->location(), "%s", reason.c_str()); this->set_is_error(); } @@ -3331,7 +3429,8 @@ Type_conversion_expression::do_get_backend(Translate_context* context) } Expression* i2s_expr = - Runtime::make_call(Runtime::INT_TO_STRING, loc, 1, this->expr_); + Runtime::make_call(Runtime::INTSTRING, loc, 2, + Expression::make_nil(loc), this->expr_); return Expression::make_cast(type, i2s_expr, loc)->get_backend(context); } else if (type->is_string_type() && expr_type->is_slice_type()) @@ -3343,16 +3442,14 @@ Type_conversion_expression::do_get_backend(Translate_context* context) Runtime::Function code; if (e->integer_type()->is_byte()) - code = Runtime::BYTE_ARRAY_TO_STRING; + code = Runtime::SLICEBYTETOSTRING; else { go_assert(e->integer_type()->is_rune()); - code = Runtime::INT_ARRAY_TO_STRING; + code = Runtime::SLICERUNETOSTRING; } - Expression* valptr = a->get_value_pointer(gogo, this->expr_); - Expression* len = a->get_length(gogo, this->expr_); - return Runtime::make_call(code, loc, 2, valptr, - len)->get_backend(context); + return Runtime::make_call(code, loc, 2, Expression::make_nil(loc), + this->expr_)->get_backend(context); } else if (type->is_slice_type() && expr_type->is_string_type()) { @@ -3361,13 +3458,15 @@ Type_conversion_expression::do_get_backend(Translate_context* context) Runtime::Function code; if (e->integer_type()->is_byte()) - code = Runtime::STRING_TO_BYTE_ARRAY; + code = Runtime::STRINGTOSLICEBYTE; else { go_assert(e->integer_type()->is_rune()); - code = Runtime::STRING_TO_INT_ARRAY; + code = Runtime::STRINGTOSLICERUNE; } - Expression* s2a = Runtime::make_call(code, loc, 1, this->expr_); + Expression* s2a = Runtime::make_call(code, loc, 2, + Expression::make_nil(loc), + this->expr_); return Expression::make_unsafe_cast(type, s2a, loc)->get_backend(context); } else if (type->is_numeric_type()) @@ -3452,10 +3551,11 @@ Unsafe_type_conversion_expression::do_traverse(Traverse* traverse) return TRAVERSE_CONTINUE; } -// Return whether an unsafe type conversion is immutable. +// Return whether an unsafe type conversion can be used as a constant +// initializer. bool -Unsafe_type_conversion_expression::do_is_immutable() const +Unsafe_type_conversion_expression::do_is_static_initializer() const { Type* type = this->type_; Type* expr_type = this->expr_->type(); @@ -3464,7 +3564,7 @@ Unsafe_type_conversion_expression::do_is_immutable() const || expr_type->interface_type() != NULL) return false; - if (!this->expr_->is_immutable()) + if (!this->expr_->is_static_initializer()) return false; if (Type::are_convertible(type, expr_type, NULL)) @@ -3516,6 +3616,7 @@ Unsafe_type_conversion_expression::do_get_backend(Translate_context* context) || et->channel_type() != NULL || et->map_type() != NULL || et->function_type() != NULL + || et->integer_type() != NULL || et->is_nil_type()); else if (et->is_unsafe_pointer_type()) go_assert(t->points_to() != NULL); @@ -3533,6 +3634,8 @@ Unsafe_type_conversion_expression::do_get_backend(Translate_context* context) || et->map_type() != NULL || et->channel_type() != NULL || et->is_nil_type()); + else if (t->function_type() != NULL) + go_assert(et->points_to() != NULL); else go_unreachable(); @@ -3604,8 +3707,8 @@ Unary_expression::do_lower(Gogo*, Named_object*, Statement_inserter*, int) // *&x == x. if (!ue->expr_->is_addressable() && !ue->create_temp_) { - error_at(ue->location(), - "invalid operand for unary %<&%>"); + go_error_at(ue->location(), + "invalid operand for unary %<&%>"); this->set_is_error(); } return ue->expr_; @@ -3619,7 +3722,7 @@ Unary_expression::do_lower(Gogo*, Named_object*, Statement_inserter*, int) // having to deal with TYPE_VOID in other places. if (op == OPERATOR_MULT && expr->type()->is_unsafe_pointer_type()) { - error_at(this->location(), "invalid indirect of %<unsafe.Pointer%>"); + go_error_at(this->location(), "invalid indirect of %<unsafe.Pointer%>"); return Expression::make_error(this->location()); } @@ -3639,8 +3742,12 @@ Unary_expression::do_lower(Gogo*, Named_object*, Statement_inserter*, int) if (expr->numeric_constant_value(&nc)) { Numeric_constant result; - if (Unary_expression::eval_constant(op, &nc, loc, &result)) + bool issued_error; + if (Unary_expression::eval_constant(op, &nc, loc, &result, + &issued_error)) return result.expression(loc); + else if (issued_error) + return Expression::make_error(this->location()); } } @@ -3695,9 +3802,25 @@ Unary_expression::do_flatten(Gogo* gogo, Named_object*, // value does not escape. If this->escapes_ is true, we may be // able to set it to false if taking the address of a variable // that does not escape. - if (this->escapes_ && this->expr_->var_expression() != NULL) + Node* n = Node::make_node(this); + if ((n->encoding() & ESCAPE_MASK) == int(Node::ESCAPE_NONE)) + this->escapes_ = false; + + // When compiling the runtime, the address operator does not + // cause local variables to escape. When escape analysis + // becomes the default, this should be changed to make it an + // error if we have an address operator that escapes. + if (gogo->compiling_runtime() && gogo->package_name() == "runtime") + this->escapes_ = false; + + Named_object* var = NULL; + if (this->expr_->var_expression() != NULL) + var = this->expr_->var_expression()->named_object(); + else if (this->expr_->enclosed_var_expression() != NULL) + var = this->expr_->enclosed_var_expression()->variable(); + + if (this->escapes_ && var != NULL) { - Named_object* var = this->expr_->var_expression()->named_object(); if (var->is_variable()) this->escapes_ = var->var_value()->escapes(); if (var->is_result_variable()) @@ -3746,13 +3869,73 @@ Unary_expression::do_is_constant() const return this->expr_->is_constant(); } +// Return whether a unary expression can be used as a constant +// initializer. + +bool +Unary_expression::do_is_static_initializer() const +{ + if (this->op_ == OPERATOR_MULT) + return false; + else if (this->op_ == OPERATOR_AND) + return Unary_expression::base_is_static_initializer(this->expr_); + else + return this->expr_->is_static_initializer(); +} + +// Return whether the address of EXPR can be used as a static +// initializer. + +bool +Unary_expression::base_is_static_initializer(Expression* expr) +{ + // The address of a field reference can be a static initializer if + // the base can be a static initializer. + Field_reference_expression* fre = expr->field_reference_expression(); + if (fre != NULL) + return Unary_expression::base_is_static_initializer(fre->expr()); + + // The address of an index expression can be a static initializer if + // the base can be a static initializer and the index is constant. + Array_index_expression* aind = expr->array_index_expression(); + if (aind != NULL) + return (aind->end() == NULL + && aind->start()->is_constant() + && Unary_expression::base_is_static_initializer(aind->array())); + + // The address of a global variable can be a static initializer. + Var_expression* ve = expr->var_expression(); + if (ve != NULL) + { + Named_object* no = ve->named_object(); + return no->is_variable() && no->var_value()->is_global(); + } + + // The address of a composite literal can be used as a static + // initializer if the composite literal is itself usable as a + // static initializer. + if (expr->is_composite_literal() && expr->is_static_initializer()) + return true; + + // The address of a string constant can be used as a static + // initializer. This can not be written in Go itself but this is + // used when building a type descriptor. + if (expr->string_expression() != NULL) + return true; + + return false; +} + // Apply unary opcode OP to UNC, setting NC. Return true if this -// could be done, false if not. Issue errors for overflow. +// could be done, false if not. On overflow, issues an error and sets +// *ISSUED_ERROR. bool Unary_expression::eval_constant(Operator op, const Numeric_constant* unc, - Location location, Numeric_constant* nc) + Location location, Numeric_constant* nc, + bool* issued_error) { + *issued_error = false; switch (op) { case OPERATOR_PLUS: @@ -3897,7 +4080,12 @@ Unary_expression::eval_constant(Operator op, const Numeric_constant* unc, mpz_clear(uval); mpz_clear(val); - return nc->set_type(unc->type(), true, location); + if (!nc->set_type(unc->type(), true, location)) + { + *issued_error = true; + return false; + } + return true; } // Return the integral constant value of a unary expression, if it has one. @@ -3908,8 +4096,9 @@ Unary_expression::do_numeric_constant_value(Numeric_constant* nc) const Numeric_constant unc; if (!this->expr_->numeric_constant_value(&unc)) return false; + bool issued_error; return Unary_expression::eval_constant(this->op_, &unc, this->location(), - nc); + nc, &issued_error); } // Return the type of a unary expression. @@ -4020,7 +4209,7 @@ Unary_expression::do_check_types(Gogo*) { if (!this->create_temp_) { - error_at(this->location(), "invalid operand for unary %<&%>"); + go_error_at(this->location(), "invalid operand for unary %<&%>"); this->set_is_error(); } } @@ -4059,11 +4248,16 @@ Unary_expression::do_get_backend(Translate_context* context) { Temporary_statement* temp = sut->temporary(); Bvariable* bvar = temp->get_backend_variable(context); - Bexpression* bvar_expr = gogo->backend()->var_expression(bvar, loc); + Bexpression* bvar_expr = + gogo->backend()->var_expression(bvar, VE_lvalue, loc); Bexpression* bval = sut->expression()->get_backend(context); + Named_object* fn = context->function(); + go_assert(fn != NULL); + Bfunction* bfn = + fn->func_value()->get_or_make_decl(gogo, fn); Bstatement* bassign = - gogo->backend()->assignment_statement(bvar_expr, bval, loc); + gogo->backend()->assignment_statement(bfn, bvar_expr, bval, loc); Bexpression* bvar_addr = gogo->backend()->address_expression(bvar_expr, loc); return gogo->backend()->compound_expression(bassign, bvar_addr, loc); @@ -4098,7 +4292,7 @@ Unary_expression::do_get_backend(Translate_context* context) // constructor will not do what the programmer expects. go_assert(!this->expr_->is_composite_literal() - || this->expr_->is_immutable()); + || this->expr_->is_static_initializer()); if (this->expr_->classification() == EXPRESSION_UNARY) { Unary_expression* ue = @@ -4136,30 +4330,47 @@ Unary_expression::do_get_backend(Translate_context* context) // 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()); + copy_to_heap = context->function() != NULL; } + std::string asm_name(go_selectively_encode_id(buf)); Bvariable* implicit = - gogo->backend()->implicit_variable(buf, btype, true, copy_to_heap, - false, 0); + gogo->backend()->implicit_variable(buf, asm_name, + btype, true, copy_to_heap, + false, 0); gogo->backend()->implicit_variable_set_init(implicit, buf, btype, true, copy_to_heap, false, bexpr); - bexpr = gogo->backend()->var_expression(implicit, loc); + bexpr = gogo->backend()->var_expression(implicit, VE_lvalue, loc); + + // If we are not copying a slice initializer to the heap, + // then it can be changed by the program, so if it can + // contain pointers we must register it as a GC root. + if (this->is_slice_init_ + && !copy_to_heap + && this->expr_->type()->has_pointer()) + { + Bexpression* root = + gogo->backend()->var_expression(implicit, VE_lvalue, loc); + root = gogo->backend()->address_expression(root, loc); + Type* type = Type::make_pointer_type(this->expr_->type()); + gogo->add_gc_root(Expression::make_backend(root, type, loc)); + } } else if ((this->expr_->is_composite_literal() - || this->expr_->string_expression() != NULL) - && this->expr_->is_immutable()) + || this->expr_->string_expression() != NULL) + && this->expr_->is_static_initializer()) { // Build a decl for a constant constructor. snprintf(buf, sizeof buf, "C%u", counter); ++counter; + std::string asm_name(go_selectively_encode_id(buf)); Bvariable* decl = - gogo->backend()->immutable_struct(buf, true, false, btype, loc); + gogo->backend()->immutable_struct(buf, asm_name, + true, false, btype, loc); gogo->backend()->immutable_struct_set_init(decl, buf, true, false, btype, loc, bexpr); - bexpr = gogo->backend()->var_expression(decl, loc); + bexpr = gogo->backend()->var_expression(decl, VE_lvalue, loc); } go_assert(!this->create_temp_ || this->expr_->is_variable()); @@ -4198,7 +4409,9 @@ Unary_expression::do_get_backend(Translate_context* context) Bexpression* crash = gogo->runtime_error(RUNTIME_ERROR_NIL_DEREFERENCE, loc)->get_backend(context); - bexpr = gogo->backend()->conditional_expression(btype, compare, + Bfunction* bfn = context->function()->func_value()->get_decl(); + bexpr = gogo->backend()->conditional_expression(bfn, btype, + compare, crash, bexpr, loc); @@ -4317,6 +4530,33 @@ Binary_expression::do_traverse(Traverse* traverse) return Expression::traverse(&this->right_, traverse); } +// Return whether this expression may be used as a static initializer. + +bool +Binary_expression::do_is_static_initializer() const +{ + if (!this->left_->is_static_initializer() + || !this->right_->is_static_initializer()) + return false; + + // Addresses can be static initializers, but we can't implement + // arbitray binary expressions of them. + Unary_expression* lu = this->left_->unary_expression(); + Unary_expression* ru = this->right_->unary_expression(); + if (lu != NULL && lu->op() == OPERATOR_AND) + { + if (ru != NULL && ru->op() == OPERATOR_AND) + return this->op_ == OPERATOR_MINUS; + else + return this->op_ == OPERATOR_PLUS || this->op_ == OPERATOR_MINUS; + } + else if (ru != NULL && ru->op() == OPERATOR_AND) + return this->op_ == OPERATOR_PLUS || this->op_ == OPERATOR_MINUS; + + // Other cases should resolve in the backend. + return true; +} + // Return the type to use for a binary operation on operands of // LEFT_TYPE and RIGHT_TYPE. These are the types of constants and as // such may be NULL or abstract. @@ -4539,13 +4779,15 @@ Binary_expression::compare_complex(const Numeric_constant* left_nc, // Apply binary opcode OP to LEFT_NC and RIGHT_NC, setting NC. Return // true if this could be done, false if not. Issue errors at LOCATION -// as appropriate. +// as appropriate, and sets *ISSUED_ERROR if it did. bool Binary_expression::eval_constant(Operator op, Numeric_constant* left_nc, Numeric_constant* right_nc, - Location location, Numeric_constant* nc) + Location location, Numeric_constant* nc, + bool* issued_error) { + *issued_error = false; switch (op) { case OPERATOR_OROR: @@ -4594,7 +4836,11 @@ Binary_expression::eval_constant(Operator op, Numeric_constant* left_nc, r = Binary_expression::eval_integer(op, left_nc, right_nc, location, nc); if (r) - r = nc->set_type(type, true, location); + { + r = nc->set_type(type, true, location); + if (!r) + *issued_error = true; + } return r; } @@ -4627,7 +4873,7 @@ Binary_expression::eval_integer(Operator op, const Numeric_constant* left_nc, mpz_add(val, left_val, right_val); if (mpz_sizeinbase(val, 2) > 0x100000) { - error_at(location, "constant addition overflow"); + go_error_at(location, "constant addition overflow"); nc->set_invalid(); mpz_set_ui(val, 1); } @@ -4636,7 +4882,7 @@ Binary_expression::eval_integer(Operator op, const Numeric_constant* left_nc, mpz_sub(val, left_val, right_val); if (mpz_sizeinbase(val, 2) > 0x100000) { - error_at(location, "constant subtraction overflow"); + go_error_at(location, "constant subtraction overflow"); nc->set_invalid(); mpz_set_ui(val, 1); } @@ -4651,7 +4897,7 @@ Binary_expression::eval_integer(Operator op, const Numeric_constant* left_nc, mpz_mul(val, left_val, right_val); if (mpz_sizeinbase(val, 2) > 0x100000) { - error_at(location, "constant multiplication overflow"); + go_error_at(location, "constant multiplication overflow"); nc->set_invalid(); mpz_set_ui(val, 1); } @@ -4661,7 +4907,7 @@ Binary_expression::eval_integer(Operator op, const Numeric_constant* left_nc, mpz_tdiv_q(val, left_val, right_val); else { - error_at(location, "division by zero"); + go_error_at(location, "division by zero"); nc->set_invalid(); mpz_set_ui(val, 0); } @@ -4671,7 +4917,7 @@ Binary_expression::eval_integer(Operator op, const Numeric_constant* left_nc, mpz_tdiv_r(val, left_val, right_val); else { - error_at(location, "division by zero"); + go_error_at(location, "division by zero"); nc->set_invalid(); mpz_set_ui(val, 0); } @@ -4683,7 +4929,7 @@ Binary_expression::eval_integer(Operator op, const Numeric_constant* left_nc, mpz_mul_2exp(val, left_val, shift); else { - error_at(location, "shift count overflow"); + go_error_at(location, "shift count overflow"); nc->set_invalid(); mpz_set_ui(val, 1); } @@ -4695,7 +4941,7 @@ Binary_expression::eval_integer(Operator op, const Numeric_constant* left_nc, unsigned long shift = mpz_get_ui(right_val); if (mpz_cmp_ui(right_val, shift) != 0) { - error_at(location, "shift count overflow"); + go_error_at(location, "shift count overflow"); nc->set_invalid(); mpz_set_ui(val, 1); } @@ -4790,7 +5036,7 @@ Binary_expression::eval_float(Operator op, const Numeric_constant* left_nc, mpfr_div(val, left_val, right_val, GMP_RNDN); else { - error_at(location, "division by zero"); + go_error_at(location, "division by zero"); nc->set_invalid(); mpfr_set_ui(val, 0, GMP_RNDN); } @@ -4855,7 +5101,7 @@ Binary_expression::eval_complex(Operator op, const Numeric_constant* left_nc, case OPERATOR_DIV: if (mpc_cmp_si(right_val, 0) == 0) { - error_at(location, "division by zero"); + go_error_at(location, "division by zero"); nc->set_invalid(); mpc_set_ui(val, 0, MPC_RNDNN); break; @@ -4917,9 +5163,15 @@ Binary_expression::do_lower(Gogo* gogo, Named_object*, else { Numeric_constant nc; + bool issued_error; if (!Binary_expression::eval_constant(op, &left_nc, &right_nc, - location, &nc)) + location, &nc, + &issued_error)) + { + if (issued_error) + return Expression::make_error(location); return this; + } return nc.expression(location); } } @@ -4963,6 +5215,31 @@ Binary_expression::do_lower(Gogo* gogo, Named_object*, return this->lower_interface_value_comparison(gogo, inserter); } + // Lower string concatenation to String_concat_expression, so that + // we can group sequences of string additions. + if (this->left_->type()->is_string_type() && this->op_ == OPERATOR_PLUS) + { + Expression_list* exprs; + String_concat_expression* left_sce = + this->left_->string_concat_expression(); + if (left_sce != NULL) + exprs = left_sce->exprs(); + else + { + exprs = new Expression_list(); + exprs->push_back(this->left_); + } + + String_concat_expression* right_sce = + this->right_->string_concat_expression(); + if (right_sce != NULL) + exprs->append(right_sce->exprs()); + else + exprs->push_back(this->right_); + + return Expression::make_string_concat(exprs); + } + return this; } @@ -5079,7 +5356,6 @@ Binary_expression::lower_array_comparison(Gogo* gogo, Expression_list* args = new Expression_list(); args->push_back(this->operand_address(inserter, this->left_)); args->push_back(this->operand_address(inserter, this->right_)); - args->push_back(Expression::make_type_info(at, TYPE_INFO_SIZE)); Expression* ret = Expression::make_call(func, args, false, loc); @@ -5172,25 +5448,6 @@ Binary_expression::do_flatten(Gogo* gogo, Named_object*, } Temporary_statement* temp; - if (this->left_->type()->is_string_type() - && this->op_ == OPERATOR_PLUS) - { - if (!this->left_->is_variable() - && !this->left_->is_constant()) - { - temp = Statement::make_temporary(NULL, this->left_, loc); - inserter->insert(temp); - this->left_ = Expression::make_temporary_reference(temp, loc); - } - if (!this->right_->is_variable() - && !this->right_->is_constant()) - { - temp = - Statement::make_temporary(this->left_->type(), this->right_, loc); - this->right_ = Expression::make_temporary_reference(temp, loc); - inserter->insert(temp); - } - } Type* left_type = this->left_->type(); bool is_shift_op = (this->op_ == OPERATOR_LSHIFT @@ -5254,8 +5511,9 @@ Binary_expression::do_numeric_constant_value(Numeric_constant* nc) const Numeric_constant right_nc; if (!this->right_->numeric_constant_value(&right_nc)) return false; + bool issued_error; return Binary_expression::eval_constant(this->op_, &left_nc, &right_nc, - this->location(), nc); + this->location(), nc, &issued_error); } // Note that the value is being discarded. @@ -5354,7 +5612,12 @@ Binary_expression::do_determine_type(const Type_context* context) Type_context subcontext(*context); - if (is_comparison) + if (is_constant_expr) + { + subcontext.type = NULL; + subcontext.may_be_abstract = true; + } + else if (is_comparison) { // In a comparison, the context does not determine the types of // the operands. @@ -5396,8 +5659,7 @@ Binary_expression::do_determine_type(const Type_context* context) subcontext.type = subcontext.type->make_non_abstract_type(); } - if (!is_constant_expr) - this->left_->determine_type(&subcontext); + this->left_->determine_type(&subcontext); if (is_shift_op) { @@ -5417,8 +5679,7 @@ Binary_expression::do_determine_type(const Type_context* context) subcontext.may_be_abstract = false; } - if (!is_constant_expr) - this->right_->determine_type(&subcontext); + this->right_->determine_type(&subcontext); if (is_comparison) { @@ -5446,7 +5707,7 @@ Binary_expression::check_operator_type(Operator op, Type* type, Type* otype, if (!type->is_boolean_type() || !otype->is_boolean_type()) { - error_at(location, "expected boolean type"); + go_error_at(location, "expected boolean type"); return false; } break; @@ -5457,7 +5718,7 @@ Binary_expression::check_operator_type(Operator op, Type* type, Type* otype, std::string reason; if (!Type::are_compatible_for_comparison(true, type, otype, &reason)) { - error_at(location, "%s", reason.c_str()); + go_error_at(location, "%s", reason.c_str()); return false; } } @@ -5471,7 +5732,7 @@ Binary_expression::check_operator_type(Operator op, Type* type, Type* otype, std::string reason; if (!Type::are_compatible_for_comparison(false, type, otype, &reason)) { - error_at(location, "%s", reason.c_str()); + go_error_at(location, "%s", reason.c_str()); return false; } } @@ -5482,7 +5743,7 @@ Binary_expression::check_operator_type(Operator op, Type* type, Type* otype, if ((!type->is_numeric_type() && !type->is_string_type()) || (!otype->is_numeric_type() && !otype->is_string_type())) { - error_at(location, + go_error_at(location, "expected integer, floating, complex, or string type"); return false; } @@ -5496,7 +5757,7 @@ Binary_expression::check_operator_type(Operator op, Type* type, Type* otype, case OPERATOR_DIVEQ: if (!type->is_numeric_type() || !otype->is_numeric_type()) { - error_at(location, "expected integer, floating, or complex type"); + go_error_at(location, "expected integer, floating, or complex type"); return false; } break; @@ -5513,7 +5774,7 @@ Binary_expression::check_operator_type(Operator op, Type* type, Type* otype, case OPERATOR_BITCLEAREQ: if (type->integer_type() == NULL || otype->integer_type() == NULL) { - error_at(location, "expected integer type"); + go_error_at(location, "expected integer type"); return false; } break; @@ -5671,6 +5932,7 @@ Binary_expression::do_get_backend(Translate_context* context) case OPERATOR_DIV: if (left_type->float_type() != NULL || left_type->complex_type() != NULL) break; + // Fall through. case OPERATOR_MOD: is_idiv_op = true; break; @@ -5686,14 +5948,9 @@ Binary_expression::do_get_backend(Translate_context* context) go_unreachable(); } - if (left_type->is_string_type()) - { - go_assert(this->op_ == OPERATOR_PLUS); - Expression* string_plus = - Runtime::make_call(Runtime::STRING_PLUS, loc, 2, - this->left_, this->right_); - return string_plus->get_backend(context); - } + // The only binary operation for string is +, and that should have + // been converted to a String_concat_expression in do_lower. + go_assert(!left_type->is_string_type()); // For complex division Go might want slightly different results than the // backend implementation provides, so we have our own runtime routine. @@ -5756,6 +6013,7 @@ Binary_expression::do_get_backend(Translate_context* context) Bexpression* zero_expr = gogo->backend()->integer_constant_expression(left_btype, zero); overflow = zero_expr; + Bfunction* bfn = context->function()->func_value()->get_decl(); if (this->op_ == OPERATOR_RSHIFT && !left_type->integer_type()->is_unsigned()) { @@ -5764,11 +6022,12 @@ Binary_expression::do_get_backend(Translate_context* context) zero_expr, loc); Bexpression* neg_one_expr = gogo->backend()->integer_constant_expression(left_btype, neg_one); - overflow = gogo->backend()->conditional_expression(btype, neg_expr, + overflow = gogo->backend()->conditional_expression(bfn, + btype, neg_expr, neg_one_expr, zero_expr, loc); } - ret = gogo->backend()->conditional_expression(btype, compare, ret, + ret = gogo->backend()->conditional_expression(bfn, btype, compare, ret, overflow, loc); mpz_clear(bitsval); } @@ -5791,7 +6050,9 @@ Binary_expression::do_get_backend(Translate_context* context) loc)->get_backend(context); // right == 0 ? (__go_runtime_error(...), 0) : ret - ret = gogo->backend()->conditional_expression(btype, check, crash, + Bfunction* bfn = context->function()->func_value()->get_decl(); + ret = gogo->backend()->conditional_expression(bfn, btype, + check, crash, ret, loc); } @@ -5811,6 +6072,7 @@ Binary_expression::do_get_backend(Translate_context* context) gogo->backend()->integer_constant_expression(btype, zero); Bexpression* one_expr = gogo->backend()->integer_constant_expression(btype, one); + Bfunction* bfn = context->function()->func_value()->get_decl(); if (type->integer_type()->is_unsigned()) { @@ -5822,12 +6084,12 @@ Binary_expression::do_get_backend(Translate_context* context) left, right, loc); if (this->op_ == OPERATOR_DIV) overflow = - gogo->backend()->conditional_expression(btype, cmp, + gogo->backend()->conditional_expression(bfn, btype, cmp, one_expr, zero_expr, loc); else overflow = - gogo->backend()->conditional_expression(btype, cmp, + gogo->backend()->conditional_expression(bfn, btype, cmp, zero_expr, left, loc); } @@ -5847,7 +6109,8 @@ Binary_expression::do_get_backend(Translate_context* context) overflow = gogo->backend()->convert_expression(btype, overflow, loc); // right == -1 ? - left : ret - ret = gogo->backend()->conditional_expression(btype, check, overflow, + ret = gogo->backend()->conditional_expression(bfn, btype, + check, overflow, ret, loc); } } @@ -6038,7 +6301,7 @@ Binary_expression::do_import(Import* imp) } else { - error_at(imp->location(), "unrecognized binary operator"); + go_error_at(imp->location(), "unrecognized binary operator"); return Expression::make_error(imp->location()); } @@ -6086,9 +6349,18 @@ Expression::comparison(Translate_context* context, Type* result_type, if (left_type->is_string_type() && right_type->is_string_type()) { - left = Runtime::make_call(Runtime::STRCMP, location, 2, - left, right); - right = zexpr; + if (op == OPERATOR_EQEQ || op == OPERATOR_NOTEQ) + { + left = Runtime::make_call(Runtime::EQSTRING, location, 2, + left, right); + right = Expression::make_boolean(true, location); + } + else + { + left = Runtime::make_call(Runtime::CMPSTRING, location, 2, + left, right); + right = zexpr; + } } else if ((left_type->interface_type() != NULL && right_type->interface_type() == NULL @@ -6120,11 +6392,12 @@ Expression::comparison(Translate_context* context, Type* result_type, Expression::make_type_descriptor(right_type, location); left = Runtime::make_call((left_type->interface_type()->is_empty() - ? Runtime::EMPTY_INTERFACE_VALUE_COMPARE - : Runtime::INTERFACE_VALUE_COMPARE), + ? Runtime::EFACEVALEQ + : Runtime::IFACEVALEQ), location, 3, left, descriptor, pointer_arg); - right = zexpr; + go_assert(op == OPERATOR_EQEQ || op == OPERATOR_NOTEQ); + right = Expression::make_boolean(true, location); } else if (left_type->interface_type() != NULL && right_type->interface_type() != NULL) @@ -6132,25 +6405,25 @@ Expression::comparison(Translate_context* context, Type* result_type, Runtime::Function compare_function; if (left_type->interface_type()->is_empty() && right_type->interface_type()->is_empty()) - compare_function = Runtime::EMPTY_INTERFACE_COMPARE; + compare_function = Runtime::EFACEEQ; else if (!left_type->interface_type()->is_empty() && !right_type->interface_type()->is_empty()) - compare_function = Runtime::INTERFACE_COMPARE; + compare_function = Runtime::IFACEEQ; else { if (left_type->interface_type()->is_empty()) { - go_assert(op == OPERATOR_EQEQ || op == OPERATOR_NOTEQ); std::swap(left_type, right_type); std::swap(left, right); } go_assert(!left_type->interface_type()->is_empty()); go_assert(right_type->interface_type()->is_empty()); - compare_function = Runtime::INTERFACE_EMPTY_COMPARE; + compare_function = Runtime::IFACEEFACEEQ; } left = Runtime::make_call(compare_function, location, 2, left, right); - right = zexpr; + go_assert(op == OPERATOR_EQEQ || op == OPERATOR_NOTEQ); + right = Expression::make_boolean(true, location); } if (left_type->is_nil_type() @@ -6188,42 +6461,190 @@ Expression::comparison(Translate_context* context, Type* result_type, return ret; } -// Class Bound_method_expression. +// Class String_concat_expression. -// Traversal. +bool +String_concat_expression::do_is_constant() const +{ + for (Expression_list::const_iterator pe = this->exprs_->begin(); + pe != this->exprs_->end(); + ++pe) + { + if (!(*pe)->is_constant()) + return false; + } + return true; +} -int -Bound_method_expression::do_traverse(Traverse* traverse) +bool +String_concat_expression::do_is_static_initializer() const { - return Expression::traverse(&this->expr_, traverse); + for (Expression_list::const_iterator pe = this->exprs_->begin(); + pe != this->exprs_->end(); + ++pe) + { + if (!(*pe)->is_static_initializer()) + return false; + } + return true; +} + +Type* +String_concat_expression::do_type() +{ + Type* t = this->exprs_->front()->type(); + Expression_list::iterator pe = this->exprs_->begin(); + ++pe; + for (; pe != this->exprs_->end(); ++pe) + { + Type* t1; + if (!Binary_expression::operation_type(OPERATOR_PLUS, t, + (*pe)->type(), + &t1)) + return Type::make_error_type(); + t = t1; + } + return t; } -// Lower the expression. If this is a method value rather than being -// called, and the method is accessed via a pointer, we may need to -// add nil checks. Introduce a temporary variable so that those nil -// checks do not cause multiple evaluation. +void +String_concat_expression::do_determine_type(const Type_context* context) +{ + Type_context subcontext(*context); + for (Expression_list::iterator pe = this->exprs_->begin(); + pe != this->exprs_->end(); + ++pe) + { + Type* t = (*pe)->type(); + if (!t->is_abstract()) + { + subcontext.type = t; + break; + } + } + if (subcontext.type == NULL) + subcontext.type = this->exprs_->front()->type(); + for (Expression_list::iterator pe = this->exprs_->begin(); + pe != this->exprs_->end(); + ++pe) + (*pe)->determine_type(&subcontext); +} + +void +String_concat_expression::do_check_types(Gogo*) +{ + if (this->is_error_expression()) + return; + Type* t = this->exprs_->front()->type(); + if (t->is_error()) + { + this->set_is_error(); + return; + } + Expression_list::iterator pe = this->exprs_->begin(); + ++pe; + for (; pe != this->exprs_->end(); ++pe) + { + Type* t1 = (*pe)->type(); + if (!Type::are_compatible_for_binop(t, t1)) + { + this->report_error("incompatible types in binary expression"); + return; + } + if (!Binary_expression::check_operator_type(OPERATOR_PLUS, t, t1, + this->location())) + { + this->set_is_error(); + return; + } + } +} Expression* -Bound_method_expression::do_lower(Gogo*, Named_object*, - Statement_inserter* inserter, int) +String_concat_expression::do_flatten(Gogo*, Named_object*, + Statement_inserter*) { - // For simplicity we use a temporary for every call to an embedded - // method, even though some of them might be pure value methods and - // not require a temporary. - if (this->expr_->var_expression() == NULL - && this->expr_->temporary_reference_expression() == NULL - && this->expr_->set_and_use_temporary_expression() == NULL - && (this->method_->field_indexes() != NULL - || (this->method_->is_value_method() - && this->expr_->type()->points_to() != NULL))) + if (this->is_error_expression()) + return this; + Location loc = this->location(); + Type* type = this->type(); + Expression* nil_arg = Expression::make_nil(loc); + Expression* call; + switch (this->exprs_->size()) { - Temporary_statement* temp = - Statement::make_temporary(this->expr_->type(), NULL, this->location()); - inserter->insert(temp); - this->expr_ = Expression::make_set_and_use_temporary(temp, this->expr_, - this->location()); + case 0: case 1: + go_unreachable(); + + case 2: case 3: case 4: case 5: + { + Expression* len = Expression::make_integer_ul(this->exprs_->size(), + NULL, loc); + Array_type* arg_type = Type::make_array_type(type, len); + arg_type->set_is_array_incomparable(); + Expression* arg = + Expression::make_array_composite_literal(arg_type, this->exprs_, + loc); + Runtime::Function code; + switch (this->exprs_->size()) + { + default: + go_unreachable(); + case 2: + code = Runtime::CONCATSTRING2; + break; + case 3: + code = Runtime::CONCATSTRING3; + break; + case 4: + code = Runtime::CONCATSTRING4; + break; + case 5: + code = Runtime::CONCATSTRING5; + break; + } + call = Runtime::make_call(code, loc, 2, nil_arg, arg); + } + break; + + default: + { + Type* arg_type = Type::make_array_type(type, NULL); + Slice_construction_expression* sce = + Expression::make_slice_composite_literal(arg_type, this->exprs_, + loc); + sce->set_storage_does_not_escape(); + call = Runtime::make_call(Runtime::CONCATSTRINGS, loc, 2, nil_arg, + sce); + } + break; } - return this; + + return Expression::make_cast(type, call, loc); +} + +void +String_concat_expression::do_dump_expression( + Ast_dump_context* ast_dump_context) const +{ + ast_dump_context->ostream() << "concat("; + ast_dump_context->dump_expression_list(this->exprs_, false); + ast_dump_context->ostream() << ")"; +} + +Expression* +Expression::make_string_concat(Expression_list* exprs) +{ + return new String_concat_expression(exprs); +} + +// Class Bound_method_expression. + +// Traversal. + +int +Bound_method_expression::do_traverse(Traverse* traverse) +{ + return Expression::traverse(&this->expr_, traverse); } // Return the type of a bound method expression. The type of this @@ -6347,8 +6768,9 @@ Bound_method_expression::create_thunk(Gogo* gogo, const Method* method, sfl->push_back(Struct_field(Typed_identifier("val.1", orig_fntype->receiver()->type(), loc))); - Type* closure_type = Type::make_struct_type(sfl, loc); - closure_type = Type::make_pointer_type(closure_type); + Struct_type* st = Type::make_struct_type(sfl, loc); + st->set_is_struct_incomparable(); + Type* closure_type = Type::make_pointer_type(st); Function_type* new_fntype = orig_fntype->copy_with_names(); @@ -6440,32 +6862,43 @@ bme_check_nil(const Method::Field_indexes* field_indexes, Location loc, return cond; } -// Get the backend representation for a method value. +// Flatten a method value into a struct with nil checks. We can't do +// this in the lowering phase, because if the method value is called +// directly we don't need a thunk. That case will have been handled +// by Call_expression::do_lower, so if we get here then we do need a +// thunk. -Bexpression* -Bound_method_expression::do_get_backend(Translate_context* context) +Expression* +Bound_method_expression::do_flatten(Gogo* gogo, Named_object*, + Statement_inserter* inserter) { - Named_object* thunk = Bound_method_expression::create_thunk(context->gogo(), + Location loc = this->location(); + + Named_object* thunk = Bound_method_expression::create_thunk(gogo, this->method_, this->function_); if (thunk->is_erroneous()) { go_assert(saw_errors()); - return context->backend()->error_expression(); + return Expression::make_error(loc); } - // FIXME: We should lower this earlier, but we can't lower it in the - // lowering pass because at that point we don't know whether we need - // to create the thunk or not. If the expression is called, we - // don't need the thunk. - - Location loc = this->location(); + // Force the expression into a variable. This is only necessary if + // we are going to do nil checks below, but it's easy enough to + // always do it. + Expression* expr = this->expr_; + if (!expr->is_variable()) + { + Temporary_statement* etemp = Statement::make_temporary(NULL, expr, loc); + inserter->insert(etemp); + expr = Expression::make_temporary_reference(etemp, loc); + } // If the method expects a value, and we have a pointer, we need to // dereference the pointer. Named_object* fn = this->method_->named_object(); - Function_type* fntype; + Function_type *fntype; if (fn->is_function()) fntype = fn->func_value()->type(); else if (fn->is_function_declaration()) @@ -6473,7 +6906,7 @@ Bound_method_expression::do_get_backend(Translate_context* context) else go_unreachable(); - Expression* val = this->expr_; + Expression* val = expr; if (fntype->receiver()->type()->points_to() == NULL && val->type()->points_to() != NULL) val = Expression::make_unary(OPERATOR_MULT, val, loc); @@ -6491,23 +6924,35 @@ Bound_method_expression::do_get_backend(Translate_context* context) loc))); fields->push_back(Struct_field(Typed_identifier("val.1", val->type(), loc))); Struct_type* st = Type::make_struct_type(fields, loc); + st->set_is_struct_incomparable(); Expression_list* vals = new Expression_list(); vals->push_back(Expression::make_func_code_reference(thunk, loc)); vals->push_back(val); Expression* ret = Expression::make_struct_composite_literal(st, vals, loc); - ret = Expression::make_heap_expression(ret, loc); - // See whether the expression or any embedded pointers are nil. + if (!gogo->compiling_runtime() || gogo->package_name() != "runtime") + ret = Expression::make_heap_expression(ret, loc); + else + { + // When compiling the runtime, method closures do not escape. + // When escape analysis becomes the default, and applies to + // method closures, this should be changed to make it an error + // if a method closure escapes. + Temporary_statement* ctemp = Statement::make_temporary(st, ret, loc); + inserter->insert(ctemp); + ret = Expression::make_temporary_reference(ctemp, loc); + ret = Expression::make_unary(OPERATOR_AND, ret, loc); + ret->unary_expression()->set_does_not_escape(); + } + + // If necessary, check whether the expression or any embedded + // pointers are nil. Expression* nil_check = NULL; - Expression* expr = this->expr_; if (this->method_->field_indexes() != NULL) { - // Note that we are evaluating this->expr_ twice, but that is OK - // because in the lowering pass we forced it into a temporary - // variable. Expression* ref = expr; nil_check = bme_check_nil(this->method_->field_indexes(), loc, &ref); expr = ref; @@ -6524,19 +6969,20 @@ Bound_method_expression::do_get_backend(Translate_context* context) nil_check = Expression::make_binary(OPERATOR_OROR, nil_check, n, loc); } - Bexpression* bme = ret->get_backend(context); if (nil_check != NULL) { - Gogo* gogo = context->gogo(); - Bexpression* crash = - gogo->runtime_error(RUNTIME_ERROR_NIL_DEREFERENCE, - loc)->get_backend(context); - Btype* btype = ret->type()->get_backend(gogo); - Bexpression* bcheck = nil_check->get_backend(context); - bme = gogo->backend()->conditional_expression(btype, bcheck, crash, - bme, loc); + Expression* crash = gogo->runtime_error(RUNTIME_ERROR_NIL_DEREFERENCE, + loc); + // Fix the type of the conditional expression by pretending to + // evaluate to RET either way through the conditional. + crash = Expression::make_compound(crash, ret, loc); + ret = Expression::make_conditional(nil_check, crash, ret, loc); } - return bme; + + // RET is a pointer to a struct, but we want a function type. + ret = Expression::make_unsafe_cast(this->type(), ret, loc); + + return ret; } // Dump ast representation of a bound method expression. @@ -6659,10 +7105,12 @@ class Builtin_call_expression : public Call_expression complex_type(Type*); Expression* - lower_make(); + lower_make(Statement_inserter*); + + Expression* flatten_append(Gogo*, Named_object*, Statement_inserter*); bool - check_int_value(Expression*, bool is_length); + check_int_value(Expression*, bool is_length, bool* small); // A pointer back to the general IR structure. This avoids a global // variable, or passing it around everywhere. @@ -6760,7 +7208,7 @@ Builtin_call_expression::do_set_recover_arg(Expression* arg) // specific expressions. We also convert to a constant if we can. Expression* -Builtin_call_expression::do_lower(Gogo* gogo, Named_object* function, +Builtin_call_expression::do_lower(Gogo*, Named_object* function, Statement_inserter* inserter, int) { if (this->is_error_expression()) @@ -6828,7 +7276,7 @@ Builtin_call_expression::do_lower(Gogo* gogo, Named_object* function, Expression* arg = args->front(); if (!arg->is_type_expression()) { - error_at(arg->location(), "expected type"); + go_error_at(arg->location(), "expected type"); this->set_is_error(); } else @@ -6838,7 +7286,7 @@ Builtin_call_expression::do_lower(Gogo* gogo, Named_object* function, break; case BUILTIN_MAKE: - return this->lower_make(); + return this->lower_make(inserter); case BUILTIN_RECOVER: if (function != NULL) @@ -6852,30 +7300,6 @@ Builtin_call_expression::do_lower(Gogo* gogo, Named_object* function, } break; - case BUILTIN_APPEND: - { - // Lower the varargs. - const Expression_list* args = this->args(); - if (args == NULL || args->empty()) - return this; - Type* slice_type = args->front()->type(); - if (!slice_type->is_slice_type()) - { - if (slice_type->is_nil_type()) - error_at(args->front()->location(), "use of untyped nil"); - else - error_at(args->front()->location(), - "argument 1 must be a slice"); - this->set_is_error(); - return this; - } - Type* element_type = slice_type->array_type()->element_type(); - this->lower_varargs(gogo, function, inserter, - Type::make_array_type(element_type, NULL), - 2); - } - break; - case BUILTIN_DELETE: { // Lower to a runtime function call. @@ -6901,16 +7325,37 @@ Builtin_call_expression::do_lower(Gogo* gogo, Named_object* function, Statement::make_temporary(mt->key_type(), args->back(), loc); inserter->insert(key_temp); - Expression* e1 = Expression::make_temporary_reference(map_temp, + Expression* e1 = Expression::make_type_descriptor(mt, loc); + Expression* e2 = Expression::make_temporary_reference(map_temp, loc); - Expression* e2 = Expression::make_temporary_reference(key_temp, + Expression* e3 = Expression::make_temporary_reference(key_temp, loc); - e2 = Expression::make_unary(OPERATOR_AND, e2, loc); + e3 = Expression::make_unary(OPERATOR_AND, e3, loc); return Runtime::make_call(Runtime::MAPDELETE, this->location(), - 2, e1, e2); + 3, e1, e2, e3); } } break; + + case BUILTIN_PRINT: + case BUILTIN_PRINTLN: + // Force all the arguments into temporary variables, so that we + // don't try to evaluate something while holding the print lock. + if (this->args() == NULL) + break; + for (Expression_list::iterator pa = this->args()->begin(); + pa != this->args()->end(); + ++pa) + { + if (!(*pa)->is_variable() && !(*pa)->is_constant()) + { + Temporary_statement* temp = + Statement::make_temporary(NULL, *pa, loc); + inserter->insert(temp); + *pa = Expression::make_temporary_reference(temp, loc); + } + } + break; } return this; @@ -6920,7 +7365,7 @@ Builtin_call_expression::do_lower(Gogo* gogo, Named_object* function, // append into temporary expressions. Expression* -Builtin_call_expression::do_flatten(Gogo*, Named_object*, +Builtin_call_expression::do_flatten(Gogo* gogo, Named_object* function, Statement_inserter* inserter) { Location loc = this->location(); @@ -6931,6 +7376,8 @@ Builtin_call_expression::do_flatten(Gogo*, Named_object*, break; case BUILTIN_APPEND: + return this->flatten_append(gogo, function, inserter); + case BUILTIN_COPY: { Type* at = this->args()->front()->type(); @@ -6968,6 +7415,23 @@ Builtin_call_expression::do_flatten(Gogo*, Named_object*, *pa = Expression::make_temporary_reference(temp, loc); } } + break; + + case BUILTIN_LEN: + case BUILTIN_CAP: + { + Expression_list::iterator pa = this->args()->begin(); + if (!(*pa)->is_variable() + && ((*pa)->type()->map_type() != NULL + || (*pa)->type()->channel_type() != NULL)) + { + Temporary_statement* temp = + Statement::make_temporary(NULL, *pa, loc); + inserter->insert(temp); + *pa = Expression::make_temporary_reference(temp, loc); + } + } + break; } return this; @@ -6976,7 +7440,7 @@ Builtin_call_expression::do_flatten(Gogo*, Named_object*, // Lower a make expression. Expression* -Builtin_call_expression::lower_make() +Builtin_call_expression::lower_make(Statement_inserter* inserter) { Location loc = this->location(); @@ -6992,7 +7456,7 @@ Builtin_call_expression::lower_make() Expression* first_arg = *parg; if (!first_arg->is_type_expression()) { - error_at(first_arg->location(), "expected type"); + go_error_at(first_arg->location(), "expected type"); this->set_is_error(); return Expression::make_error(this->location()); } @@ -7013,14 +7477,11 @@ Builtin_call_expression::lower_make() return Expression::make_error(this->location()); } - bool have_big_args = false; - Type* uintptr_type = Type::lookup_integer_type("uintptr"); - int uintptr_bits = uintptr_type->integer_type()->bits(); - Type_context int_context(Type::lookup_integer_type("int"), false); ++parg; Expression* len_arg; + bool len_small = false; if (parg == args->end()) { if (is_slice) @@ -7034,20 +7495,18 @@ Builtin_call_expression::lower_make() { len_arg = *parg; len_arg->determine_type(&int_context); - if (!this->check_int_value(len_arg, true)) + if (!this->check_int_value(len_arg, true, &len_small)) return Expression::make_error(this->location()); - if (len_arg->type()->integer_type() != NULL - && len_arg->type()->integer_type()->bits() > uintptr_bits) - have_big_args = true; ++parg; } Expression* cap_arg = NULL; + bool cap_small = false; if (is_slice && parg != args->end()) { cap_arg = *parg; cap_arg->determine_type(&int_context); - if (!this->check_int_value(cap_arg, false)) + if (!this->check_int_value(cap_arg, false, &cap_small)) return Expression::make_error(this->location()); Numeric_constant nclen; @@ -7064,9 +7523,6 @@ Builtin_call_expression::lower_make() return Expression::make_error(this->location()); } - if (cap_arg->type()->integer_type() != NULL - && cap_arg->type()->integer_type()->bits() > uintptr_bits) - have_big_args = true; ++parg; } @@ -7077,51 +7533,250 @@ Builtin_call_expression::lower_make() } Location type_loc = first_arg->location(); - Expression* type_arg; - if (is_slice || is_chan) - type_arg = Expression::make_type_descriptor(type, type_loc); - else if (is_map) - type_arg = Expression::make_map_descriptor(type->map_type(), type_loc); - else - go_unreachable(); Expression* call; if (is_slice) { + Type* et = type->array_type()->element_type(); + Expression* type_arg = Expression::make_type_descriptor(et, type_loc); if (cap_arg == NULL) - call = Runtime::make_call((have_big_args - ? Runtime::MAKESLICE1BIG - : Runtime::MAKESLICE1), - loc, 2, type_arg, len_arg); - else - call = Runtime::make_call((have_big_args - ? Runtime::MAKESLICE2BIG - : Runtime::MAKESLICE2), - loc, 3, type_arg, len_arg, cap_arg); + { + Temporary_statement* temp = Statement::make_temporary(NULL, + len_arg, + loc); + inserter->insert(temp); + len_arg = Expression::make_temporary_reference(temp, loc); + cap_arg = Expression::make_temporary_reference(temp, loc); + cap_small = len_small; + } + + Runtime::Function code = Runtime::MAKESLICE; + if (!len_small || !cap_small) + code = Runtime::MAKESLICE64; + call = Runtime::make_call(code, loc, 3, type_arg, len_arg, cap_arg); } else if (is_map) - call = Runtime::make_call((have_big_args - ? Runtime::MAKEMAPBIG - : Runtime::MAKEMAP), - loc, 2, type_arg, len_arg); + { + Expression* type_arg = Expression::make_type_descriptor(type, type_loc); + call = Runtime::make_call(Runtime::MAKEMAP, loc, 4, type_arg, len_arg, + Expression::make_nil(loc), + Expression::make_nil(loc)); + } else if (is_chan) - call = Runtime::make_call((have_big_args - ? Runtime::MAKECHANBIG - : Runtime::MAKECHAN), - loc, 2, type_arg, len_arg); + { + Expression* type_arg = Expression::make_type_descriptor(type, type_loc); + call = Runtime::make_call(Runtime::MAKECHAN, loc, 2, type_arg, len_arg); + } else go_unreachable(); return Expression::make_unsafe_cast(type, call, loc); } +// Flatten a call to the predeclared append function. We do this in +// the flatten phase, not the lowering phase, so that we run after +// type checking and after order_evaluations. + +Expression* +Builtin_call_expression::flatten_append(Gogo* gogo, Named_object* function, + Statement_inserter* inserter) +{ + if (this->is_error_expression()) + return this; + + Location loc = this->location(); + + const Expression_list* args = this->args(); + go_assert(args != NULL && !args->empty()); + + Type* slice_type = args->front()->type(); + go_assert(slice_type->is_slice_type()); + Type* element_type = slice_type->array_type()->element_type(); + + if (args->size() == 1) + { + // append(s) evaluates to s. + return args->front(); + } + + Type* int_type = Type::lookup_integer_type("int"); + Type* uint_type = Type::lookup_integer_type("uint"); + + // Implementing + // append(s1, s2...) + // or + // append(s1, a1, a2, a3, ...) + + // s1tmp := s1 + Temporary_statement* s1tmp = Statement::make_temporary(NULL, args->front(), + loc); + inserter->insert(s1tmp); + + // l1tmp := len(s1tmp) + Named_object* lenfn = gogo->lookup_global("len"); + Expression* lenref = Expression::make_func_reference(lenfn, NULL, loc); + Expression_list* call_args = new Expression_list(); + call_args->push_back(Expression::make_temporary_reference(s1tmp, loc)); + Expression* len = Expression::make_call(lenref, call_args, false, loc); + gogo->lower_expression(function, inserter, &len); + gogo->flatten_expression(function, inserter, &len); + Temporary_statement* l1tmp = Statement::make_temporary(int_type, len, loc); + inserter->insert(l1tmp); + + Temporary_statement* s2tmp = NULL; + Temporary_statement* l2tmp = NULL; + Expression_list* add = NULL; + Expression* len2; + if (this->is_varargs()) + { + go_assert(args->size() == 2); + + // s2tmp := s2 + s2tmp = Statement::make_temporary(NULL, args->back(), loc); + inserter->insert(s2tmp); + + // l2tmp := len(s2tmp) + lenref = Expression::make_func_reference(lenfn, NULL, loc); + call_args = new Expression_list(); + call_args->push_back(Expression::make_temporary_reference(s2tmp, loc)); + len = Expression::make_call(lenref, call_args, false, loc); + gogo->lower_expression(function, inserter, &len); + gogo->flatten_expression(function, inserter, &len); + l2tmp = Statement::make_temporary(int_type, len, loc); + inserter->insert(l2tmp); + + // len2 = l2tmp + len2 = Expression::make_temporary_reference(l2tmp, loc); + } + else + { + // We have to ensure that all the arguments are in variables + // now, because otherwise if one of them is an index expression + // into the current slice we could overwrite it before we fetch + // it. + add = new Expression_list(); + Expression_list::const_iterator pa = args->begin(); + for (++pa; pa != args->end(); ++pa) + { + if ((*pa)->is_variable()) + add->push_back(*pa); + else + { + Temporary_statement* tmp = Statement::make_temporary(NULL, *pa, + loc); + inserter->insert(tmp); + add->push_back(Expression::make_temporary_reference(tmp, loc)); + } + } + + // len2 = len(add) + len2 = Expression::make_integer_ul(add->size(), int_type, loc); + } + + // ntmp := l1tmp + len2 + Expression* ref = Expression::make_temporary_reference(l1tmp, loc); + Expression* sum = Expression::make_binary(OPERATOR_PLUS, ref, len2, loc); + gogo->lower_expression(function, inserter, &sum); + gogo->flatten_expression(function, inserter, &sum); + Temporary_statement* ntmp = Statement::make_temporary(int_type, sum, loc); + inserter->insert(ntmp); + + // s1tmp = uint(ntmp) > uint(cap(s1tmp)) ? + // growslice(type, s1tmp, ntmp) : + // s1tmp[:ntmp] + // Using uint here means that if the computation of ntmp overflowed, + // we will call growslice which will panic. + + Expression* left = Expression::make_temporary_reference(ntmp, loc); + left = Expression::make_cast(uint_type, left, loc); + + Named_object* capfn = gogo->lookup_global("cap"); + Expression* capref = Expression::make_func_reference(capfn, NULL, loc); + call_args = new Expression_list(); + call_args->push_back(Expression::make_temporary_reference(s1tmp, loc)); + Expression* right = Expression::make_call(capref, call_args, false, loc); + right = Expression::make_cast(uint_type, right, loc); + + Expression* cond = Expression::make_binary(OPERATOR_GT, left, right, loc); + + Expression* a1 = Expression::make_type_descriptor(element_type, loc); + Expression* a2 = Expression::make_temporary_reference(s1tmp, loc); + Expression* a3 = Expression::make_temporary_reference(ntmp, loc); + Expression* call = Runtime::make_call(Runtime::GROWSLICE, loc, 3, + a1, a2, a3); + call = Expression::make_unsafe_cast(slice_type, call, loc); + + ref = Expression::make_temporary_reference(s1tmp, loc); + Expression* zero = Expression::make_integer_ul(0, int_type, loc); + Expression* ref2 = Expression::make_temporary_reference(ntmp, loc); + // FIXME: Mark this index as not requiring bounds checks. + ref = Expression::make_index(ref, zero, ref2, NULL, loc); + + Expression* rhs = Expression::make_conditional(cond, call, ref, loc); + + gogo->lower_expression(function, inserter, &rhs); + gogo->flatten_expression(function, inserter, &rhs); + + Expression* lhs = Expression::make_temporary_reference(s1tmp, loc); + Statement* assign = Statement::make_assignment(lhs, rhs, loc); + inserter->insert(assign); + + if (this->is_varargs()) + { + // copy(s1tmp[l1tmp:], s2tmp) + a1 = Expression::make_temporary_reference(s1tmp, loc); + ref = Expression::make_temporary_reference(l1tmp, loc); + Expression* nil = Expression::make_nil(loc); + // FIXME: Mark this index as not requiring bounds checks. + a1 = Expression::make_index(a1, ref, nil, NULL, loc); + + a2 = Expression::make_temporary_reference(s2tmp, loc); + + Named_object* copyfn = gogo->lookup_global("copy"); + Expression* copyref = Expression::make_func_reference(copyfn, NULL, loc); + call_args = new Expression_list(); + call_args->push_back(a1); + call_args->push_back(a2); + call = Expression::make_call(copyref, call_args, false, loc); + gogo->lower_expression(function, inserter, &call); + gogo->flatten_expression(function, inserter, &call); + inserter->insert(Statement::make_statement(call, false)); + } + else + { + // For each argument: + // s1tmp[l1tmp+i] = a + unsigned long i = 0; + for (Expression_list::const_iterator pa = add->begin(); + pa != add->end(); + ++pa, ++i) + { + ref = Expression::make_temporary_reference(s1tmp, loc); + ref2 = Expression::make_temporary_reference(l1tmp, loc); + Expression* off = Expression::make_integer_ul(i, int_type, loc); + ref2 = Expression::make_binary(OPERATOR_PLUS, ref2, off, loc); + // FIXME: Mark this index as not requiring bounds checks. + lhs = Expression::make_index(ref, ref2, NULL, NULL, loc); + gogo->lower_expression(function, inserter, &lhs); + gogo->flatten_expression(function, inserter, &lhs); + assign = Statement::make_assignment(lhs, *pa, loc); + inserter->insert(assign); + } + } + + return Expression::make_temporary_reference(s1tmp, loc); +} + // Return whether an expression has an integer value. Report an error // if not. This is used when handling calls to the predeclared make -// function. +// function. Set *SMALL if the value is known to fit in type "int". bool -Builtin_call_expression::check_int_value(Expression* e, bool is_length) +Builtin_call_expression::check_int_value(Expression* e, bool is_length, + bool *small) { + *small = false; + Numeric_constant nc; if (e->numeric_constant_value(&nc)) { @@ -7131,12 +7786,12 @@ Builtin_call_expression::check_int_value(Expression* e, bool is_length) case Numeric_constant::NC_UL_VALID: break; case Numeric_constant::NC_UL_NOTINT: - error_at(e->location(), "non-integer %s argument to make", - is_length ? "len" : "cap"); + go_error_at(e->location(), "non-integer %s argument to make", + is_length ? "len" : "cap"); return false; case Numeric_constant::NC_UL_NEGATIVE: - error_at(e->location(), "negative %s argument to make", - is_length ? "len" : "cap"); + go_error_at(e->location(), "negative %s argument to make", + is_length ? "len" : "cap"); return false; case Numeric_constant::NC_UL_BIG: // We don't want to give a compile-time error for a 64-bit @@ -7152,19 +7807,30 @@ Builtin_call_expression::check_int_value(Expression* e, bool is_length) Type* int_type = Type::lookup_integer_type("int"); if (bits >= int_type->integer_type()->bits()) { - error_at(e->location(), "%s argument too large for make", - is_length ? "len" : "cap"); + go_error_at(e->location(), "%s argument too large for make", + is_length ? "len" : "cap"); return false; } + *small = true; return true; } if (e->type()->integer_type() != NULL) - return true; + { + int ebits = e->type()->integer_type()->bits(); + int intbits = Type::lookup_integer_type("int")->integer_type()->bits(); - error_at(e->location(), "non-integer %s argument to make", - is_length ? "len" : "cap"); + // We can treat ebits == intbits as small even for an unsigned + // integer type, because we will convert the value to int and + // then reject it in the runtime if it is negative. + *small = ebits <= intbits; + + return true; + } + + go_error_at(e->location(), "non-integer %s argument to make", + is_length ? "len" : "cap"); return false; } @@ -7694,6 +8360,7 @@ Builtin_call_expression::do_determine_type(const Type_context* context) bool is_print; Type* arg_type = NULL; + Type* trailing_arg_types = NULL; switch (this->code_) { case BUILTIN_PRINT: @@ -7730,6 +8397,16 @@ Builtin_call_expression::do_determine_type(const Type_context* context) } break; + case BUILTIN_APPEND: + if (!this->is_varargs() + && args != NULL + && !args->empty() + && args->front()->type()->is_slice_type()) + trailing_arg_types = + args->front()->type()->array_type()->element_type(); + is_print = false; + break; + default: is_print = false; break; @@ -7786,6 +8463,12 @@ Builtin_call_expression::do_determine_type(const Type_context* context) } (*pa)->determine_type(&subcontext); + + if (trailing_arg_types != NULL) + { + arg_type = trailing_arg_types; + trailing_arg_types = NULL; + } } } } @@ -7872,7 +8555,7 @@ Builtin_call_expression::do_check_types(Gogo*) if (args == NULL) { if (this->code_ == BUILTIN_PRINT) - warning_at(this->location(), 0, + go_warning_at(this->location(), 0, "no arguments for builtin function %<%s%>", (this->code_ == BUILTIN_PRINT ? "print" @@ -7992,53 +8675,102 @@ Builtin_call_expression::do_check_types(Gogo*) case BUILTIN_APPEND: { const Expression_list* args = this->args(); - if (args == NULL || args->size() < 2) + if (args == NULL || args->empty()) { this->report_error(_("not enough arguments")); break; } - if (args->size() > 2) - { - this->report_error(_("too many arguments")); - break; - } - if (args->front()->type()->is_error() - || args->back()->type()->is_error()) + + Type* slice_type = args->front()->type(); + if (!slice_type->is_slice_type()) { + if (slice_type->is_error_type()) + break; + if (slice_type->is_nil_type()) + go_error_at(args->front()->location(), "use of untyped nil"); + else + go_error_at(args->front()->location(), + "argument 1 must be a slice"); this->set_is_error(); break; } - Array_type* at = args->front()->type()->array_type(); - Type* e = at->element_type(); - - // The language permits appending a string to a []byte, as a - // special case. - if (args->back()->type()->is_string_type()) + Type* element_type = slice_type->array_type()->element_type(); + if (this->is_varargs()) { - if (e->integer_type() != NULL && e->integer_type()->is_byte()) - break; - } + if (!args->back()->type()->is_slice_type() + && !args->back()->type()->is_string_type()) + { + go_error_at(args->back()->location(), + "invalid use of %<...%> with non-slice/non-string"); + this->set_is_error(); + break; + } - // The language says that the second argument must be - // assignable to a slice of the element type of the first - // argument. We already know the first argument is a slice - // type. - Type* arg2_type = Type::make_array_type(e, NULL); - std::string reason; - if (!Type::are_assignable(arg2_type, args->back()->type(), &reason)) - { - if (reason.empty()) - this->report_error(_("argument 2 has invalid type")); + if (args->size() < 2) + { + this->report_error(_("not enough arguments")); + break; + } + if (args->size() > 2) + { + this->report_error(_("too many arguments")); + break; + } + + if (args->back()->type()->is_string_type() + && element_type->integer_type() != NULL + && element_type->integer_type()->is_byte()) + { + // Permit append(s1, s2...) when s1 is a slice of + // bytes and s2 is a string type. + } else { - error_at(this->location(), "argument 2 has invalid type (%s)", - reason.c_str()); - this->set_is_error(); + // We have to test for assignment compatibility to a + // slice of the element type, which is not necessarily + // the same as the type of the first argument: the + // first argument might have a named type. + Type* check_type = Type::make_array_type(element_type, NULL); + std::string reason; + if (!Type::are_assignable(check_type, args->back()->type(), + &reason)) + { + if (reason.empty()) + go_error_at(args->back()->location(), + "argument 2 has invalid type"); + else + go_error_at(args->back()->location(), + "argument 2 has invalid type (%s)", + reason.c_str()); + this->set_is_error(); + break; + } + } + } + else + { + Expression_list::const_iterator pa = args->begin(); + int i = 2; + for (++pa; pa != args->end(); ++pa, ++i) + { + std::string reason; + if (!Type::are_assignable(element_type, (*pa)->type(), + &reason)) + { + if (reason.empty()) + go_error_at((*pa)->location(), + "argument %d has incompatible type", i); + else + go_error_at((*pa)->location(), + "argument %d has incompatible type (%s)", + i, reason.c_str()); + this->set_is_error(); + } } } - break; } + break; case BUILTIN_REAL: case BUILTIN_IMAG: @@ -8153,10 +8885,23 @@ Builtin_call_expression::do_get_backend(Translate_context* context) val = arg_type->array_type()->get_length(gogo, arg); this->seen_ = false; } - else if (arg_type->map_type() != NULL) - val = Runtime::make_call(Runtime::MAP_LEN, location, 1, arg); - else if (arg_type->channel_type() != NULL) - val = Runtime::make_call(Runtime::CHAN_LEN, location, 1, arg); + else if (arg_type->map_type() != NULL + || arg_type->channel_type() != NULL) + { + // The first field is the length. If the pointer is + // nil, the length is zero. + Type* pint_type = Type::make_pointer_type(int_type); + arg = Expression::make_unsafe_cast(pint_type, arg, location); + Expression* nil = Expression::make_nil(location); + nil = Expression::make_cast(pint_type, nil, location); + Expression* cmp = Expression::make_binary(OPERATOR_EQEQ, + arg, nil, location); + Expression* zero = Expression::make_integer_ul(0, int_type, + location); + Expression* indir = Expression::make_unary(OPERATOR_MULT, + arg, location); + val = Expression::make_conditional(cmp, zero, indir, location); + } else go_unreachable(); } @@ -8174,7 +8919,31 @@ Builtin_call_expression::do_get_backend(Translate_context* context) this->seen_ = false; } else if (arg_type->channel_type() != NULL) - val = Runtime::make_call(Runtime::CHAN_CAP, location, 1, arg); + { + // The second field is the capacity. If the pointer + // is nil, the capacity is zero. + Type* uintptr_type = Type::lookup_integer_type("uintptr"); + Type* pint_type = Type::make_pointer_type(int_type); + Expression* parg = Expression::make_unsafe_cast(uintptr_type, + arg, + location); + int off = int_type->integer_type()->bits() / 8; + Expression* eoff = Expression::make_integer_ul(off, + uintptr_type, + location); + parg = Expression::make_binary(OPERATOR_PLUS, parg, eoff, + location); + parg = Expression::make_unsafe_cast(pint_type, parg, location); + Expression* nil = Expression::make_nil(location); + nil = Expression::make_cast(pint_type, nil, location); + Expression* cmp = Expression::make_binary(OPERATOR_EQEQ, + arg, nil, location); + Expression* zero = Expression::make_integer_ul(0, int_type, + location); + Expression* indir = Expression::make_unary(OPERATOR_MULT, + parg, location); + val = Expression::make_conditional(cmp, zero, indir, location); + } else go_unreachable(); } @@ -8187,7 +8956,9 @@ Builtin_call_expression::do_get_backend(Translate_context* context) case BUILTIN_PRINTLN: { const bool is_ln = this->code_ == BUILTIN_PRINTLN; - Expression* print_stmts = NULL; + + Expression* print_stmts = Runtime::make_call(Runtime::PRINTLOCK, + location, 0); const Expression_list* call_args = this->args(); if (call_args != NULL) @@ -8199,8 +8970,7 @@ Builtin_call_expression::do_get_backend(Translate_context* context) if (is_ln && p != call_args->begin()) { Expression* print_space = - Runtime::make_call(Runtime::PRINT_SPACE, - this->location(), 0); + Runtime::make_call(Runtime::PRINTSP, location, 0); print_stmts = Expression::make_compound(print_stmts, print_space, @@ -8211,51 +8981,51 @@ Builtin_call_expression::do_get_backend(Translate_context* context) Type* type = arg->type(); Runtime::Function code; if (type->is_string_type()) - code = Runtime::PRINT_STRING; + code = Runtime::PRINTSTRING; else if (type->integer_type() != NULL && type->integer_type()->is_unsigned()) { Type* itype = Type::lookup_integer_type("uint64"); arg = Expression::make_cast(itype, arg, location); - code = Runtime::PRINT_UINT64; + code = Runtime::PRINTUINT; } else if (type->integer_type() != NULL) { Type* itype = Type::lookup_integer_type("int64"); arg = Expression::make_cast(itype, arg, location); - code = Runtime::PRINT_INT64; + code = Runtime::PRINTINT; } else if (type->float_type() != NULL) { Type* dtype = Type::lookup_float_type("float64"); arg = Expression::make_cast(dtype, arg, location); - code = Runtime::PRINT_DOUBLE; + code = Runtime::PRINTFLOAT; } else if (type->complex_type() != NULL) { Type* ctype = Type::lookup_complex_type("complex128"); arg = Expression::make_cast(ctype, arg, location); - code = Runtime::PRINT_COMPLEX; + code = Runtime::PRINTCOMPLEX; } else if (type->is_boolean_type()) - code = Runtime::PRINT_BOOL; + code = Runtime::PRINTBOOL; else if (type->points_to() != NULL || type->channel_type() != NULL || type->map_type() != NULL || type->function_type() != NULL) { arg = Expression::make_cast(type, arg, location); - code = Runtime::PRINT_POINTER; + code = Runtime::PRINTPOINTER; } else if (type->interface_type() != NULL) { if (type->interface_type()->is_empty()) - code = Runtime::PRINT_EMPTY_INTERFACE; + code = Runtime::PRINTEFACE; else - code = Runtime::PRINT_INTERFACE; + code = Runtime::PRINTIFACE; } else if (type->is_slice_type()) - code = Runtime::PRINT_SLICE; + code = Runtime::PRINTSLICE; else { go_assert(saw_errors()); @@ -8263,30 +9033,22 @@ Builtin_call_expression::do_get_backend(Translate_context* context) } Expression* call = Runtime::make_call(code, location, 1, arg); - if (print_stmts == NULL) - print_stmts = call; - else - print_stmts = Expression::make_compound(print_stmts, call, - location); + print_stmts = Expression::make_compound(print_stmts, call, + location); } } if (is_ln) { Expression* print_nl = - Runtime::make_call(Runtime::PRINT_NL, location, 0); - if (print_stmts == NULL) - print_stmts = print_nl; - else - print_stmts = Expression::make_compound(print_stmts, print_nl, - location); + Runtime::make_call(Runtime::PRINTNL, location, 0); + print_stmts = Expression::make_compound(print_stmts, print_nl, + location); } - // There aren't any arguments to the print builtin. The compiler - // issues a warning for this so we should avoid getting the backend - // representation for this call. Instead, perform a no-op. - if (print_stmts == NULL) - return context->backend()->boolean_constant_expression(false); + Expression* unlock = Runtime::make_call(Runtime::PRINTUNLOCK, + location, 0); + print_stmts = Expression::make_compound(print_stmts, unlock, location); return print_stmts->get_backend(context); } @@ -8301,7 +9063,7 @@ Builtin_call_expression::do_get_backend(Translate_context* context) arg = Expression::convert_for_assignment(gogo, empty, arg, location); Expression* panic = - Runtime::make_call(Runtime::PANIC, location, 1, arg); + Runtime::make_call(Runtime::GOPANIC, location, 1, arg); return panic->get_backend(context); } @@ -8322,8 +9084,8 @@ Builtin_call_expression::do_get_backend(Translate_context* context) // because it changes whether it can recover a panic or not. // See test7 in test/recover1.go. Expression* recover = Runtime::make_call((this->is_deferred() - ? Runtime::DEFERRED_RECOVER - : Runtime::RECOVER), + ? Runtime::DEFERREDRECOVER + : Runtime::GORECOVER), location, 0); Expression* cond = Expression::make_conditional(arg, recover, nil, location); @@ -8371,97 +9133,39 @@ Builtin_call_expression::do_get_backend(Translate_context* context) Type* arg1_type = arg1->type(); Array_type* at = arg1_type->array_type(); go_assert(arg1->is_variable()); - Expression* arg1_val = at->get_value_pointer(gogo, arg1); - Expression* arg1_len = at->get_length(gogo, arg1); + + Expression* call; Type* arg2_type = arg2->type(); go_assert(arg2->is_variable()); - Expression* arg2_val; - Expression* arg2_len; - if (arg2_type->is_slice_type()) - { - at = arg2_type->array_type(); - arg2_val = at->get_value_pointer(gogo, arg2); - arg2_len = at->get_length(gogo, arg2); - } + if (arg2_type->is_string_type()) + call = Runtime::make_call(Runtime::SLICESTRINGCOPY, location, + 2, arg1, arg2); else { - go_assert(arg2->is_variable()); - arg2_val = Expression::make_string_info(arg2, STRING_INFO_DATA, - location); - arg2_len = Expression::make_string_info(arg2, STRING_INFO_LENGTH, - location); + Type* et = at->element_type(); + if (et->has_pointer()) + { + Expression* td = Expression::make_type_descriptor(et, + location); + call = Runtime::make_call(Runtime::TYPEDSLICECOPY, location, + 3, td, arg1, arg2); + } + else + { + Expression* sz = Expression::make_type_info(et, + TYPE_INFO_SIZE); + call = Runtime::make_call(Runtime::SLICECOPY, location, 3, + arg1, arg2, sz); + } } - Expression* cond = - Expression::make_binary(OPERATOR_LT, arg1_len, arg2_len, location); - Expression* length = - Expression::make_conditional(cond, arg1_len, arg2_len, location); - - Type* element_type = at->element_type(); - int64_t element_size; - bool ok = element_type->backend_type_size(gogo, &element_size); - if (!ok) - { - go_assert(saw_errors()); - return gogo->backend()->error_expression(); - } - Expression* size_expr = Expression::make_integer_int64(element_size, - length->type(), - location); - Expression* bytecount = - Expression::make_binary(OPERATOR_MULT, size_expr, length, location); - Expression* copy = Runtime::make_call(Runtime::COPY, location, 3, - arg1_val, arg2_val, bytecount); - - Expression* compound = Expression::make_compound(copy, length, location); - return compound->get_backend(context); + return call->get_backend(context); } case BUILTIN_APPEND: - { - const Expression_list* args = this->args(); - go_assert(args != NULL && args->size() == 2); - Expression* arg1 = args->front(); - Expression* arg2 = args->back(); - - Array_type* at = arg1->type()->array_type(); - Type* element_type = at->element_type()->forwarded(); - - go_assert(arg2->is_variable()); - Expression* arg2_val; - Expression* arg2_len; - int64_t size; - if (arg2->type()->is_string_type() - && element_type->integer_type() != NULL - && element_type->integer_type()->is_byte()) - { - arg2_val = Expression::make_string_info(arg2, STRING_INFO_DATA, - location); - arg2_len = Expression::make_string_info(arg2, STRING_INFO_LENGTH, - location); - size = 1; - } - else - { - arg2_val = at->get_value_pointer(gogo, arg2); - arg2_len = at->get_length(gogo, arg2); - bool ok = element_type->backend_type_size(gogo, &size); - if (!ok) - { - go_assert(saw_errors()); - return gogo->backend()->error_expression(); - } - } - Expression* element_size = - Expression::make_integer_int64(size, NULL, location); - - Expression* append = Runtime::make_call(Runtime::APPEND, location, 4, - arg1, arg2_val, arg2_len, - element_size); - append = Expression::make_unsafe_cast(arg1->type(), append, location); - return append->get_backend(context); - } + // Handled in Builtin_call_expression::flatten_append. + go_unreachable(); case BUILTIN_REAL: case BUILTIN_IMAG: @@ -8501,7 +9205,7 @@ Builtin_call_expression::do_export(Export* exp) const Numeric_constant nc; if (!this->numeric_constant_value(&nc)) { - error_at(this->location(), "value is not constant"); + go_error_at(this->location(), "value is not constant"); return; } @@ -8677,8 +9381,8 @@ Call_expression::do_lower(Gogo* gogo, Named_object* function, // the ellipsis operator should be applied to. If we unpack the // the call into its individual results here, the ellipsis will be // applied to the last result. - error_at(call->location(), - _("multiple-value argument in single-value context")); + go_error_at(call->location(), + _("multiple-value argument in single-value context")); return Expression::make_error(call->location()); } @@ -8727,7 +9431,7 @@ Call_expression::do_lower(Gogo* gogo, Named_object* function, go_assert(parameters != NULL && !parameters->empty()); Type* varargs_type = parameters->back().type(); this->lower_varargs(gogo, function, inserter, varargs_type, - parameters->size()); + parameters->size(), SLICE_STORAGE_MAY_ESCAPE); } // If this is call to a method, call the method directly passing the @@ -8780,6 +9484,45 @@ Call_expression::do_lower(Gogo* gogo, Named_object* function, bme->location()); } + // Handle a couple of special runtime functions. In the runtime + // package, getcallerpc returns the PC of the caller, and + // getcallersp returns the frame pointer of the caller. Implement + // these by turning them into calls to GCC builtin functions. We + // could implement them in normal code, but then we would have to + // explicitly unwind the stack. These functions are intended to be + // efficient. Note that this technique obviously only works for + // direct calls, but that is the only way they are used. The actual + // argument to these functions is always the address of a parameter; + // we don't need that for the GCC builtin functions, so we just + // ignore it. + if (gogo->compiling_runtime() + && this->args_ != NULL + && this->args_->size() == 1 + && gogo->package_name() == "runtime") + { + Func_expression* fe = this->fn_->func_expression(); + if (fe != NULL + && fe->named_object()->is_function_declaration() + && fe->named_object()->package() == NULL) + { + std::string n = Gogo::unpack_hidden_name(fe->named_object()->name()); + if (n == "getcallerpc") + { + static Named_object* builtin_return_address; + return this->lower_to_builtin(&builtin_return_address, + "__builtin_return_address", + 0); + } + else if (n == "getcallersp") + { + static Named_object* builtin_frame_address; + return this->lower_to_builtin(&builtin_frame_address, + "__builtin_frame_address", + 1); + } + } + } + return this; } @@ -8793,7 +9536,8 @@ Call_expression::do_lower(Gogo* gogo, Named_object* function, void Call_expression::lower_varargs(Gogo* gogo, Named_object* function, Statement_inserter* inserter, - Type* varargs_type, size_t param_count) + Type* varargs_type, size_t param_count, + Slice_storage_escape_disp escape_disp) { if (this->varargs_are_lowered_) return; @@ -8842,8 +9586,8 @@ Call_expression::lower_varargs(Gogo* gogo, Named_object* function, this->report_error(_("too many arguments")); else { - error_at(this->location(), - _("invalid use of %<...%> with non-slice")); + go_error_at(this->location(), + _("invalid use of %<...%> with non-slice")); this->set_is_error(); } return; @@ -8862,8 +9606,11 @@ Call_expression::lower_varargs(Gogo* gogo, Named_object* function, continue; vals->push_back(*pa); } - Expression* val = + Slice_construction_expression* sce = Expression::make_slice_composite_literal(varargs_type, vals, loc); + if (escape_disp == SLICE_STORAGE_DOES_NOT_ESCAPE) + sce->set_storage_does_not_escape(); + Expression* val = sce; gogo->lower_expression(function, inserter, &val); new_args->push_back(val); } @@ -8880,6 +9627,28 @@ Call_expression::lower_varargs(Gogo* gogo, Named_object* function, this->varargs_are_lowered_ = true; } +// Return a call to __builtin_return_address or __builtin_frame_address. + +Expression* +Call_expression::lower_to_builtin(Named_object** pno, const char* name, + int arg) +{ + if (*pno == NULL) + *pno = Gogo::declare_builtin_rf_address(name); + + Location loc = this->location(); + + Expression* fn = Expression::make_func_reference(*pno, NULL, loc); + Expression* a = Expression::make_integer_ul(arg, NULL, loc); + Expression_list *args = new Expression_list(); + args->push_back(a); + Expression* call = Expression::make_call(fn, args, false, loc); + + // The builtin functions return void*, but the Go functions return uintptr. + Type* uintptr_type = Type::lookup_integer_type("uintptr"); + return Expression::make_cast(uintptr_type, call, loc); +} + // Flatten a call with multiple results into a temporary. Expression* @@ -8953,7 +9722,7 @@ Call_expression::do_flatten(Gogo* gogo, Named_object*, Location loc = this->location(); int i = 0; - char buf[10]; + char buf[20]; for (Typed_identifier_list::const_iterator p = results->begin(); p != results->end(); ++p, ++i) @@ -8963,6 +9732,7 @@ Call_expression::do_flatten(Gogo* gogo, Named_object*, } Struct_type* st = Type::make_struct_type(sfl, loc); + st->set_is_struct_incomparable(); this->call_temp_ = Statement::make_temporary(st, NULL, loc); inserter->insert(this->call_temp_); } @@ -9187,11 +9957,11 @@ Call_expression::check_argument_type(int i, const Type* parameter_type, if (!issued_error) { if (reason.empty()) - error_at(argument_location, "argument %d has incompatible type", i); + go_error_at(argument_location, "argument %d has incompatible type", i); else - error_at(argument_location, - "argument %d has incompatible type (%s)", - i, reason.c_str()); + go_error_at(argument_location, + "argument %d has incompatible type (%s)", + i, reason.c_str()); } this->set_is_error(); return false; @@ -9240,9 +10010,9 @@ Call_expression::do_check_types(Gogo*) this->report_error(_("incompatible type for receiver")); else { - error_at(this->location(), - "incompatible type for receiver (%s)", - reason.c_str()); + go_error_at(this->location(), + "incompatible type for receiver (%s)", + reason.c_str()); this->set_is_error(); } } @@ -9254,8 +10024,8 @@ Call_expression::do_check_types(Gogo*) { if (!fntype->is_varargs()) { - error_at(this->location(), - _("invalid use of %<...%> calling non-variadic function")); + go_error_at(this->location(), + _("invalid use of %<...%> calling non-variadic function")); this->set_is_error(); return; } @@ -9484,8 +10254,10 @@ Call_expression::do_get_backend(Translate_context* context) Expression* call_ref = Expression::make_temporary_reference(this->call_temp_, location); Bexpression* bcall_ref = call_ref->get_backend(context); + Bfunction* bfunction = context->function()->func_value()->get_decl(); Bstatement* assn_stmt = - gogo->backend()->assignment_statement(bcall_ref, call, location); + gogo->backend()->assignment_statement(bfunction, + bcall_ref, call, location); this->call_ = this->set_results(context, bcall_ref); @@ -9522,11 +10294,13 @@ Call_expression::set_results(Translate_context* context, Bexpression* call) Expression::make_temporary_reference(temp, loc); ref->set_is_lvalue(); + Bfunction* bfunction = context->function()->func_value()->get_decl(); Bexpression* result_ref = ref->get_backend(context); Bexpression* call_result = gogo->backend()->struct_field_expression(call, i, loc); Bstatement* assn_stmt = - gogo->backend()->assignment_statement(result_ref, call_result, loc); + gogo->backend()->assignment_statement(bfunction, + result_ref, call_result, loc); Bexpression* result = gogo->backend()->compound_expression(assn_stmt, call_result, loc); @@ -9535,7 +10309,8 @@ Call_expression::set_results(Translate_context* context, Bexpression* call) results = result; else { - Bstatement* expr_stmt = gogo->backend()->expression_statement(result); + Bstatement* expr_stmt = + gogo->backend()->expression_statement(bfunction, result); results = gogo->backend()->compound_expression(expr_stmt, results, loc); } @@ -9732,7 +10507,7 @@ Index_expression::do_lower(Gogo*, Named_object*, Statement_inserter*, int) } else if (left->is_type_expression()) { - error_at(location, "attempt to index type expression"); + go_error_at(location, "attempt to index type expression"); return Expression::make_error(location); } else if (type->array_type() != NULL) @@ -9757,7 +10532,7 @@ Index_expression::do_lower(Gogo*, Named_object*, Statement_inserter*, int) { if (cap != NULL) { - error_at(location, "invalid 3-index slice of string"); + go_error_at(location, "invalid 3-index slice of string"); return Expression::make_error(location); } return Expression::make_string_index(left, start, end, location); @@ -9766,19 +10541,15 @@ Index_expression::do_lower(Gogo*, Named_object*, Statement_inserter*, int) { if (end != NULL || cap != NULL) { - error_at(location, "invalid slice of map"); + go_error_at(location, "invalid slice of map"); return Expression::make_error(location); } - Map_index_expression* ret = Expression::make_map_index(left, start, - location); - if (this->is_lvalue_) - ret->set_is_lvalue(); - return ret; + return Expression::make_map_index(left, start, location); } else { - error_at(location, - "attempt to index object which is not array, string, or map"); + go_error_at(location, + "attempt to index object which is not array, string, or map"); return Expression::make_error(location); } } @@ -9910,7 +10681,7 @@ Array_index_expression::do_determine_type(const Type_context*) // Check types of an array index. void -Array_index_expression::do_check_types(Gogo*) +Array_index_expression::do_check_types(Gogo* gogo) { Numeric_constant nc; unsigned long v; @@ -9964,7 +10735,7 @@ Array_index_expression::do_check_types(Gogo*) ? mpz_cmp(ival, lval) >= 0 : mpz_cmp(ival, lval) > 0))) { - error_at(this->start_->location(), "array index out of bounds"); + go_error_at(this->start_->location(), "array index out of bounds"); this->set_is_error(); } } @@ -9980,7 +10751,7 @@ Array_index_expression::do_check_types(Gogo*) || mpz_sizeinbase(eval, 2) >= int_bits || (lval_valid && mpz_cmp(eval, lval) > 0)) { - error_at(this->end_->location(), "array index out of bounds"); + go_error_at(this->end_->location(), "array index out of bounds"); this->set_is_error(); } else if (ival_valid && mpz_cmp(ival, eval) > 0) @@ -9996,19 +10767,19 @@ Array_index_expression::do_check_types(Gogo*) || mpz_sizeinbase(cval, 2) >= int_bits || (lval_valid && mpz_cmp(cval, lval) > 0)) { - error_at(this->cap_->location(), "array index out of bounds"); + go_error_at(this->cap_->location(), "array index out of bounds"); this->set_is_error(); } else if (ival_valid && mpz_cmp(ival, cval) > 0) { - error_at(this->cap_->location(), - "invalid slice index: capacity less than start"); + go_error_at(this->cap_->location(), + "invalid slice index: capacity less than start"); this->set_is_error(); } else if (eval_valid && mpz_cmp(eval, cval) > 0) { - error_at(this->cap_->location(), - "invalid slice index: capacity less than length"); + go_error_at(this->cap_->location(), + "invalid slice index: capacity less than length"); this->set_is_error(); } mpz_clear(cval); @@ -10029,7 +10800,18 @@ Array_index_expression::do_check_types(Gogo*) if (!this->array_->is_addressable()) this->report_error(_("slice of unaddressable value")); else - this->array_->address_taken(true); + { + bool escapes = true; + + // When compiling the runtime, a slice operation does not + // cause local variables to escape. When escape analysis + // becomes the default, this should be changed to make it an + // error if we have a slice operation that escapes. + if (gogo->compiling_runtime() && gogo->package_name() == "runtime") + escapes = false; + + this->array_->address_taken(escapes); + } } } @@ -10188,12 +10970,13 @@ Array_index_expression::do_get_backend(Translate_context* context) bad_index = gogo->backend()->binary_expression(OPERATOR_OROR, start_too_large, bad_index, loc); + Bfunction* bfn = context->function()->func_value()->get_decl(); if (this->end_ == NULL) { // Simple array indexing. This has to return an l-value, so // wrap the index check into START. start = - gogo->backend()->conditional_expression(int_btype, bad_index, + gogo->backend()->conditional_expression(bfn, int_btype, bad_index, crash, start, loc); Bexpression* ret; @@ -10282,7 +11065,7 @@ Array_index_expression::do_get_backend(Translate_context* context) Bexpression* ctor = gogo->backend()->constructor_expression(struct_btype, init, loc); - return gogo->backend()->conditional_expression(struct_btype, bad_index, + return gogo->backend()->conditional_expression(bfn, struct_btype, bad_index, crash, ctor, loc); } @@ -10306,66 +11089,7 @@ Expression::make_array_index(Expression* array, Expression* start, return new Array_index_expression(array, start, end, cap, location); } -// A string index. This is used for both indexing and slicing. - -class String_index_expression : public Expression -{ - public: - String_index_expression(Expression* string, Expression* start, - Expression* end, Location location) - : Expression(EXPRESSION_STRING_INDEX, location), - string_(string), start_(start), end_(end) - { } - - protected: - int - do_traverse(Traverse*); - - Expression* - do_flatten(Gogo*, Named_object*, Statement_inserter*); - - Type* - do_type(); - - void - do_determine_type(const Type_context*); - - void - do_check_types(Gogo*); - - Expression* - do_copy() - { - return Expression::make_string_index(this->string_->copy(), - this->start_->copy(), - (this->end_ == NULL - ? NULL - : this->end_->copy()), - this->location()); - } - - bool - do_must_eval_subexpressions_in_order(int* skip) const - { - *skip = 1; - return true; - } - - Bexpression* - do_get_backend(Translate_context*); - - void - do_dump_expression(Ast_dump_context*) const; - - private: - // The string we are getting a value from. - Expression* string_; - // The start or only index. - Expression* start_; - // The end index of a slice. This may be NULL for a single index, - // or it may be a nil expression for the length of the string. - Expression* end_; -}; +// Class String_index_expression. // String index traversal. @@ -10496,7 +11220,7 @@ String_index_expression::do_check_types(Gogo*) ? mpz_cmp_ui(ival, sval.length()) >= 0 : mpz_cmp_ui(ival, sval.length()) > 0))) { - error_at(this->start_->location(), "string index out of bounds"); + go_error_at(this->start_->location(), "string index out of bounds"); this->set_is_error(); } } @@ -10509,7 +11233,7 @@ String_index_expression::do_check_types(Gogo*) if (mpz_sgn(eval) < 0 || (sval_valid && mpz_cmp_ui(eval, sval.length()) > 0)) { - error_at(this->end_->location(), "string index out of bounds"); + go_error_at(this->end_->location(), "string index out of bounds"); this->set_is_error(); } else if (ival_valid && mpz_cmp(ival, eval) > 0) @@ -10555,6 +11279,7 @@ String_index_expression::do_get_backend(Translate_context* context) } Expression* start = Expression::make_cast(int_type, this->start_, loc); + Bfunction* bfn = context->function()->func_value()->get_decl(); if (this->end_ == NULL) { @@ -10577,8 +11302,9 @@ String_index_expression::do_get_backend(Translate_context* context) Btype* byte_btype = bytes->type()->points_to()->get_backend(gogo); Bexpression* index_error = bad_index->get_backend(context); - return gogo->backend()->conditional_expression(byte_btype, index_error, - crash, index, loc); + return gogo->backend()->conditional_expression(bfn, byte_btype, + index_error, crash, + index, loc); } Expression* end = NULL; @@ -10598,7 +11324,7 @@ String_index_expression::do_get_backend(Translate_context* context) Btype* str_btype = strslice->type()->get_backend(gogo); Bexpression* index_error = bad_index->get_backend(context); - return gogo->backend()->conditional_expression(str_btype, index_error, + return gogo->backend()->conditional_expression(bfn, str_btype, index_error, crash, bstrslice, loc); } @@ -10628,7 +11354,7 @@ Expression::make_string_index(Expression* string, Expression* start, Map_type* Map_index_expression::get_map_type() const { - Map_type* mt = this->map_->type()->deref()->map_type(); + Map_type* mt = this->map_->type()->map_type(); if (mt == NULL) go_assert(saw_errors()); return mt; @@ -10686,7 +11412,7 @@ Map_index_expression::do_flatten(Gogo* gogo, Named_object*, } if (this->value_pointer_ == NULL) - this->get_value_pointer(this->is_lvalue_); + this->get_value_pointer(gogo); if (this->value_pointer_->is_error_expression() || this->value_pointer_->type()->is_error_type()) return Expression::make_error(loc); @@ -10709,14 +11435,7 @@ Map_index_expression::do_type() Map_type* mt = this->get_map_type(); if (mt == NULL) return Type::make_error_type(); - Type* type = mt->val_type(); - // If this map index is in a tuple assignment, we actually return a - // pointer to the value type. Tuple_map_assignment_statement is - // responsible for handling this correctly. We need to get the type - // right in case this gets assigned to a temporary variable. - if (this->is_in_tuple_assignment_) - type = Type::make_pointer_type(type); - return type; + return mt->val_type(); } // Fix the type of a map index. @@ -10746,8 +11465,8 @@ Map_index_expression::do_check_types(Gogo*) this->report_error(_("incompatible type for map index")); else { - error_at(this->location(), "incompatible type for map index (%s)", - reason.c_str()); + go_error_at(this->location(), "incompatible type for map index (%s)", + reason.c_str()); this->set_is_error(); } } @@ -10768,47 +11487,17 @@ Map_index_expression::do_get_backend(Translate_context* context) go_assert(this->value_pointer_ != NULL && this->value_pointer_->is_variable()); - Bexpression* ret; - if (this->is_lvalue_) - { - Expression* val = - Expression::make_unary(OPERATOR_MULT, this->value_pointer_, - this->location()); - ret = val->get_backend(context); - } - else if (this->is_in_tuple_assignment_) - { - // Tuple_map_assignment_statement is responsible for using this - // appropriately. - ret = this->value_pointer_->get_backend(context); - } - else - { - Location loc = this->location(); - - Expression* nil_check = - Expression::make_binary(OPERATOR_EQEQ, this->value_pointer_, - Expression::make_nil(loc), loc); - Bexpression* bnil_check = nil_check->get_backend(context); - Expression* val = - Expression::make_unary(OPERATOR_MULT, this->value_pointer_, loc); - Bexpression* bval = val->get_backend(context); - - Gogo* gogo = context->gogo(); - Btype* val_btype = type->val_type()->get_backend(gogo); - Bexpression* val_zero = gogo->backend()->zero_expression(val_btype); - ret = gogo->backend()->conditional_expression(val_btype, bnil_check, - val_zero, bval, loc); - } - return ret; + Expression* val = Expression::make_unary(OPERATOR_MULT, this->value_pointer_, + this->location()); + return val->get_backend(context); } -// Get an expression for the map index. This returns an expression which -// evaluates to a pointer to a value. The pointer will be NULL if the key is -// not in the map. +// Get an expression for the map index. This returns an expression +// that evaluates to a pointer to a value. If the key is not in the +// map, the pointer will point to a zero value. Expression* -Map_index_expression::get_value_pointer(bool insert) +Map_index_expression::get_value_pointer(Gogo* gogo) { if (this->value_pointer_ == NULL) { @@ -10821,21 +11510,32 @@ Map_index_expression::get_value_pointer(bool insert) Location loc = this->location(); Expression* map_ref = this->map_; - if (this->map_->type()->points_to() != NULL) - map_ref = Expression::make_unary(OPERATOR_MULT, map_ref, loc); - Expression* index_ptr = Expression::make_unary(OPERATOR_AND, this->index_, + Expression* index_ptr = Expression::make_unary(OPERATOR_AND, + this->index_, loc); - Expression* map_index = - Runtime::make_call(Runtime::MAP_INDEX, loc, 3, - map_ref, index_ptr, - Expression::make_boolean(insert, loc)); + + Expression* zero = type->fat_zero_value(gogo); + + Expression* map_index; + + if (zero == NULL) + map_index = + Runtime::make_call(Runtime::MAPACCESS1, loc, 3, + Expression::make_type_descriptor(type, loc), + map_ref, index_ptr); + else + map_index = + Runtime::make_call(Runtime::MAPACCESS1_FAT, loc, 4, + Expression::make_type_descriptor(type, loc), + map_ref, index_ptr, zero); Type* val_type = type->val_type(); this->value_pointer_ = Expression::make_unsafe_cast(Type::make_pointer_type(val_type), map_index, this->location()); } + return this->value_pointer_; } @@ -10918,7 +11618,8 @@ Field_reference_expression::do_lower(Gogo* gogo, Named_object* function, Expression* length_expr = Expression::make_integer_ul(s.length(), NULL, loc); Type* byte_type = gogo->lookup_global("byte")->type_value(); - Type* array_type = Type::make_array_type(byte_type, length_expr); + Array_type* array_type = Type::make_array_type(byte_type, length_expr); + array_type->set_is_array_incomparable(); Expression_list* bytes = new Expression_list(); for (std::string::const_iterator p = s.begin(); p != s.end(); p++) @@ -11137,8 +11838,8 @@ Interface_field_reference_expression::do_check_types(Gogo*) interface_type->find_method(this->name_); if (method == NULL) { - error_at(this->location(), "method %qs not in interface", - Gogo::message_name(this->name_).c_str()); + go_error_at(this->location(), "method %qs not in interface", + Gogo::message_name(this->name_).c_str()); this->set_is_error(); } } @@ -11196,8 +11897,9 @@ Interface_field_reference_expression::create_thunk(Gogo* gogo, Type* vt = Type::make_pointer_type(Type::make_void_type()); sfl->push_back(Struct_field(Typed_identifier("fn.0", vt, loc))); sfl->push_back(Struct_field(Typed_identifier("val.1", type, loc))); - Type* closure_type = Type::make_struct_type(sfl, loc); - closure_type = Type::make_pointer_type(closure_type); + Struct_type* st = Type::make_struct_type(sfl, loc); + st->set_is_struct_incomparable(); + Type* closure_type = Type::make_pointer_type(st); Function_type* new_fntype = orig_fntype->copy_with_names(); @@ -11296,6 +11998,7 @@ Interface_field_reference_expression::do_get_backend(Translate_context* context) this->expr_->type(), loc))); Struct_type* st = Type::make_struct_type(fields, loc); + st->set_is_struct_incomparable(); Expression_list* vals = new Expression_list(); vals->push_back(Expression::make_func_code_reference(thunk, loc)); @@ -11314,9 +12017,13 @@ Interface_field_reference_expression::do_get_backend(Translate_context* context) Bexpression* bcrash = gogo->runtime_error(RUNTIME_ERROR_NIL_DEREFERENCE, loc)->get_backend(context); + Bfunction* bfn = context->function()->func_value()->get_decl(); Bexpression* bcond = - gogo->backend()->conditional_expression(NULL, bnil_check, bcrash, NULL, loc); - Bstatement* cond_statement = gogo->backend()->expression_statement(bcond); + gogo->backend()->conditional_expression(bfn, NULL, + bnil_check, bcrash, NULL, loc); + Bfunction* bfunction = context->function()->func_value()->get_decl(); + Bstatement* cond_statement = + gogo->backend()->expression_statement(bfunction, bcond); return gogo->backend()->compound_expression(cond_statement, bclosure, loc); } @@ -11401,7 +12108,8 @@ Expression* Selector_expression::lower_method_expression(Gogo* gogo) { Location location = this->location(); - Type* type = this->left_->type(); + Type* left_type = this->left_->type(); + Type* type = left_type; const std::string& name(this->name_); bool is_pointer; @@ -11415,9 +12123,9 @@ Selector_expression::lower_method_expression(Gogo* gogo) Named_type* nt = type->named_type(); if (nt == NULL) { - error_at(location, - ("method expression requires named type or " - "pointer to named type")); + go_error_at(location, + ("method expression requires named type or " + "pointer to named type")); return Expression::make_error(location); } @@ -11431,26 +12139,27 @@ Selector_expression::lower_method_expression(Gogo* gogo) imethod = it->find_method(name); } - if (method == NULL && imethod == NULL) + if ((method == NULL && imethod == NULL) + || (left_type->named_type() != NULL && left_type->points_to() != NULL)) { if (!is_ambiguous) - error_at(location, "type %<%s%s%> has no method %<%s%>", - is_pointer ? "*" : "", - nt->message_name().c_str(), - Gogo::message_name(name).c_str()); + go_error_at(location, "type %<%s%s%> has no method %<%s%>", + is_pointer ? "*" : "", + nt->message_name().c_str(), + Gogo::message_name(name).c_str()); else - error_at(location, "method %<%s%s%> is ambiguous in type %<%s%>", - Gogo::message_name(name).c_str(), - is_pointer ? "*" : "", - nt->message_name().c_str()); + go_error_at(location, "method %<%s%s%> is ambiguous in type %<%s%>", + Gogo::message_name(name).c_str(), + is_pointer ? "*" : "", + nt->message_name().c_str()); return Expression::make_error(location); } if (method != NULL && !is_pointer && !method->is_value_method()) { - error_at(location, "method requires pointer (use %<(*%s).%s)%>", - nt->message_name().c_str(), - Gogo::message_name(name).c_str()); + go_error_at(location, "method requires pointer (use %<(*%s).%s%>)", + nt->message_name().c_str(), + Gogo::message_name(name).c_str()); return Expression::make_error(location); } @@ -11643,7 +12352,9 @@ Allocation_expression::do_get_backend(Translate_context* context) Gogo* gogo = context->gogo(); Location loc = this->location(); - if (this->allocate_on_stack_) + Node* n = Node::make_node(this); + if (this->allocate_on_stack_ + || (n->encoding() & ESCAPE_MASK) == int(Node::ESCAPE_NONE)) { int64_t size; bool ok = this->type_->backend_type_size(gogo, &size); @@ -11681,12 +12392,10 @@ Expression::make_allocation(Type* type, Location location) return new Allocation_expression(type, location); } -// Class Struct_construction_expression. - -// Traversal. +// Class Ordered_value_list. int -Struct_construction_expression::do_traverse(Traverse* traverse) +Ordered_value_list::traverse_vals(Traverse* traverse) { if (this->vals_ != NULL) { @@ -11697,8 +12406,8 @@ Struct_construction_expression::do_traverse(Traverse* traverse) } else { - for (std::vector<int>::const_iterator p = - this->traverse_order_->begin(); + for (std::vector<unsigned long>::const_iterator p = + this->traverse_order_->begin(); p != this->traverse_order_->end(); ++p) { @@ -11708,6 +12417,18 @@ Struct_construction_expression::do_traverse(Traverse* traverse) } } } + return TRAVERSE_CONTINUE; +} + +// Class Struct_construction_expression. + +// Traversal. + +int +Struct_construction_expression::do_traverse(Traverse* traverse) +{ + if (this->traverse_vals(traverse) == TRAVERSE_EXIT) + return TRAVERSE_EXIT; if (Type::traverse(this->type_, traverse) == TRAVERSE_EXIT) return TRAVERSE_EXIT; return TRAVERSE_CONTINUE; @@ -11718,10 +12439,10 @@ Struct_construction_expression::do_traverse(Traverse* traverse) bool Struct_construction_expression::is_constant_struct() const { - if (this->vals_ == NULL) + if (this->vals() == NULL) return true; - for (Expression_list::const_iterator pv = this->vals_->begin(); - pv != this->vals_->end(); + for (Expression_list::const_iterator pv = this->vals()->begin(); + pv != this->vals()->end(); ++pv) { if (*pv != NULL @@ -11744,20 +12465,31 @@ Struct_construction_expression::is_constant_struct() const return true; } -// Return whether this struct is immutable. +// Return whether this struct can be used as a constant initializer. bool -Struct_construction_expression::do_is_immutable() const +Struct_construction_expression::do_is_static_initializer() const { - if (this->vals_ == NULL) + if (this->vals() == NULL) return true; - for (Expression_list::const_iterator pv = this->vals_->begin(); - pv != this->vals_->end(); + for (Expression_list::const_iterator pv = this->vals()->begin(); + pv != this->vals()->end(); ++pv) { - if (*pv != NULL && !(*pv)->is_immutable()) + if (*pv != NULL && !(*pv)->is_static_initializer()) + return false; + } + + const Struct_field_list* fields = this->type_->struct_type()->fields(); + for (Struct_field_list::const_iterator pf = fields->begin(); + pf != fields->end(); + ++pf) + { + // There are no constant constructors for interfaces. + if (pf->type()->interface_type() != NULL) return false; } + return true; } @@ -11766,15 +12498,15 @@ Struct_construction_expression::do_is_immutable() const void Struct_construction_expression::do_determine_type(const Type_context*) { - if (this->vals_ == NULL) + if (this->vals() == NULL) return; const Struct_field_list* fields = this->type_->struct_type()->fields(); - Expression_list::const_iterator pv = this->vals_->begin(); + Expression_list::const_iterator pv = this->vals()->begin(); for (Struct_field_list::const_iterator pf = fields->begin(); pf != fields->end(); ++pf, ++pv) { - if (pv == this->vals_->end()) + if (pv == this->vals()->end()) return; if (*pv != NULL) { @@ -11784,7 +12516,7 @@ Struct_construction_expression::do_determine_type(const Type_context*) } // Extra values are an error we will report elsewhere; we still want // to determine the type to avoid knockon errors. - for (; pv != this->vals_->end(); ++pv) + for (; pv != this->vals()->end(); ++pv) (*pv)->determine_type_no_context(); } @@ -11793,24 +12525,24 @@ Struct_construction_expression::do_determine_type(const Type_context*) void Struct_construction_expression::do_check_types(Gogo*) { - if (this->vals_ == NULL) + if (this->vals() == NULL) return; Struct_type* st = this->type_->struct_type(); - if (this->vals_->size() > st->field_count()) + if (this->vals()->size() > st->field_count()) { this->report_error(_("too many expressions for struct")); return; } const Struct_field_list* fields = st->fields(); - Expression_list::const_iterator pv = this->vals_->begin(); + Expression_list::const_iterator pv = this->vals()->begin(); int i = 0; for (Struct_field_list::const_iterator pf = fields->begin(); pf != fields->end(); ++pf, ++pv, ++i) { - if (pv == this->vals_->end()) + if (pv == this->vals()->end()) { this->report_error(_("too few expressions for struct")); break; @@ -11823,18 +12555,18 @@ Struct_construction_expression::do_check_types(Gogo*) if (!Type::are_assignable(pf->type(), (*pv)->type(), &reason)) { if (reason.empty()) - error_at((*pv)->location(), - "incompatible type for field %d in struct construction", - i + 1); + go_error_at((*pv)->location(), + "incompatible type for field %d in struct construction", + i + 1); else - error_at((*pv)->location(), - ("incompatible type for field %d in " - "struct construction (%s)"), - i + 1, reason.c_str()); + go_error_at((*pv)->location(), + ("incompatible type for field %d in " + "struct construction (%s)"), + i + 1, reason.c_str()); this->set_is_error(); } } - go_assert(pv == this->vals_->end()); + go_assert(pv == this->vals()->end()); } // Flatten a struct construction expression. Store the values into @@ -11844,16 +12576,16 @@ Expression* Struct_construction_expression::do_flatten(Gogo*, Named_object*, Statement_inserter* inserter) { - if (this->vals_ == NULL) + if (this->vals() == NULL) return this; // If this is a constant struct, we don't need temporaries. - if (this->is_constant_struct()) + if (this->is_constant_struct() || this->is_static_initializer()) return this; Location loc = this->location(); - for (Expression_list::iterator pv = this->vals_->begin(); - pv != this->vals_->end(); + for (Expression_list::iterator pv = this->vals()->begin(); + pv != this->vals()->end(); ++pv) { if (*pv != NULL) @@ -11883,18 +12615,18 @@ Struct_construction_expression::do_get_backend(Translate_context* context) Gogo* gogo = context->gogo(); Btype* btype = this->type_->get_backend(gogo); - if (this->vals_ == NULL) + if (this->vals() == NULL) return gogo->backend()->zero_expression(btype); const Struct_field_list* fields = this->type_->struct_type()->fields(); - Expression_list::const_iterator pv = this->vals_->begin(); + Expression_list::const_iterator pv = this->vals()->begin(); std::vector<Bexpression*> init; for (Struct_field_list::const_iterator pf = fields->begin(); pf != fields->end(); ++pf) { Btype* fbtype = pf->type()->get_backend(gogo); - if (pv == this->vals_->end()) + if (pv == this->vals()->end()) init.push_back(gogo->backend()->zero_expression(fbtype)); else if (*pv == NULL) { @@ -11920,8 +12652,8 @@ Struct_construction_expression::do_export(Export* exp) const { exp->write_c_string("convert("); exp->write_type(this->type_); - for (Expression_list::const_iterator pv = this->vals_->begin(); - pv != this->vals_->end(); + for (Expression_list::const_iterator pv = this->vals()->begin(); + pv != this->vals()->end(); ++pv) { exp->write_c_string(", "); @@ -11939,7 +12671,7 @@ Struct_construction_expression::do_dump_expression( { ast_dump_context->dump_type(this->type_); ast_dump_context->ostream() << "{"; - ast_dump_context->dump_expression_list(this->vals_); + ast_dump_context->dump_expression_list(this->vals()); ast_dump_context->ostream() << "}"; } @@ -11960,8 +12692,7 @@ Expression::make_struct_composite_literal(Type* type, Expression_list* vals, int Array_construction_expression::do_traverse(Traverse* traverse) { - if (this->vals_ != NULL - && this->vals_->traverse(traverse) == TRAVERSE_EXIT) + if (this->traverse_vals(traverse) == TRAVERSE_EXIT) return TRAVERSE_EXIT; if (Type::traverse(this->type_, traverse) == TRAVERSE_EXIT) return TRAVERSE_EXIT; @@ -11973,15 +12704,15 @@ Array_construction_expression::do_traverse(Traverse* traverse) bool Array_construction_expression::is_constant_array() const { - if (this->vals_ == NULL) + if (this->vals() == NULL) return true; // There are no constant constructors for interfaces. if (this->type_->array_type()->element_type()->interface_type() != NULL) return false; - for (Expression_list::const_iterator pv = this->vals_->begin(); - pv != this->vals_->end(); + for (Expression_list::const_iterator pv = this->vals()->begin(); + pv != this->vals()->end(); ++pv) { if (*pv != NULL @@ -11993,18 +12724,23 @@ Array_construction_expression::is_constant_array() const return true; } -// Return whether this is an immutable array initializer. +// Return whether this can be used a constant initializer. bool -Array_construction_expression::do_is_immutable() const +Array_construction_expression::do_is_static_initializer() const { - if (this->vals_ == NULL) + if (this->vals() == NULL) return true; - for (Expression_list::const_iterator pv = this->vals_->begin(); - pv != this->vals_->end(); + + // There are no constant constructors for interfaces. + if (this->type_->array_type()->element_type()->interface_type() != NULL) + return false; + + for (Expression_list::const_iterator pv = this->vals()->begin(); + pv != this->vals()->end(); ++pv) { - if (*pv != NULL && !(*pv)->is_immutable()) + if (*pv != NULL && !(*pv)->is_static_initializer()) return false; } return true; @@ -12015,11 +12751,11 @@ Array_construction_expression::do_is_immutable() const void Array_construction_expression::do_determine_type(const Type_context*) { - if (this->vals_ == NULL) + if (this->vals() == NULL) return; Type_context subcontext(this->type_->array_type()->element_type(), false); - for (Expression_list::const_iterator pv = this->vals_->begin(); - pv != this->vals_->end(); + for (Expression_list::const_iterator pv = this->vals()->begin(); + pv != this->vals()->end(); ++pv) { if (*pv != NULL) @@ -12032,22 +12768,22 @@ Array_construction_expression::do_determine_type(const Type_context*) void Array_construction_expression::do_check_types(Gogo*) { - if (this->vals_ == NULL) + if (this->vals() == NULL) return; Array_type* at = this->type_->array_type(); int i = 0; Type* element_type = at->element_type(); - for (Expression_list::const_iterator pv = this->vals_->begin(); - pv != this->vals_->end(); + for (Expression_list::const_iterator pv = this->vals()->begin(); + pv != this->vals()->end(); ++pv, ++i) { if (*pv != NULL && !Type::are_assignable(element_type, (*pv)->type(), NULL)) { - error_at((*pv)->location(), - "incompatible type for element %d in composite literal", - i + 1); + go_error_at((*pv)->location(), + "incompatible type for element %d in composite literal", + i + 1); this->set_is_error(); } } @@ -12060,16 +12796,16 @@ Expression* Array_construction_expression::do_flatten(Gogo*, Named_object*, Statement_inserter* inserter) { - if (this->vals_ == NULL) + if (this->vals() == NULL) return this; // If this is a constant array, we don't need temporaries. - if (this->is_constant_array()) + if (this->is_constant_array() || this->is_static_initializer()) return this; Location loc = this->location(); - for (Expression_list::iterator pv = this->vals_->begin(); - pv != this->vals_->end(); + for (Expression_list::iterator pv = this->vals()->begin(); + pv != this->vals()->end(); ++pv) { if (*pv != NULL) @@ -12102,14 +12838,14 @@ Array_construction_expression::get_constructor(Translate_context* context, std::vector<unsigned long> indexes; std::vector<Bexpression*> vals; Gogo* gogo = context->gogo(); - if (this->vals_ != NULL) + if (this->vals() != NULL) { size_t i = 0; std::vector<unsigned long>::const_iterator pi; if (this->indexes_ != NULL) pi = this->indexes_->begin(); - for (Expression_list::const_iterator pv = this->vals_->begin(); - pv != this->vals_->end(); + for (Expression_list::const_iterator pv = this->vals()->begin(); + pv != this->vals()->end(); ++pv, ++i) { if (this->indexes_ != NULL) @@ -12149,13 +12885,13 @@ Array_construction_expression::do_export(Export* exp) const { exp->write_c_string("convert("); exp->write_type(this->type_); - if (this->vals_ != NULL) + if (this->vals() != NULL) { std::vector<unsigned long>::const_iterator pi; if (this->indexes_ != NULL) pi = this->indexes_->begin(); - for (Expression_list::const_iterator pv = this->vals_->begin(); - pv != this->vals_->end(); + for (Expression_list::const_iterator pv = this->vals()->begin(); + pv != this->vals()->end(); ++pv) { exp->write_c_string(", "); @@ -12178,7 +12914,7 @@ Array_construction_expression::do_export(Export* exp) const exp->write_c_string(")"); } -// Dump ast representation of an array construction expressin. +// Dump ast representation of an array construction expression. void Array_construction_expression::do_dump_expression( @@ -12193,12 +12929,13 @@ Array_construction_expression::do_dump_expression( } ast_dump_context->ostream() << "]" ; ast_dump_context->dump_type(this->type_); + this->dump_slice_storage_expression(ast_dump_context); ast_dump_context->ostream() << "{" ; if (this->indexes_ == NULL) - ast_dump_context->dump_expression_list(this->vals_); + ast_dump_context->dump_expression_list(this->vals()); else { - Expression_list::const_iterator pv = this->vals_->begin(); + Expression_list::const_iterator pv = this->vals()->begin(); for (std::vector<unsigned long>::const_iterator pi = this->indexes_->begin(); pi != this->indexes_->end(); @@ -12248,7 +12985,8 @@ Slice_construction_expression::Slice_construction_expression( Expression_list* vals, Location location) : Array_construction_expression(EXPRESSION_SLICE_CONSTRUCTION, type, indexes, vals, location), - valtype_(NULL) + valtype_(NULL), array_val_(NULL), slice_storage_(NULL), + storage_escapes_(true) { go_assert(type->is_slice_type()); @@ -12266,10 +13004,11 @@ Slice_construction_expression::Slice_construction_expression( Type* int_type = Type::lookup_integer_type("int"); length = Expression::make_integer_ul(lenval, int_type, location); Type* element_type = type->array_type()->element_type(); - this->valtype_ = Type::make_array_type(element_type, length); + Array_type* array_type = Type::make_array_type(element_type, length); + array_type->set_is_array_incomparable(); + this->valtype_ = array_type; } - // Traversal. int @@ -12280,59 +13019,125 @@ Slice_construction_expression::do_traverse(Traverse* traverse) return TRAVERSE_EXIT; if (Type::traverse(this->valtype_, traverse) == TRAVERSE_EXIT) return TRAVERSE_EXIT; + if (this->array_val_ != NULL + && Expression::traverse(&this->array_val_, traverse) == TRAVERSE_EXIT) + return TRAVERSE_EXIT; + if (this->slice_storage_ != NULL + && Expression::traverse(&this->slice_storage_, traverse) == TRAVERSE_EXIT) + return TRAVERSE_EXIT; return TRAVERSE_CONTINUE; } -// Return the backend representation for constructing a slice. +// Helper routine to create fixed array value underlying the slice literal. +// May be called during flattening, or later during do_get_backend(). -Bexpression* -Slice_construction_expression::do_get_backend(Translate_context* context) +Expression* +Slice_construction_expression::create_array_val() { Array_type* array_type = this->type()->array_type(); if (array_type == NULL) { go_assert(this->type()->is_error()); - return context->backend()->error_expression(); + return NULL; } Location loc = this->location(); - Type* element_type = array_type->element_type(); go_assert(this->valtype_ != NULL); Expression_list* vals = this->vals(); - if (this->vals() == NULL || this->vals()->empty()) + return new Fixed_array_construction_expression( + this->valtype_, this->indexes(), vals, loc); +} + +// If we're previous established that the slice storage does not +// escape, then create a separate array temp val here for it. We +// need to do this as part of flattening so as to be able to insert +// the new temp statement. + +Expression* +Slice_construction_expression::do_flatten(Gogo* gogo, Named_object* no, + Statement_inserter* inserter) +{ + if (this->type()->array_type() == NULL) + return NULL; + + // Base class flattening first + this->Array_construction_expression::do_flatten(gogo, no, inserter); + + // Create a stack-allocated storage temp if storage won't escape + if (!this->storage_escapes_ && this->slice_storage_ == NULL) + { + Location loc = this->location(); + this->array_val_ = create_array_val(); + go_assert(this->array_val_); + Temporary_statement* temp = + Statement::make_temporary(this->valtype_, this->array_val_, loc); + inserter->insert(temp); + this->slice_storage_ = Expression::make_temporary_reference(temp, loc); + } + return this; +} + +// When dumping a slice construction expression that has an explicit +// storeage temp, emit the temp here (if we don't do this the storage +// temp appears unused in the AST dump). + +void +Slice_construction_expression:: +dump_slice_storage_expression(Ast_dump_context* ast_dump_context) const +{ + if (this->slice_storage_ == NULL) + return; + ast_dump_context->ostream() << "storage=" ; + ast_dump_context->dump_expression(this->slice_storage_); +} + +// Return the backend representation for constructing a slice. + +Bexpression* +Slice_construction_expression::do_get_backend(Translate_context* context) +{ + if (this->array_val_ == NULL) + this->array_val_ = create_array_val(); + if (this->array_val_ == NULL) { - // We need to create a unique value for the empty array literal. - vals = new Expression_list; - vals->push_back(NULL); + go_assert(this->type()->is_error()); + return context->backend()->error_expression(); } - Expression* array_val = - new Fixed_array_construction_expression(this->valtype_, this->indexes(), - vals, loc); - bool is_constant_initializer = array_val->is_immutable(); + Location loc = this->location(); + + bool is_static_initializer = this->array_val_->is_static_initializer(); // 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 - // copy them if they may contain pointers in a non-constant context, - // as otherwise the garbage collector won't see them. - bool copy_to_heap = (context->function() != NULL - || !is_constant_initializer - || (element_type->has_pointer() - && !context->is_const())); + // a function or if the values are not constants. + bool copy_to_heap = context->function() != NULL || !is_static_initializer; Expression* space; - if (!copy_to_heap) + + if (this->slice_storage_ != NULL) + { + go_assert(!this->storage_escapes_); + space = Expression::make_unary(OPERATOR_AND, this->slice_storage_, loc); + } + else if (!copy_to_heap) { // The initializer will only run once. - space = Expression::make_unary(OPERATOR_AND, array_val, loc); + space = Expression::make_unary(OPERATOR_AND, this->array_val_, loc); space->unary_expression()->set_is_slice_init(); } else - space = Expression::make_heap_expression(array_val, loc); + { + space = Expression::make_heap_expression(this->array_val_, loc); + Node* n = Node::make_node(this); + if ((n->encoding() & ESCAPE_MASK) == int(Node::ESCAPE_NONE)) + { + n = Node::make_node(space); + n->set_encoding(Node::ESCAPE_NONE); + } + } // Build a constructor for the slice. - Expression* len = this->valtype_->array_type()->length(); Expression* slice_val = Expression::make_slice_value(this->type(), space, len, len, loc); @@ -12342,7 +13147,7 @@ Slice_construction_expression::do_get_backend(Translate_context* context) // Make a slice composite literal. This is used by the type // descriptor code. -Expression* +Slice_construction_expression* Expression::make_slice_composite_literal(Type* type, Expression_list* vals, Location location) { @@ -12432,8 +13237,9 @@ Map_construction_expression::do_flatten(Gogo* gogo, Named_object*, } Expression* element_count = Expression::make_integer_ul(i, NULL, loc); - Type* ctor_type = + Array_type* ctor_type = Type::make_array_type(this->element_type_, element_count); + ctor_type->set_is_array_incomparable(); Expression* constructor = new Fixed_array_construction_expression(ctor_type, NULL, value_pairs, loc); @@ -12487,17 +13293,17 @@ Map_construction_expression::do_check_types(Gogo*) { if (!Type::are_assignable(key_type, (*pv)->type(), NULL)) { - error_at((*pv)->location(), - "incompatible type for element %d key in map construction", - i + 1); + go_error_at((*pv)->location(), + "incompatible type for element %d key in map construction", + i + 1); this->set_is_error(); } ++pv; if (!Type::are_assignable(val_type, (*pv)->type(), NULL)) { - error_at((*pv)->location(), - ("incompatible type for element %d value " - "in map construction"), + go_error_at((*pv)->location(), + ("incompatible type for element %d value " + "in map construction"), i + 1); this->set_is_error(); } @@ -12533,7 +13339,7 @@ Map_construction_expression::do_get_backend(Translate_context* context) Type::make_builtin_struct_type(2, "__key", mt->key_type(), "__val", mt->val_type()); - Expression* descriptor = Expression::make_map_descriptor(mt, loc); + Expression* descriptor = Expression::make_type_descriptor(mt, loc); Type* uintptr_t = Type::lookup_integer_type("uintptr"); Expression* count = Expression::make_integer_ul(i, uintptr_t, loc); @@ -12546,12 +13352,10 @@ Map_construction_expression::do_get_backend(Translate_context* context) this->element_type_->find_local_field("__val", &field_index); Expression* val_offset = Expression::make_struct_field_offset(this->element_type_, valfield); - Expression* val_size = - Expression::make_type_info(mt->val_type(), TYPE_INFO_SIZE); Expression* map_ctor = - Runtime::make_call(Runtime::CONSTRUCT_MAP, loc, 6, descriptor, count, - entry_size, val_offset, val_size, ventries); + Runtime::make_call(Runtime::CONSTRUCT_MAP, loc, 5, descriptor, count, + entry_size, val_offset, ventries); return map_ctor->get_backend(context); } @@ -12680,9 +13484,9 @@ Composite_literal_expression::do_lower(Gogo* gogo, Named_object* function, else { if (!type->is_error()) - error_at(this->location(), - ("may only omit types within composite literals " - "of slice, array, or map type")); + go_error_at(this->location(), + ("may only omit types within composite literals " + "of slice, array, or map type")); return Expression::make_error(this->location()); } } @@ -12706,9 +13510,9 @@ Composite_literal_expression::do_lower(Gogo* gogo, Named_object* function, ret = this->lower_map(gogo, function, inserter, type); else { - error_at(this->location(), - ("expected struct, slice, array, or map type " - "for composite literal")); + go_error_at(this->location(), + ("expected struct, slice, array, or map type " + "for composite literal")); return Expression::make_error(this->location()); } @@ -12738,10 +13542,10 @@ Composite_literal_expression::lower_struct(Gogo* gogo, Type* type) { if (Gogo::is_hidden_name(pf->field_name()) || pf->is_embedded_builtin(gogo)) - error_at(this->location(), - "assignment of unexported field %qs in %qs literal", - Gogo::message_name(pf->field_name()).c_str(), - type->named_type()->message_name().c_str()); + go_error_at(this->location(), + "assignment of unexported field %qs in %qs literal", + Gogo::message_name(pf->field_name()).c_str(), + type->named_type()->message_name().c_str()); } } @@ -12750,7 +13554,7 @@ Composite_literal_expression::lower_struct(Gogo* gogo, Type* type) size_t field_count = st->field_count(); std::vector<Expression*> vals(field_count); - std::vector<int>* traverse_order = new(std::vector<int>); + std::vector<unsigned long>* traverse_order = new(std::vector<unsigned long>); Expression_list::const_iterator p = this->vals_->begin(); Expression* external_expr = NULL; const Named_object* external_no = NULL; @@ -12766,7 +13570,8 @@ Composite_literal_expression::lower_struct(Gogo* gogo, Type* type) if (name_expr == NULL) { - error_at(val->location(), "mixture of field and value initializers"); + go_error_at(val->location(), + "mixture of field and value initializers"); return Expression::make_error(location); } @@ -12808,53 +13613,12 @@ Composite_literal_expression::lower_struct(Gogo* gogo, Type* type) no = name_expr->var_expression()->named_object(); break; - case EXPRESSION_FUNC_REFERENCE: - no = name_expr->func_expression()->named_object(); + case EXPRESSION_ENCLOSED_VAR_REFERENCE: + no = name_expr->enclosed_var_expression()->variable(); break; - case EXPRESSION_UNARY: - // If there is a local variable around with the same name as - // the field, and this occurs in the closure, then the - // parser may turn the field reference into an indirection - // through the closure. FIXME: This is a mess. - { - bad_key = true; - Unary_expression* ue = static_cast<Unary_expression*>(name_expr); - if (ue->op() == OPERATOR_MULT) - { - Field_reference_expression* fre = - ue->operand()->field_reference_expression(); - if (fre != NULL) - { - Struct_type* st = - fre->expr()->type()->deref()->struct_type(); - if (st != NULL) - { - const Struct_field* sf = st->field(fre->field_index()); - name = sf->field_name(); - - // See below. FIXME. - if (!Gogo::is_hidden_name(name) - && name[0] >= 'a' - && name[0] <= 'z') - { - if (gogo->lookup_global(name.c_str()) != NULL) - name = gogo->pack_hidden_name(name, false); - } - - char buf[20]; - snprintf(buf, sizeof buf, "%u", fre->field_index()); - size_t buflen = strlen(buf); - if (name.compare(name.length() - buflen, buflen, buf) - == 0) - { - name = name.substr(0, name.length() - buflen); - bad_key = false; - } - } - } - } - } + case EXPRESSION_FUNC_REFERENCE: + no = name_expr->func_expression()->named_object(); break; default: @@ -12863,7 +13627,7 @@ Composite_literal_expression::lower_struct(Gogo* gogo, Type* type) } if (bad_key) { - error_at(name_expr->location(), "expected struct field name"); + go_error_at(name_expr->location(), "expected struct field name"); return Expression::make_error(location); } @@ -12894,21 +13658,21 @@ Composite_literal_expression::lower_struct(Gogo* gogo, Type* type) const Struct_field* sf = st->find_local_field(name, &index); if (sf == NULL) { - error_at(name_expr->location(), "unknown field %qs in %qs", - Gogo::message_name(name).c_str(), - (type->named_type() != NULL - ? type->named_type()->message_name().c_str() - : "unnamed struct")); + go_error_at(name_expr->location(), "unknown field %qs in %qs", + Gogo::message_name(name).c_str(), + (type->named_type() != NULL + ? type->named_type()->message_name().c_str() + : "unnamed struct")); return Expression::make_error(location); } if (vals[index] != NULL) { - error_at(name_expr->location(), - "duplicate value for field %qs in %qs", - Gogo::message_name(name).c_str(), - (type->named_type() != NULL - ? type->named_type()->message_name().c_str() - : "unnamed struct")); + go_error_at(name_expr->location(), + "duplicate value for field %qs in %qs", + Gogo::message_name(name).c_str(), + (type->named_type() != NULL + ? type->named_type()->message_name().c_str() + : "unnamed struct")); return Expression::make_error(location); } @@ -12916,29 +13680,29 @@ Composite_literal_expression::lower_struct(Gogo* gogo, Type* type) && type->named_type()->named_object()->package() != NULL && (Gogo::is_hidden_name(sf->field_name()) || sf->is_embedded_builtin(gogo))) - error_at(name_expr->location(), - "assignment of unexported field %qs in %qs literal", - Gogo::message_name(sf->field_name()).c_str(), - type->named_type()->message_name().c_str()); + go_error_at(name_expr->location(), + "assignment of unexported field %qs in %qs literal", + Gogo::message_name(sf->field_name()).c_str(), + type->named_type()->message_name().c_str()); vals[index] = val; - traverse_order->push_back(index); + traverse_order->push_back(static_cast<unsigned long>(index)); } if (!this->all_are_names_) { // This is a weird case like bug462 in the testsuite. if (external_expr == NULL) - error_at(this->location(), "unknown field in %qs literal", - (type->named_type() != NULL - ? type->named_type()->message_name().c_str() - : "unnamed struct")); + go_error_at(this->location(), "unknown field in %qs literal", + (type->named_type() != NULL + ? type->named_type()->message_name().c_str() + : "unnamed struct")); else - error_at(external_expr->location(), "unknown field %qs in %qs", - external_no->message_name().c_str(), - (type->named_type() != NULL - ? type->named_type()->message_name().c_str() - : "unnamed struct")); + go_error_at(external_expr->location(), "unknown field %qs in %qs", + external_no->message_name().c_str(), + (type->named_type() != NULL + ? type->named_type()->message_name().c_str() + : "unnamed struct")); return Expression::make_error(location); } @@ -12953,15 +13717,16 @@ Composite_literal_expression::lower_struct(Gogo* gogo, Type* type) return ret; } -// Used to sort an index/value array. +// Index/value/traversal-order triple. -class Index_value_compare -{ - public: - bool - operator()(const std::pair<unsigned long, Expression*>& a, - const std::pair<unsigned long, Expression*>& b) - { return a.first < b.first; } +struct IVT_triple { + unsigned long index; + unsigned long traversal_order; + Expression* expr; + IVT_triple(unsigned long i, unsigned long to, Expression *e) + : index(i), traversal_order(to), expr(e) { } + bool operator<(const IVT_triple& other) const + { return this->index < other.index; } }; // Lower an array composite literal. @@ -13006,8 +13771,8 @@ Composite_literal_expression::lower_array(Type* type) Numeric_constant nc; if (!index_expr->numeric_constant_value(&nc)) { - error_at(index_expr->location(), - "index expression is not integer constant"); + go_error_at(index_expr->location(), + "index expression is not integer constant"); return Expression::make_error(location); } @@ -13016,14 +13781,15 @@ Composite_literal_expression::lower_array(Type* type) case Numeric_constant::NC_UL_VALID: break; case Numeric_constant::NC_UL_NOTINT: - error_at(index_expr->location(), - "index expression is not integer constant"); + go_error_at(index_expr->location(), + "index expression is not integer constant"); return Expression::make_error(location); case Numeric_constant::NC_UL_NEGATIVE: - error_at(index_expr->location(), "index expression is negative"); + go_error_at(index_expr->location(), + "index expression is negative"); return Expression::make_error(location); case Numeric_constant::NC_UL_BIG: - error_at(index_expr->location(), "index value overflow"); + go_error_at(index_expr->location(), "index value overflow"); return Expression::make_error(location); default: go_unreachable(); @@ -13034,15 +13800,16 @@ Composite_literal_expression::lower_array(Type* type) if (sizeof(index) <= static_cast<size_t>(inttype->bits() * 8) && index >> (inttype->bits() - 1) != 0) { - error_at(index_expr->location(), "index value overflow"); + go_error_at(index_expr->location(), "index value overflow"); return Expression::make_error(location); } if (std::find(indexes->begin(), indexes->end(), index) != indexes->end()) { - error_at(index_expr->location(), "duplicate value for index %lu", - index); + go_error_at(index_expr->location(), + "duplicate value for index %lu", + index); return Expression::make_error(location); } @@ -13063,35 +13830,45 @@ Composite_literal_expression::lower_array(Type* type) indexes = NULL; } + std::vector<unsigned long>* traverse_order = NULL; if (indexes_out_of_order) { - typedef std::vector<std::pair<unsigned long, Expression*> > V; + typedef std::vector<IVT_triple> V; V v; v.reserve(indexes->size()); std::vector<unsigned long>::const_iterator pi = indexes->begin(); + unsigned long torder = 0; for (Expression_list::const_iterator pe = vals->begin(); pe != vals->end(); - ++pe, ++pi) - v.push_back(std::make_pair(*pi, *pe)); + ++pe, ++pi, ++torder) + v.push_back(IVT_triple(*pi, torder, *pe)); - std::sort(v.begin(), v.end(), Index_value_compare()); + std::sort(v.begin(), v.end()); delete indexes; delete vals; + indexes = new std::vector<unsigned long>(); indexes->reserve(v.size()); vals = new Expression_list(); vals->reserve(v.size()); + traverse_order = new std::vector<unsigned long>(); + traverse_order->reserve(v.size()); for (V::const_iterator p = v.begin(); p != v.end(); ++p) { - indexes->push_back(p->first); - vals->push_back(p->second); + indexes->push_back(p->index); + vals->push_back(p->expr); + traverse_order->push_back(p->traversal_order); } } - return this->make_array(type, indexes, vals); + Expression* ret = this->make_array(type, indexes, vals); + Array_construction_expression* ace = ret->array_literal(); + if (ace != NULL && traverse_order != NULL) + ace->set_traverse_order(traverse_order); + return ret; } // Actually build the array composite literal. This handles @@ -13120,7 +13897,7 @@ Composite_literal_expression::make_array( if (sizeof(size) <= static_cast<size_t>(it->bits() * 8) && size >> (it->bits() - 1) != 0) { - error_at(location, "too many elements in composite literal"); + go_error_at(location, "too many elements in composite literal"); return Expression::make_error(location); } } @@ -13142,7 +13919,8 @@ Composite_literal_expression::make_array( { if (this->vals_->size() > val) { - error_at(location, "too many elements in composite literal"); + go_error_at(location, + "too many elements in composite literal"); return Expression::make_error(location); } } @@ -13151,9 +13929,9 @@ Composite_literal_expression::make_array( unsigned long max = indexes->back(); if (max >= val) { - error_at(location, - ("some element keys in composite literal " - "are out of range")); + go_error_at(location, + ("some element keys in composite literal " + "are out of range")); return Expression::make_error(location); } } @@ -13179,7 +13957,7 @@ Composite_literal_expression::lower_map(Gogo* gogo, Named_object* function, { if (!this->has_keys_) { - error_at(location, "map composite literal must have keys"); + go_error_at(location, "map composite literal must have keys"); return Expression::make_error(location); } @@ -13190,8 +13968,9 @@ Composite_literal_expression::lower_map(Gogo* gogo, Named_object* function, if (*p == NULL) { ++p; - error_at((*p)->location(), - "map composite literal must have keys for every value"); + go_error_at((*p)->location(), + ("map composite literal must " + "have keys for every value")); return Expression::make_error(location); } // Make sure we have lowered the key; it may not have been @@ -13295,6 +14074,7 @@ Expression::is_variable() const case EXPRESSION_VAR_REFERENCE: case EXPRESSION_TEMPORARY_REFERENCE: case EXPRESSION_SET_AND_USE_TEMPORARY: + case EXPRESSION_ENCLOSED_VAR_REFERENCE: return true; default: return false; @@ -13375,10 +14155,10 @@ Type_guard_expression::do_check_types(Gogo*) this->report_error(_("impossible type assertion: " "type does not implement interface")); else - error_at(this->location(), - ("impossible type assertion: " - "type does not implement interface (%s)"), - reason.c_str()); + go_error_at(this->location(), + ("impossible type assertion: " + "type does not implement interface (%s)"), + reason.c_str()); } this->set_is_error(); } @@ -13442,8 +14222,12 @@ Heap_expression::do_get_backend(Translate_context* context) Location loc = this->location(); Gogo* gogo = context->gogo(); Btype* btype = this->type()->get_backend(gogo); - Bexpression* space = Expression::make_allocation(this->expr_->type(), - loc)->get_backend(context); + + Expression* alloc = Expression::make_allocation(this->expr_->type(), loc); + Node* n = Node::make_node(this); + if ((n->encoding() & ESCAPE_MASK) == int(Node::ESCAPE_NONE)) + alloc->allocation_expression()->set_allocate_on_stack(); + Bexpression* space = alloc->get_backend(context); Bstatement* decl; Named_object* fn = context->function(); @@ -13452,15 +14236,16 @@ Heap_expression::do_get_backend(Translate_context* context) Bvariable* space_temp = gogo->backend()->temporary_variable(fndecl, context->bblock(), btype, space, true, loc, &decl); - space = gogo->backend()->var_expression(space_temp, loc); + space = gogo->backend()->var_expression(space_temp, VE_lvalue, loc); Btype* expr_btype = this->expr_->type()->get_backend(gogo); Bexpression* ref = gogo->backend()->indirect_expression(expr_btype, space, true, loc); Bexpression* bexpr = this->expr_->get_backend(context); - Bstatement* assn = gogo->backend()->assignment_statement(ref, bexpr, loc); + Bstatement* assn = gogo->backend()->assignment_statement(fndecl, ref, + bexpr, loc); decl = gogo->backend()->compound_statement(decl, assn); - space = gogo->backend()->var_expression(space_temp, loc); + space = gogo->backend()->var_expression(space_temp, VE_rvalue, loc); return gogo->backend()->compound_expression(decl, space, loc); } @@ -13576,9 +14361,8 @@ Receive_expression::do_get_backend(Translate_context* context) Expression* recv_addr = Expression::make_temporary_reference(this->temp_receiver_, loc); recv_addr = Expression::make_unary(OPERATOR_AND, recv_addr, loc); - Expression* recv = - Runtime::make_call(Runtime::RECEIVE, loc, 3, - td, this->channel_, recv_addr); + Expression* recv = Runtime::make_call(Runtime::CHANRECV1, loc, 3, + td, this->channel_, recv_addr); return Expression::make_compound(recv, recv_ref, loc)->get_backend(context); } @@ -13619,7 +14403,7 @@ class Type_descriptor_expression : public Expression { return Type::make_type_descriptor_ptr_type(); } bool - do_is_immutable() const + do_is_static_initializer() const { return true; } void @@ -13687,7 +14471,7 @@ class GC_symbol_expression : public Expression { return Type::lookup_integer_type("uintptr"); } bool - do_is_immutable() const + do_is_static_initializer() const { return true; } void @@ -13745,7 +14529,7 @@ class Type_info_expression : public Expression protected: bool - do_is_immutable() const + do_is_static_initializer() const { return true; } Type* @@ -14103,16 +14887,27 @@ Interface_info_expression::do_type() { case INTERFACE_INFO_METHODS: { + typedef Unordered_map(Interface_type*, Type*) Hashtable; + static Hashtable result_types; + + Interface_type* itype = this->iface_->type()->interface_type(); + + Hashtable::const_iterator p = result_types.find(itype); + if (p != result_types.end()) + return p->second; + Type* pdt = Type::make_type_descriptor_ptr_type(); - if (this->iface_->type()->interface_type()->is_empty()) - return pdt; + if (itype->is_empty()) + { + result_types[itype] = pdt; + return pdt; + } Location loc = this->location(); Struct_field_list* sfl = new Struct_field_list(); sfl->push_back( Struct_field(Typed_identifier("__type_descriptor", pdt, loc))); - Interface_type* itype = this->iface_->type()->interface_type(); for (Typed_identifier_list::const_iterator p = itype->methods()->begin(); p != itype->methods()->end(); ++p) @@ -14145,7 +14940,11 @@ Interface_info_expression::do_type() sfl->push_back(Struct_field(Typed_identifier(fname, mft, loc))); } - return Type::make_pointer_type(Type::make_struct_type(sfl, loc)); + Struct_type* st = Type::make_struct_type(sfl, loc); + st->set_is_struct_incomparable(); + Pointer_type *pt = Type::make_pointer_type(st); + result_types[itype] = pt; + return pt; } case INTERFACE_INFO_OBJECT: return Type::make_pointer_type(Type::make_void_type()); @@ -14313,7 +15112,7 @@ class Interface_mtable_expression : public Expression do_type(); bool - is_immutable() const + do_is_static_initializer() const { return true; } void @@ -14377,7 +15176,9 @@ Interface_mtable_expression::do_type() p != interface_methods->end(); ++p) sfl->push_back(Struct_field(*p)); - this->method_table_type_ = Type::make_struct_type(sfl, this->location()); + Struct_type* st = Type::make_struct_type(sfl, this->location()); + st->set_is_struct_incomparable(); + this->method_table_type_ = st; return this->method_table_type_; } @@ -14387,7 +15188,8 @@ Interface_mtable_expression::do_get_backend(Translate_context* context) Gogo* gogo = context->gogo(); Location loc = Linemap::predeclared_location(); if (this->bvar_ != NULL) - return gogo->backend()->var_expression(this->bvar_, this->location()); + return gogo->backend()->var_expression(this->bvar_, VE_rvalue, + this->location()); const Typed_identifier_list* interface_methods = this->itype_->methods(); go_assert(!interface_methods->empty()); @@ -14419,9 +15221,12 @@ Interface_mtable_expression::do_get_backend(Translate_context* context) && this->type_->named_type()->named_object()->package() != NULL) { Btype* btype = this->type()->get_backend(gogo); + std::string asm_name(go_selectively_encode_id(mangled_name)); this->bvar_ = - gogo->backend()->immutable_struct_reference(mangled_name, btype, loc); - return gogo->backend()->var_expression(this->bvar_, this->location()); + gogo->backend()->immutable_struct_reference(mangled_name, asm_name, + btype, loc); + return gogo->backend()->var_expression(this->bvar_, VE_rvalue, + this->location()); } // The first element is the type descriptor. @@ -14464,11 +15269,12 @@ Interface_mtable_expression::do_get_backend(Translate_context* context) Bexpression* ctor = mtable->get_backend(context); bool is_public = has_hidden_methods && this->type_->named_type() != NULL; - this->bvar_ = gogo->backend()->immutable_struct(mangled_name, false, + std::string asm_name(go_selectively_encode_id(mangled_name)); + this->bvar_ = gogo->backend()->immutable_struct(mangled_name, asm_name, false, !is_public, btype, loc); gogo->backend()->immutable_struct_set_init(this->bvar_, mangled_name, false, !is_public, btype, loc, ctor); - return gogo->backend()->var_expression(this->bvar_, loc); + return gogo->backend()->var_expression(this->bvar_, VE_lvalue, loc); } void @@ -14504,7 +15310,7 @@ class Struct_field_offset_expression : public Expression protected: bool - do_is_immutable() const + do_is_static_initializer() const { return true; } Type* @@ -14581,64 +15387,6 @@ Expression::make_struct_field_offset(Struct_type* type, return new Struct_field_offset_expression(type, field); } -// An expression which evaluates to a pointer to the map descriptor of -// a map type. - -class Map_descriptor_expression : public Expression -{ - public: - Map_descriptor_expression(Map_type* type, Location location) - : Expression(EXPRESSION_MAP_DESCRIPTOR, location), - type_(type) - { } - - protected: - Type* - do_type() - { return Type::make_pointer_type(Map_type::make_map_descriptor_type()); } - - void - do_determine_type(const Type_context*) - { } - - Expression* - do_copy() - { return this; } - - Bexpression* - do_get_backend(Translate_context* context) - { - return this->type_->map_descriptor_pointer(context->gogo(), - this->location()); - } - - void - do_dump_expression(Ast_dump_context*) const; - - private: - // The type for which this is the descriptor. - Map_type* type_; -}; - -// Dump ast representation for a map descriptor expression. - -void -Map_descriptor_expression::do_dump_expression( - Ast_dump_context* ast_dump_context) const -{ - ast_dump_context->ostream() << "map_descriptor("; - ast_dump_context->dump_type(this->type_); - ast_dump_context->ostream() << ")"; -} - -// Make a map descriptor expression. - -Expression* -Expression::make_map_descriptor(Map_type* type, Location location) -{ - return new Map_descriptor_expression(type, location); -} - // An expression which evaluates to the address of an unnamed label. class Label_addr_expression : public Expression @@ -14734,7 +15482,8 @@ Conditional_expression::do_get_backend(Translate_context* context) Bexpression* cond = this->cond_->get_backend(context); Bexpression* then = this->then_->get_backend(context); Bexpression* belse = this->else_->get_backend(context); - return gogo->backend()->conditional_expression(result_btype, cond, then, + Bfunction* bfn = context->function()->func_value()->get_decl(); + return gogo->backend()->conditional_expression(bfn, result_btype, cond, then, belse, this->location()); } @@ -14799,7 +15548,9 @@ Compound_expression::do_get_backend(Translate_context* context) { Gogo* gogo = context->gogo(); Bexpression* binit = this->init_->get_backend(context); - Bstatement* init_stmt = gogo->backend()->expression_statement(binit); + Bfunction* bfunction = context->function()->func_value()->get_decl(); + Bstatement* init_stmt = gogo->backend()->expression_statement(bfunction, + binit); Bexpression* bexpr = this->expr_->get_backend(context); return gogo->backend()->compound_expression(init_stmt, bexpr, this->location()); @@ -14826,6 +15577,28 @@ Expression::make_compound(Expression* init, Expression* expr, Location location) return new Compound_expression(init, expr, location); } +// Class Backend_expression. + +int +Backend_expression::do_traverse(Traverse*) +{ + return TRAVERSE_CONTINUE; +} + +void +Backend_expression::do_dump_expression(Ast_dump_context* ast_dump_context) const +{ + ast_dump_context->ostream() << "backend_expression<"; + ast_dump_context->dump_type(this->type_); + ast_dump_context->ostream() << ">"; +} + +Expression* +Expression::make_backend(Bexpression* bexpr, Type* type, Location location) +{ + return new Backend_expression(bexpr, type, location); +} + // Import an expression. This comes at the end in order to see the // various class definitions. @@ -14855,7 +15628,7 @@ Expression::import_expression(Import* imp) return Type_conversion_expression::do_import(imp); else { - error_at(imp->location(), "import error: expected expression"); + go_error_at(imp->location(), "import error: expected expression"); return Expression::make_error(imp->location()); } } @@ -15295,8 +16068,8 @@ Numeric_constant::check_int_type(Integer_type* type, bool issue_error, { if (issue_error) { - error_at(location, - "floating point constant truncated to integer"); + go_error_at(location, + "floating point constant truncated to integer"); this->set_invalid(); } return false; @@ -15311,7 +16084,7 @@ Numeric_constant::check_int_type(Integer_type* type, bool issue_error, { if (issue_error) { - error_at(location, "complex constant truncated to integer"); + go_error_at(location, "complex constant truncated to integer"); this->set_invalid(); } return false; @@ -15352,7 +16125,7 @@ Numeric_constant::check_int_type(Integer_type* type, bool issue_error, if (!ret && issue_error) { - error_at(location, "integer constant overflow"); + go_error_at(location, "integer constant overflow"); this->set_invalid(); } @@ -15384,7 +16157,7 @@ Numeric_constant::check_float_type(Float_type* type, bool issue_error, if (issue_error) { this->set_invalid(); - error_at(location, "complex constant truncated to float"); + go_error_at(location, "complex constant truncated to float"); } return false; } @@ -15449,7 +16222,7 @@ Numeric_constant::check_float_type(Float_type* type, bool issue_error, if (!ret && issue_error) { - error_at(location, "floating point constant overflow"); + go_error_at(location, "floating point constant overflow"); this->set_invalid(); } @@ -15507,7 +16280,7 @@ Numeric_constant::check_complex_type(Complex_type* type, bool issue_error, { if (issue_error) { - error_at(location, "complex real part overflow"); + go_error_at(location, "complex real part overflow"); this->set_invalid(); } ret = false; @@ -15520,7 +16293,7 @@ Numeric_constant::check_complex_type(Complex_type* type, bool issue_error, { if (issue_error) { - error_at(location, "complex imaginary part overflow"); + go_error_at(location, "complex imaginary part overflow"); this->set_invalid(); } ret = false; |