diff options
Diffstat (limited to 'gcc/go/gofrontend/expressions.cc')
-rw-r--r-- | gcc/go/gofrontend/expressions.cc | 3684 |
1 files changed, 2583 insertions, 1101 deletions
diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc index c9177b7..a09d33b 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -214,6 +214,31 @@ Expression::is_untyped_type(Type* type, Type** ptype) return true; } +// Report whether this is a type expression. + +bool +Expression::is_type_expression() const +{ + if (this->classification_ == EXPRESSION_TYPE) + return true; + if (this->unknown_expression() != NULL) + { + Named_object* no = this->unknown_expression()->named_object(); + if (no->is_unknown()) + { + no = no->unknown_value()->real_named_object(); + if (no == NULL) + return false; + } + return no->is_type(); + } + if (this->unary_expression() != NULL + && this->unary_expression()->op() == OPERATOR_MULT + && this->unary_expression()->operand()->is_type_expression()) + return true; + return false; +} + // Set types of variables and constants. This is implemented by the // child class. @@ -301,24 +326,25 @@ Expression::convert_for_assignment(Gogo* gogo, Type* lhs_type, (Type::COMPARE_ERRORS | Type::COMPARE_TAGS), NULL); + Expression* ret; if (!are_identical && lhs_type->interface_type() != NULL) { // Type to interface conversions have been made explicit early. go_assert(rhs_type->interface_type() != NULL); - return Expression::convert_interface_to_interface(gogo, lhs_type, rhs, - false, location); + ret = Expression::convert_interface_to_interface(gogo, lhs_type, rhs, + false, location); } else if (!are_identical && rhs_type->interface_type() != NULL) - return Expression::convert_interface_to_type(gogo, lhs_type, rhs, location); + ret = Expression::convert_interface_to_type(gogo, lhs_type, rhs, location); else if (lhs_type->is_slice_type() && rhs_type->is_nil_type()) { // Assigning nil to a slice. Expression* nil = Expression::make_nil(location); Expression* zero = Expression::make_integer_ul(0, NULL, location); - return Expression::make_slice_value(lhs_type, nil, zero, zero, location); + ret = Expression::make_slice_value(lhs_type, nil, zero, zero, location); } else if (rhs_type->is_nil_type()) - return Expression::make_nil(location); + ret = Expression::make_nil(location); else if (are_identical) { if (lhs_type->forwarded() != rhs_type->forwarded()) @@ -332,9 +358,9 @@ Expression::convert_for_assignment(Gogo* gogo, Type* lhs_type, return rhs; } else if (lhs_type->points_to() != NULL) - return Expression::make_unsafe_cast(lhs_type, rhs, location); + ret = Expression::make_unsafe_cast(lhs_type, rhs, location); else if (lhs_type->is_numeric_type()) - return Expression::make_cast(lhs_type, rhs, location); + ret = Expression::make_cast(lhs_type, rhs, location); else if ((lhs_type->struct_type() != NULL && rhs_type->struct_type() != NULL) || (lhs_type->array_type() != NULL @@ -342,10 +368,14 @@ Expression::convert_for_assignment(Gogo* gogo, Type* lhs_type, { // This conversion must be permitted by Go, or we wouldn't have // gotten here. - return Expression::make_unsafe_cast(lhs_type, rhs, location); + ret = Expression::make_unsafe_cast(lhs_type, rhs, location); } else return rhs; + + Type_context context(lhs_type, false); + ret->determine_type(gogo, &context); + return ret; } // Return an expression for a conversion from a non-interface type to an @@ -579,7 +609,11 @@ Expression::convert_interface_to_interface(Gogo* gogo, Type *lhs_type, // The second field is simply the object pointer. Expression* obj = Expression::make_interface_info(rhs, INTERFACE_INFO_OBJECT, location); - return Expression::make_interface_value(lhs_type, first_field, obj, location); + Expression* ret = Expression::make_interface_value(lhs_type, first_field, + obj, location); + Type_context context(lhs_type, false); + ret->determine_type(gogo, &context); + return ret; } // Return an expression for the conversion of an interface type to a @@ -818,7 +852,9 @@ Expression::check_bounds(Gogo* gogo, Expression* val, Operator op, Expression* crash = Runtime::make_call(gogo, c, loc, 2, val->copy(), bound->copy()); Expression* cond = Expression::make_conditional(check, ignore, crash, loc); - inserter->insert(Statement::make_statement(cond, true)); + Statement* s = Statement::make_statement(cond, true); + s->determine_types(gogo); + inserter->insert(s); } void @@ -846,11 +882,8 @@ class Error_expression : public Expression { return false; } bool - do_numeric_constant_value(Numeric_constant* nc) - { - nc->set_unsigned_long(NULL, 0); - return true; - } + do_numeric_constant_value(Numeric_constant*) + { return false; } bool do_discarding_value() @@ -897,8 +930,7 @@ Expression::make_error(Location location) // An expression which is really a type. This is used during parsing. // It is an error if these survive after lowering. -class -Type_expression : public Expression +class Type_expression : public Expression { public: Type_expression(Type* type, Location location) @@ -927,8 +959,7 @@ Type_expression : public Expression { return this; } Bexpression* - do_get_backend(Translate_context*) - { go_unreachable(); } + do_get_backend(Translate_context*); void do_dump_expression(Ast_dump_context*) const; @@ -945,8 +976,14 @@ Type_expression::do_check_types(Gogo*) go_assert(saw_errors()); this->set_is_error(); } - else - this->report_error(_("invalid use of type")); +} + +Bexpression* +Type_expression::do_get_backend(Translate_context* context) +{ + if (!this->is_error_expression()) + this->report_error("invalid use of type"); + return context->backend()->error_expression(); } void @@ -961,19 +998,6 @@ Expression::make_type(Type* type, Location location) return new Type_expression(type, location); } -// Class Parser_expression. - -Type* -Parser_expression::do_type() -{ - // We should never really ask for the type of a Parser_expression. - // However, it can happen, at least when we have an invalid const - // whose initializer refers to the const itself. In that case we - // may ask for the type when lowering the const itself. - go_assert(saw_errors()); - return Type::make_error_type(); -} - // Class Var_expression. // Lower a variable expression. Here we just make sure that the @@ -1114,6 +1138,8 @@ Expression::make_var_reference(Named_object* var, Location location) { if (var->is_sink()) return Expression::make_sink(location); + if (var->is_redefinition()) + return Expression::make_error(location); // FIXME: Creating a new object for each reference to a variable is // wasteful. @@ -1874,60 +1900,221 @@ Unknown_expression::name() const return this->named_object_->name(); } -// Lower a reference to an unknown name. +// Set the iota value if this could be a reference to iota. -Expression* -Unknown_expression::do_lower(Gogo*, Named_object*, Statement_inserter*, int) +void +Unknown_expression::set_iota_value(int iota_value) { - Location location = this->location(); + this->iota_value_ = iota_value; + this->is_iota_ = true; +} + +// Traversal. + +int +Unknown_expression::do_traverse(Traverse* traverse) +{ + if (this->lowered_ != NULL) + { + if (Expression::traverse(&this->lowered_, traverse) == TRAVERSE_EXIT) + return TRAVERSE_EXIT; + } + return TRAVERSE_CONTINUE; +} + +// Determine the type of a reference to an unknown name. At this +// point we have to figure out what the name refers to. + +void +Unknown_expression::do_determine_type(Gogo* gogo, const Type_context* context) +{ + if (this->is_error_expression()) + return; + + if (this->lowered_ != NULL) + { + this->lowered_->determine_type(gogo, context); + return; + } + + Location loc = this->location(); + Named_object* no = this->named_object_; - Named_object* real; - if (!no->is_unknown()) - real = no; - else + if (no->is_unknown()) { - real = no->unknown_value()->real_named_object(); + Named_object* real = no->unknown_value()->real_named_object(); if (real == NULL) { if (!this->no_error_message_) - go_error_at(location, "reference to undefined name %qs", - this->named_object_->message_name().c_str()); - return Expression::make_error(location); + go_error_at(loc, "reference to undefined name %qs", + no->message_name().c_str()); + this->set_is_error(); + return; } + no = real; + this->named_object_ = real; } - switch (real->classification()) + + switch (no->classification()) { - case Named_object::NAMED_OBJECT_CONST: - return Expression::make_const_reference(real, location); case Named_object::NAMED_OBJECT_TYPE: - return Expression::make_type(real->type_value(), location); - case Named_object::NAMED_OBJECT_TYPE_DECLARATION: - if (!this->no_error_message_) - 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(); - return Expression::make_var_reference(real, location); + this->lowered_ = Expression::make_type(no->type_value(), loc); + break; case Named_object::NAMED_OBJECT_FUNC: case Named_object::NAMED_OBJECT_FUNC_DECLARATION: - return Expression::make_func_reference(real, NULL, location); + this->lowered_ = Expression::make_func_reference(no, NULL, loc); + break; + case Named_object::NAMED_OBJECT_CONST: + this->lowered_ = Expression::make_const_reference(no, loc); + this->lowered_->determine_type(gogo, context); + if (this->is_iota_) + this->lowered_->const_expression()->set_iota_value(this->iota_value_); + break; + case Named_object::NAMED_OBJECT_VAR: + this->lowered_ = Expression::make_var_reference(no, loc); + no->var_value()->set_is_used(); + this->lowered_->determine_type(gogo, context); + break; + case Named_object::NAMED_OBJECT_TYPE_DECLARATION: + if (!this->no_error_message_) + go_error_at(this->location(), "reference to undefined type %qs", + no->message_name().c_str()); + this->set_is_error(); + break; case Named_object::NAMED_OBJECT_PACKAGE: if (!this->no_error_message_) - go_error_at(location, "unexpected reference to package"); - return Expression::make_error(location); + this->report_error(_("unexpected reference to package")); + this->set_is_error(); + break; default: go_unreachable(); } } +Type* +Unknown_expression::do_type() +{ + if (this->is_error_expression()) + return Type::make_error_type(); + go_assert(this->lowered_ != NULL); + return this->lowered_->type(); +} + +bool +Unknown_expression::do_is_constant() const +{ + if (this->is_error_expression()) + return true; + if (this->lowered_ != NULL) + return this->lowered_->is_constant(); + + // This can be called before do_determine_types by + // Binary_expression::do_determine_type, which needs to know which + // values are constant before it works out the appropriate + // Type_context to pass down. + Named_object* no = this->named_object_; + if (no->is_unknown()) + { + no = no->unknown_value()->real_named_object(); + if (no == NULL) + return true; + } + return no->is_const(); +} + +bool +Unknown_expression::do_is_untyped(Type** ptype) const +{ + if (this->is_error_expression()) + return false; + if (this->lowered_ != NULL) + return this->lowered_->is_untyped(ptype); + + Named_object* no = this->named_object_; + if (no->is_unknown()) + { + no = no->unknown_value()->real_named_object(); + if (no == NULL) + return false; + } + + if (!no->is_const()) + return false; + Type* t = no->const_value()->type(); + if (t != NULL) + return Expression::is_untyped_type(t, ptype); + return no->const_value()->expr()->is_untyped(ptype); +} + +bool +Unknown_expression::do_numeric_constant_value(Numeric_constant* nc) +{ + if (this->is_error_expression()) + return false; + if (this->lowered_ != NULL) + return this->lowered_->numeric_constant_value(nc); + + // This can be called before the determine_types pass. + Named_object* no = this->named_object_; + if (no->is_unknown()) + { + no = no->unknown_value()->real_named_object(); + if (no == NULL) + return false; + } + if (!no->is_const()) + return false; + return no->const_value()->expr()->numeric_constant_value(nc); +} + +bool +Unknown_expression::do_string_constant_value(std::string* val) +{ + if (this->is_error_expression()) + return false; + go_assert(this->lowered_ != NULL); + return this->lowered_->string_constant_value(val); +} + +bool +Unknown_expression::do_boolean_constant_value(bool* val) +{ + if (this->is_error_expression()) + return false; + go_assert(this->lowered_ != NULL); + return this->lowered_->boolean_constant_value(val); +} + +bool +Unknown_expression::do_is_addressable() const +{ + if (this->is_error_expression()) + return true; + go_assert(this->lowered_ != NULL); + return this->lowered_->is_addressable(); +} + +// Lower a reference to an unknown name. + +Expression* +Unknown_expression::do_lower(Gogo*, Named_object*, Statement_inserter*, int) +{ + if (this->is_error_expression()) + return Expression::make_error(this->location()); + go_assert(this->lowered_ != NULL); + return this->lowered_; +} + // Dump the ast representation for an unknown expression to a dump context. void Unknown_expression::do_dump_expression(Ast_dump_context* ast_dump_context) const { - ast_dump_context->ostream() << "_Unknown_(" << this->named_object_->name() - << ")"; + if (this->lowered_ != NULL) + this->lowered_->dump_expression(ast_dump_context); + else + ast_dump_context->ostream() << "_Unknown_(" << this->named_object_->name() + << ")"; } // Make a reference to an unknown name. @@ -2320,7 +2507,7 @@ class String_info_expression : public Expression void do_determine_type(Gogo*, const Type_context*) - { go_unreachable(); } + { } Expression* do_copy() @@ -2715,8 +2902,7 @@ Integer_expression::do_get_backend(Translate_context* context) else { if (!saw_errors()) - go_error_at(this->location(), - "unknown type for large integer constant"); + go_error_at(this->location(), "integer constant overflow"); return context->gogo()->backend()->error_expression(); } } @@ -3456,20 +3642,17 @@ Const_expression::do_is_zero_value() const // predeclared constant iota into an integer value. Expression* -Const_expression::do_lower(Gogo* gogo, Named_object*, - Statement_inserter*, int iota_value) +Const_expression::do_lower(Gogo* gogo, Named_object*, Statement_inserter*, int) { - if (this->constant_->const_value()->expr()->classification() - == EXPRESSION_IOTA) - { - if (iota_value == -1) - { - 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()); - } + Location loc = this->location(); + + if (this->is_error_expression()) + return Expression::make_error(loc); + if (this->constant_->const_value()->expr()->is_error_expression()) + return Expression::make_error(loc); + + if (this->is_iota_) + return Expression::make_integer_ul(this->iota_value_, NULL, loc); // Make sure that the constant itself has been lowered. gogo->lower_constant(this->constant_); @@ -3485,6 +3668,19 @@ Const_expression::do_numeric_constant_value(Numeric_constant* nc) if (this->seen_) return false; + Type* ctype; + if (this->type_ != NULL) + ctype = this->type_; + else + ctype = this->constant_->const_value()->type(); + + if (this->is_iota_) + { + nc->set_unsigned_long(ctype, + static_cast<unsigned long>(this->iota_value_)); + return true; + } + Expression* e = this->constant_->const_value()->expr(); this->seen_ = true; @@ -3493,11 +3689,6 @@ Const_expression::do_numeric_constant_value(Numeric_constant* nc) this->seen_ = false; - Type* ctype; - if (this->type_ != NULL) - ctype = this->type_; - else - ctype = this->constant_->const_value()->type(); if (r && ctype != NULL) { if (!nc->set_type(ctype, false, this->location())) @@ -3512,6 +3703,8 @@ Const_expression::do_string_constant_value(std::string* val) { if (this->seen_) return false; + if (this->is_iota_) + return false; Expression* e = this->constant_->const_value()->expr(); @@ -3527,6 +3720,8 @@ Const_expression::do_boolean_constant_value(bool* val) { if (this->seen_) return false; + if (this->is_iota_) + return false; Expression* e = this->constant_->const_value()->expr(); @@ -3557,77 +3752,71 @@ Const_expression::do_is_untyped(Type** ptype) const Type* Const_expression::do_type() { - if (this->type_ != NULL) - return this->type_; + if (this->type_ == NULL) + { + go_assert(saw_errors()); + return Type::make_error_type(); + } - Named_constant* nc = this->constant_->const_value(); + return this->type_; +} + +// Set the type of the const reference. + +void +Const_expression::do_determine_type(Gogo* gogo, const Type_context* context) +{ + if (this->type_ != NULL) + return; - if (this->seen_ || nc->lowering()) + // The type may depend on the type of other constants. Avoid an + // endless loop. + if (this->seen_) { - if (nc->type() == NULL || !nc->type()->is_error_type()) - { - Location loc = this->location(); - if (!this->seen_) - loc = nc->location(); - go_error_at(loc, "constant refers to itself"); - } + if (!saw_errors()) + go_error_at(this->location(), "constant refers to itself"); this->set_is_error(); this->type_ = Type::make_error_type(); - nc->set_type(this->type_); - return this->type_; + return; } this->seen_ = true; - Type* ret = nc->type(); - - if (ret != NULL) - { - this->seen_ = false; - return ret; - } + Named_constant* nc = this->constant_->const_value(); + nc->determine_type(gogo); - // During parsing, a named constant may have a NULL type, but we - // must not return a NULL type here. - ret = nc->expr()->type(); + Type* ctype = nc->type(); this->seen_ = false; - if (ret->is_error_type()) - nc->set_type(ret); - - return ret; -} - -// Set the type of the const reference. - -void -Const_expression::do_determine_type(Gogo*, const Type_context* context) -{ - Type* ctype = this->constant_->const_value()->type(); - Type* cetype = (ctype != NULL - ? ctype - : this->constant_->const_value()->expr()->type()); - if (ctype != NULL && !ctype->is_abstract()) - ; + if (ctype == NULL) + { + go_error_at(nc->expr()->location(), "constant refers to itself"); + this->set_is_error(); + this->type_ = Type::make_error_type(); + } + else if (!ctype->is_abstract()) + this->type_ = ctype; else if (context->type != NULL && context->type->is_numeric_type() - && cetype->is_numeric_type()) + && ctype->is_numeric_type()) this->type_ = context->type; else if (context->type != NULL && context->type->is_string_type() - && cetype->is_string_type()) + && ctype->is_string_type()) this->type_ = context->type; else if (context->type != NULL && context->type->is_boolean_type() - && cetype->is_boolean_type()) + && ctype->is_boolean_type()) this->type_ = context->type; else if (!context->may_be_abstract) { - if (cetype->is_abstract()) - cetype = cetype->make_non_abstract_type(); - this->type_ = cetype; + if (ctype->is_abstract()) + ctype = ctype->make_non_abstract_type(); + this->type_ = ctype; } + else + this->type_ = ctype; } // Check for a loop in which the initializer of a constant refers to @@ -3636,8 +3825,15 @@ Const_expression::do_determine_type(Gogo*, const Type_context* context) void Const_expression::check_for_init_loop() { + if (this->is_error_expression()) + return; if (this->type_ != NULL && this->type_->is_error()) return; + if (this->constant_->const_value()->expr()->is_error_expression()) + { + this->set_is_error(); + return; + } if (this->seen_) { @@ -3664,21 +3860,61 @@ Const_expression::check_for_init_loop() } } +// Set the iota value if this is a reference to iota. + +void +Const_expression::set_iota_value(int iota_value) +{ + Named_constant* nc = this->constant_->const_value(); + if (nc->expr()->classification() == EXPRESSION_IOTA) + { + this->is_iota_ = true; + this->iota_value_ = iota_value; + } +} + // Check types of a const reference. void Const_expression::do_check_types(Gogo*) { + if (this->is_error_expression()) + return; if (this->type_ != NULL && this->type_->is_error()) return; + if (this->constant_->const_value()->expr()->is_error_expression()) + { + this->set_is_error(); + return; + } + + Expression* expr = this->constant_->const_value()->expr(); + if (expr->classification() == EXPRESSION_IOTA && !this->is_iota_) + { + go_error_at(this->location(), + "iota is only defined in const declarations"); + // Avoid knock-on errors. + this->is_iota_ = true; + this->iota_value_ = 0; + } + + if (this->is_iota_ && this->type_->is_numeric_type()) + { + Numeric_constant nc; + nc.set_unsigned_long(Type::make_abstract_integer_type(), + static_cast<unsigned long>(this->iota_value_)); + if (!nc.set_type(this->type_, true, this->location())) + this->set_is_error(); + return; + } this->check_for_init_loop(); // Check that numeric constant fits in type. - if (this->type_ != NULL && this->type_->is_numeric_type()) + if (this->type_->is_numeric_type()) { Numeric_constant nc; - if (this->constant_->const_value()->expr()->numeric_constant_value(&nc)) + if (expr->numeric_constant_value(&nc)) { if (!nc.set_type(this->type_, true, this->location())) this->set_is_error(); @@ -3698,6 +3934,8 @@ Const_expression::do_get_backend(Translate_context* context) return context->backend()->error_expression(); } + go_assert(!this->is_iota_); + // If the type has been set for this expression, but the underlying // object is an abstract int or float, we try to get the abstract // value. Otherwise we may lose something in the conversion. @@ -3760,12 +3998,6 @@ Find_named_object::expression(Expression** pexpr) Const_expression* ce = static_cast<Const_expression*>(*pexpr); if (ce->named_object() == this->no_) break; - - // We need to check a constant initializer explicitly, as - // loops here will not be caught by the loop checking for - // variable initializers. - ce->check_for_init_loop(); - return TRAVERSE_CONTINUE; } @@ -3777,6 +4009,8 @@ Find_named_object::expression(Expression** pexpr) if ((*pexpr)->func_expression()->named_object() == this->no_) break; return TRAVERSE_CONTINUE; + case Expression::EXPRESSION_ERROR: + return TRAVERSE_EXIT; default: return TRAVERSE_CONTINUE; } @@ -3877,6 +4111,14 @@ class Iota_expression : public Parser_expression { } protected: + Type* + do_type() + { return Type::make_abstract_integer_type(); } + + void + do_determine_type(Gogo*, const Type_context*) + { } + Expression* do_lower(Gogo*, Named_object*, Statement_inserter*, int) { go_unreachable(); } @@ -3914,6 +4156,16 @@ Type_conversion_expression::do_traverse(Traverse* traverse) return TRAVERSE_CONTINUE; } +// Return the type of the expression. + +Type* +Type_conversion_expression::do_type() +{ + if (this->is_error_expression() || this->expr_->is_error_expression()) + return Type::make_error_type(); + return this->type_; +} + // Convert to a constant at lowering time. Also lower conversions // from slice to pointer-to-array, as they can panic. @@ -4039,7 +4291,8 @@ Type_conversion_expression::do_lower(Gogo* gogo, Named_object*, location); vallen = Expression::make_temporary_reference(vallen_temp, location); - Expression* panic = Runtime::make_call(gogo, Runtime::PANIC_SLICE_CONVERT, + Expression* panic = Runtime::make_call(gogo, + Runtime::PANIC_SLICE_CONVERT, location, 2, arrlen, vallen); Expression* nil = Expression::make_nil(location); @@ -4055,7 +4308,9 @@ Type_conversion_expression::do_lower(Gogo* gogo, Named_object*, location); ptr = Expression::make_unsafe_cast(type, ptr, location); - return Expression::make_compound(check, ptr, location); + Expression* ret = Expression::make_compound(check, ptr, location); + ret->determine_type_no_context(gogo); + return ret; } return this; @@ -4268,6 +4523,12 @@ Type_conversion_expression::do_check_types(Gogo*) if (Type::are_convertible(type, expr_type, &reason)) return; + // We can convert all numeric types if the value is a constant. + if (type->is_numeric_type() + && expr_type->is_numeric_type() + && this->expr_->is_constant()) + return; + go_error_at(this->location(), "%s", reason.c_str()); this->set_is_error(); } @@ -4291,6 +4552,7 @@ Type_conversion_expression::do_get_backend(Translate_context* context) { Type* type = this->type_; Type* expr_type = this->expr_->type(); + Type_context tcontext(type, false); Gogo* gogo = context->gogo(); Btype* btype = type->get_backend(gogo); @@ -4309,6 +4571,7 @@ Type_conversion_expression::do_get_backend(Translate_context* context) Expression* conversion = Expression::convert_type_to_interface(type, this->expr_, this->no_escape_, loc); + conversion->determine_type(gogo, &tcontext); return conversion->get_backend(context); } else if (type->interface_type() != NULL @@ -4317,6 +4580,7 @@ Type_conversion_expression::do_get_backend(Translate_context* context) Expression* conversion = Expression::convert_for_assignment(gogo, type, this->expr_, loc); + conversion->determine_type(gogo, &tcontext); return conversion->get_backend(context); } else if (type->is_string_type() @@ -4343,6 +4607,7 @@ Type_conversion_expression::do_get_backend(Translate_context* context) Lex::append_char(x, true, &s, loc); mpz_clear(intval); Expression* se = Expression::make_string(s, loc); + se->determine_type(gogo, &tcontext); return se->get_backend(context); } @@ -4361,7 +4626,10 @@ Type_conversion_expression::do_get_backend(Translate_context* context) buf = Expression::make_nil(loc); Expression* i2s_expr = Runtime::make_call(gogo, Runtime::INTSTRING, loc, 2, buf, this->expr_); - return Expression::make_cast(type, i2s_expr, loc)->get_backend(context); + Expression* ret = Expression::make_cast(type, i2s_expr, loc); + Type_context tcontext(type, false); + ret->determine_type(gogo, &tcontext); + return ret->get_backend(context); } else if (type->is_string_type() && expr_type->is_slice_type()) { @@ -4398,14 +4666,20 @@ Type_conversion_expression::do_get_backend(Translate_context* context) Expression* str = Expression::make_string_value(ptr, len, loc); return str->get_backend(context); } - return Runtime::make_call(gogo, Runtime::SLICEBYTETOSTRING, loc, 3, - buf, ptr, len)->get_backend(context); + Expression* ret = Runtime::make_call(gogo, Runtime::SLICEBYTETOSTRING, + loc, 3, buf, ptr, len); + Type_context tcontext(type, false); + ret->determine_type(gogo, &tcontext); + return ret->get_backend(context); } else { go_assert(e->integer_type()->is_rune()); - return Runtime::make_call(gogo, Runtime::SLICERUNETOSTRING, loc, 2, - buf, this->expr_)->get_backend(context); + Expression* ret = Runtime::make_call(gogo, Runtime::SLICERUNETOSTRING, + loc, 2, buf, this->expr_); + Type_context tcontext(type, false); + ret->determine_type(gogo, &tcontext); + return ret->get_backend(context); } } else if (type->is_slice_type() && expr_type->is_string_type()) @@ -4436,7 +4710,10 @@ Type_conversion_expression::do_get_backend(Translate_context* context) buf = Expression::make_nil(loc); Expression* s2a = Runtime::make_call(gogo, code, loc, 2, buf, this->expr_); - return Expression::make_unsafe_cast(type, s2a, loc)->get_backend(context); + Expression* ret = Expression::make_unsafe_cast(type, s2a, loc); + Type_context tcontext(type, false); + ret->determine_type(gogo, &tcontext); + return ret->get_backend(context); } else if (type->is_numeric_type()) { @@ -4460,6 +4737,7 @@ Type_conversion_expression::do_get_backend(Translate_context* context) { Expression* conversion = Expression::convert_for_assignment(gogo, type, this->expr_, loc); + conversion->determine_type(gogo, &tcontext); return conversion->get_backend(context); } } @@ -4719,14 +4997,26 @@ Unary_expression::check_operand_address_taken(Gogo*) // instead. Expression* -Unary_expression::do_lower(Gogo*, Named_object*, Statement_inserter*, int) +Unary_expression::do_lower(Gogo* gogo, Named_object*, Statement_inserter*, int) { Location loc = this->location(); + + if (this->is_error_expression()) + return Expression::make_error(loc); + Operator op = this->op_; Expression* expr = this->expr_; + if (expr->is_error_expression()) + return Expression::make_error(loc); + if (op == OPERATOR_MULT && expr->is_type_expression()) - return Expression::make_type(Type::make_pointer_type(expr->type()), loc); + { + Expression* ret = + Expression::make_type(Type::make_pointer_type(expr->type()), loc); + ret->determine_type_no_context(gogo); + return ret; + } // *&x simplifies to x. *(*T)(unsafe.Pointer)(&x) does not require // moving x to the heap. FIXME: Is it worth doing a real escape @@ -4763,14 +5053,6 @@ Unary_expression::do_lower(Gogo*, Named_object*, Statement_inserter*, int) } } - // Catching an invalid indirection of unsafe.Pointer here avoid - // having to deal with TYPE_VOID in other places. - if (op == OPERATOR_MULT && expr->type()->is_unsafe_pointer_type()) - { - go_error_at(this->location(), "invalid indirect of %<unsafe.Pointer%>"); - return Expression::make_error(this->location()); - } - // Check for an invalid pointer dereference. We need to do this // here because Unary_expression::do_type will return an error type // in this case. That can cause code to appear erroneous, and @@ -4788,9 +5070,15 @@ Unary_expression::do_lower(Gogo*, Named_object*, Statement_inserter*, int) { Numeric_constant result; bool issued_error; - if (Unary_expression::eval_constant(op, &nc, loc, &result, - &issued_error)) - return result.expression(loc); + if (Unary_expression::eval_constant(this->type_, op, &nc, loc, + &result, &issued_error)) + { + Expression* ret = result.expression(loc); + Type_context subcontext(this->type_, this->type_->is_abstract()); + ret->determine_type(gogo, &subcontext); + ret->check_types(gogo); + return ret; + } else if (issued_error) return Expression::make_error(this->location()); } @@ -4852,24 +5140,9 @@ Unary_expression::do_flatten(Gogo* gogo, Named_object*, bool Unary_expression::do_is_constant() const { - if (this->op_ == OPERATOR_MULT) - { - // Indirecting through a pointer is only constant if the object - // to which the expression points is constant, but we currently - // have no way to determine that. - return false; - } - else if (this->op_ == OPERATOR_AND) + if (this->op_ == OPERATOR_MULT || this->op_ == OPERATOR_AND) { - // Taking the address of a variable is constant if it is a - // global variable, not constant otherwise. In other cases taking the - // address is probably not a constant. - Var_expression* ve = this->expr_->var_expression(); - if (ve != NULL) - { - Named_object* no = ve->named_object(); - return no->is_variable() && no->var_value()->is_global(); - } + // These are not constant by Go language rules. return false; } else @@ -4879,6 +5152,9 @@ Unary_expression::do_is_constant() const bool Unary_expression::do_is_untyped(Type** ptype) const { + if (this->type_ != NULL) + return Expression::is_untyped_type(this->type_, ptype); + if (this->op_ == OPERATOR_MULT || this->op_ == OPERATOR_AND) return false; return this->expr_->is_untyped(ptype); @@ -4981,7 +5257,8 @@ Unary_expression::requires_nil_check(Gogo* gogo) // *ISSUED_ERROR. bool -Unary_expression::eval_constant(Operator op, const Numeric_constant* unc, +Unary_expression::eval_constant(Type* type, Operator op, + const Numeric_constant* unc, Location location, Numeric_constant* nc, bool* issued_error) { @@ -5002,7 +5279,12 @@ Unary_expression::eval_constant(Operator op, const Numeric_constant* unc, mpfr_t val; mpfr_init(val); mpfr_neg(val, uval, MPFR_RNDN); - nc->set_float(unc->type(), val); + Type* utype = unc->type(); + if (type != NULL + && type->is_abstract() + && type->is_numeric_type()) + utype = type; + nc->set_float(utype, val); mpfr_clear(uval); mpfr_clear(val); return true; @@ -5014,7 +5296,12 @@ Unary_expression::eval_constant(Operator op, const Numeric_constant* unc, mpc_t val; mpc_init2(val, mpc_precision); mpc_neg(val, uval, MPC_RNDNN); - nc->set_complex(unc->type(), val); + Type* utype = unc->type(); + if (type != NULL + && type->is_abstract() + && type->is_numeric_type()) + utype = type; + nc->set_complex(utype, val); mpc_clear(uval); mpc_clear(val); return true; @@ -5143,12 +5430,19 @@ Unary_expression::eval_constant(Operator op, const Numeric_constant* unc, bool Unary_expression::do_numeric_constant_value(Numeric_constant* nc) { + if (this->is_error_expression()) + return false; + 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, &issued_error); + bool r = Unary_expression::eval_constant(this->type_, this->op_, &unc, + this->location(), nc, + &issued_error); + if (issued_error) + this->set_is_error(); + return r; } // Return the boolean constant value of a unary expression, if it has one. @@ -5170,29 +5464,36 @@ Unary_expression::do_boolean_constant_value(bool* val) Type* Unary_expression::do_type() { - switch (this->op_) + if (this->type_ == NULL) { - case OPERATOR_PLUS: - case OPERATOR_MINUS: - case OPERATOR_NOT: - case OPERATOR_XOR: - return this->expr_->type(); + switch (this->op_) + { + case OPERATOR_AND: + return Type::make_pointer_type(this->expr_->type()); - case OPERATOR_AND: - return Type::make_pointer_type(this->expr_->type()); + case OPERATOR_MULT: + { + if (this->expr_->is_type_expression()) + return Type::make_pointer_type(this->expr_->type()); - case OPERATOR_MULT: - { - Type* subtype = this->expr_->type(); - Type* points_to = subtype->points_to(); - if (points_to == NULL) - return Type::make_error_type(); - return points_to; - } + Type* subtype = this->expr_->type(); + Type* points_to = subtype->points_to(); + if (points_to == NULL) + { + this->report_error(_("expected pointer")); + this->type_ = Type::make_error_type(); + return this->type_; + } + return points_to; + } - default: - go_unreachable(); + default: + go_assert(saw_errors()); + return Type::make_error_type(); + } } + + return this->type_; } // Determine abstract types for a unary expression. @@ -5206,7 +5507,39 @@ Unary_expression::do_determine_type(Gogo* gogo, const Type_context* context) case OPERATOR_MINUS: case OPERATOR_NOT: case OPERATOR_XOR: - this->expr_->determine_type(gogo, context); + { + if (this->type_ != NULL) + return; + + Type* dummy; + Type_context subcontext(*context); + if (this->expr_->is_untyped(&dummy) && this->expr_->is_constant()) + { + // We evaluate an untyped operator as untyped. Then we + // convert it to the desired type. Otherwise we may, for + // example, give a useless error for one more than the + // most positive integer when it is the operand of a unary + // minus. + subcontext.type = NULL; + subcontext.may_be_abstract = true; + } + this->expr_->determine_type(gogo, &subcontext); + + this->type_ = this->expr_->type(); + + // If this is an untyped expression in a typed context, use + // the context type. If this doesn't work we'll report an + // error later. + if (this->type_->is_abstract() + && !context->may_be_abstract + && context->type != NULL) + { + if (context->type->interface_type() == NULL) + this->type_ = context->type; + else + this->type_ = this->type_->make_non_abstract_type(); + } + } break; case OPERATOR_AND: @@ -5221,8 +5554,14 @@ Unary_expression::do_determine_type(Gogo* gogo, const Type_context* context) break; case OPERATOR_MULT: - // Indirecting through a pointer. { + if (this->expr_->is_type_expression()) + { + this->expr_->determine_type_no_context(gogo); + return; + } + + // Indirecting through a pointer. Type* subtype = (context->type == NULL ? NULL : Type::make_pointer_type(context->type)); @@ -5241,6 +5580,9 @@ Unary_expression::do_determine_type(Gogo* gogo, const Type_context* context) void Unary_expression::do_check_types(Gogo*) { + if (this->is_error_expression()) + return; + Type* type = this->expr_->type(); if (type->is_error()) { @@ -5282,6 +5624,19 @@ Unary_expression::do_check_types(Gogo*) break; case OPERATOR_MULT: + if (this->expr_->is_type_expression()) + break; + + // Catching an invalid indirection of unsafe.Pointer here avoid + // having to deal with TYPE_VOID in other places. + if (this->expr_->type()->is_unsafe_pointer_type()) + { + go_error_at(this->location(), + "invalid indirect of %<unsafe.Pointer%>"); + this->set_is_error(); + return; + } + // Indirecting through a pointer. if (type->points_to() == NULL) this->report_error(_("expected pointer")); @@ -5330,11 +5685,13 @@ Unary_expression::do_get_backend(Translate_context* context) Bexpression* ret; Bexpression* bexpr = this->expr_->get_backend(context); - Btype* btype = this->expr_->type()->get_backend(gogo); + Btype* btype = (this->type_ == NULL + ? this->expr_->type()->get_backend(gogo) + : this->type_->get_backend(gogo)); switch (this->op_) { case OPERATOR_PLUS: - ret = bexpr; + ret = gogo->backend()->convert_expression(btype, bexpr, loc); break; case OPERATOR_MINUS: @@ -5345,6 +5702,7 @@ Unary_expression::do_get_backend(Translate_context* context) case OPERATOR_NOT: case OPERATOR_XOR: ret = gogo->backend()->unary_expression(this->op_, bexpr, loc); + ret = gogo->backend()->convert_expression(btype, ret, loc); break; case OPERATOR_AND: @@ -5485,6 +5843,7 @@ Unary_expression::do_get_backend(Translate_context* context) nil, loc); Expression* crash = Runtime::make_call(gogo, Runtime::PANIC_MEM, loc, 0); + crash->determine_type_no_context(gogo); Bexpression* bcrash = crash->get_backend(context); Bfunction* bfn = context->function()->func_value()->get_decl(); bexpr = gogo->backend()->conditional_expression(bfn, btype, @@ -5999,19 +6358,20 @@ Binary_expression::eval_constant(Operator op, Numeric_constant* left_nc, if (!is_shift && !right_nc->set_type(type, true, location)) return false; if (is_shift - && ((left_type->integer_type() == NULL - && !left_type->is_abstract()) - || (right_type->integer_type() == NULL - && !right_type->is_abstract()))) + && right_type->integer_type() == NULL + && !right_type->is_abstract()) return false; bool r; if (type->complex_type() != NULL) - r = Binary_expression::eval_complex(op, left_nc, right_nc, location, nc); + r = Binary_expression::eval_complex(op, left_nc, right_nc, location, nc, + issued_error); else if (type->float_type() != NULL) - r = Binary_expression::eval_float(op, left_nc, right_nc, location, nc); + r = Binary_expression::eval_float(op, left_nc, right_nc, location, nc, + issued_error); else - r = Binary_expression::eval_integer(op, left_nc, right_nc, location, nc); + r = Binary_expression::eval_integer(op, left_nc, right_nc, location, nc, + issued_error); if (r) { @@ -6030,7 +6390,8 @@ Binary_expression::eval_constant(Operator op, Numeric_constant* left_nc, bool Binary_expression::eval_integer(Operator op, const Numeric_constant* left_nc, const Numeric_constant* right_nc, - Location location, Numeric_constant* nc) + Location location, Numeric_constant* nc, + bool* issued_error) { mpz_t left_val; if (!left_nc->to_int(&left_val)) @@ -6054,6 +6415,7 @@ Binary_expression::eval_integer(Operator op, const Numeric_constant* left_nc, go_error_at(location, "constant addition overflow"); nc->set_invalid(); mpz_set_ui(val, 1); + *issued_error = true; } break; case OPERATOR_MINUS: @@ -6063,6 +6425,7 @@ Binary_expression::eval_integer(Operator op, const Numeric_constant* left_nc, go_error_at(location, "constant subtraction overflow"); nc->set_invalid(); mpz_set_ui(val, 1); + *issued_error = true; } break; case OPERATOR_OR: @@ -6078,6 +6441,7 @@ Binary_expression::eval_integer(Operator op, const Numeric_constant* left_nc, go_error_at(location, "constant multiplication overflow"); nc->set_invalid(); mpz_set_ui(val, 1); + *issued_error = true; } break; case OPERATOR_DIV: @@ -6088,6 +6452,7 @@ Binary_expression::eval_integer(Operator op, const Numeric_constant* left_nc, go_error_at(location, "division by zero"); nc->set_invalid(); mpz_set_ui(val, 0); + *issued_error = true; } break; case OPERATOR_MOD: @@ -6098,6 +6463,7 @@ Binary_expression::eval_integer(Operator op, const Numeric_constant* left_nc, go_error_at(location, "division by zero"); nc->set_invalid(); mpz_set_ui(val, 0); + *issued_error = true; } break; case OPERATOR_LSHIFT: @@ -6110,6 +6476,7 @@ Binary_expression::eval_integer(Operator op, const Numeric_constant* left_nc, go_error_at(location, "shift count overflow"); nc->set_invalid(); mpz_set_ui(val, 1); + *issued_error = true; } break; } @@ -6122,6 +6489,7 @@ Binary_expression::eval_integer(Operator op, const Numeric_constant* left_nc, go_error_at(location, "shift count overflow"); nc->set_invalid(); mpz_set_ui(val, 1); + *issued_error = true; } else { @@ -6172,7 +6540,8 @@ Binary_expression::eval_integer(Operator op, const Numeric_constant* left_nc, bool Binary_expression::eval_float(Operator op, const Numeric_constant* left_nc, const Numeric_constant* right_nc, - Location location, Numeric_constant* nc) + Location location, Numeric_constant* nc, + bool* issued_error) { mpfr_t left_val; if (!left_nc->to_float(&left_val)) @@ -6217,6 +6586,7 @@ Binary_expression::eval_float(Operator op, const Numeric_constant* left_nc, go_error_at(location, "division by zero"); nc->set_invalid(); mpfr_set_ui(val, 0, MPFR_RNDN); + *issued_error = true; } break; default: @@ -6239,7 +6609,8 @@ Binary_expression::eval_float(Operator op, const Numeric_constant* left_nc, bool Binary_expression::eval_complex(Operator op, const Numeric_constant* left_nc, const Numeric_constant* right_nc, - Location location, Numeric_constant* nc) + Location location, Numeric_constant* nc, + bool* issued_error) { mpc_t left_val; if (!left_nc->to_complex(&left_val)) @@ -6282,6 +6653,7 @@ Binary_expression::eval_complex(Operator op, const Numeric_constant* left_nc, go_error_at(location, "division by zero"); nc->set_invalid(); mpc_set_ui(val, 0, MPC_RNDNN); + *issued_error = true; break; } mpc_div(val, left_val, right_val, MPC_RNDNN); @@ -6308,10 +6680,17 @@ Binary_expression::do_lower(Gogo* gogo, Named_object*, Statement_inserter* inserter, int) { Location location = this->location(); + + if (this->is_error_expression()) + return Expression::make_error(location); + Operator op = this->op_; Expression* left = this->left_; Expression* right = this->right_; + if (left->is_error_expression() || right->is_error_expression()) + return Expression::make_error(location); + const bool is_comparison = (op == OPERATOR_EQEQ || op == OPERATOR_NOTEQ || op == OPERATOR_LT @@ -6326,6 +6705,7 @@ Binary_expression::do_lower(Gogo* gogo, Named_object*, if (left->numeric_constant_value(&left_nc) && right->numeric_constant_value(&right_nc)) { + Expression* ret; if (is_comparison) { bool result; @@ -6333,7 +6713,7 @@ Binary_expression::do_lower(Gogo* gogo, Named_object*, &right_nc, location, &result)) return this; - return Expression::make_boolean(result, location); + ret = Expression::make_boolean(result, location); } else { @@ -6347,8 +6727,13 @@ Binary_expression::do_lower(Gogo* gogo, Named_object*, return Expression::make_error(location); return this; } - return nc.expression(location); + ret = nc.expression(location); } + + Type_context subcontext(this->type_, this->type_->is_abstract()); + ret->determine_type(gogo, &subcontext); + ret->check_types(gogo); + return ret; } } @@ -6369,15 +6754,13 @@ Binary_expression::do_lower(Gogo* gogo, Named_object*, if (left->string_constant_value(&left_string) && right->string_constant_value(&right_string)) { + Expression* ret = NULL; if (op == OPERATOR_PLUS) { - Type* result_type = (left->type()->named_type() != NULL - ? left->type() - : right->type()); delete left; delete right; - return Expression::make_string_typed(left_string + right_string, - result_type, location); + ret = Expression::make_string_typed(left_string + right_string, + this->type_, location); } else if (is_comparison) { @@ -6385,7 +6768,15 @@ Binary_expression::do_lower(Gogo* gogo, Named_object*, bool r = Binary_expression::cmp_to_bool(op, cmp); delete left; delete right; - return Expression::make_boolean(r, location); + ret = Expression::make_boolean(r, location); + } + + if (ret != NULL) + { + Type_context subcontext(this->type_, this->type_->is_abstract()); + ret->determine_type(gogo, &subcontext); + ret->check_types(gogo); + return ret; } } } @@ -6515,6 +6906,8 @@ Binary_expression::lower_struct_comparison(Gogo* gogo, if (this->op_ == OPERATOR_NOTEQ) ret = Expression::make_unary(OPERATOR_NOT, ret, loc); + ret->determine_type_no_context(gogo); + return ret; } @@ -6572,6 +6965,8 @@ Binary_expression::lower_array_comparison(Gogo* gogo, if (this->op_ == OPERATOR_NOTEQ) ret = Expression::make_unary(OPERATOR_NOT, ret, loc); + ret->determine_type_no_context(gogo); + return ret; } @@ -6643,7 +7038,10 @@ Binary_expression::lower_compare_to_memcmp(Gogo* gogo, a1, a2, len); Type* int32_type = Type::lookup_integer_type("int32"); Expression* zero = Expression::make_integer_ul(0, int32_type, loc); - return Expression::make_binary(this->op_, call, zero, loc); + Expression* ret = Expression::make_binary(this->op_, call, zero, loc); + Type_context context(this->type_, this->type_->is_abstract()); + ret->determine_type(gogo, &context); + return ret; } Expression* @@ -6735,6 +7133,9 @@ Binary_expression::operand_address(Statement_inserter* inserter, bool Binary_expression::do_numeric_constant_value(Numeric_constant* nc) { + if (this->is_error_expression()) + return false; + Numeric_constant left_nc; if (!this->left_->numeric_constant_value(&left_nc)) return false; @@ -6742,8 +7143,12 @@ Binary_expression::do_numeric_constant_value(Numeric_constant* 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, &issued_error); + bool r = Binary_expression::eval_constant(this->op_, &left_nc, &right_nc, + this->location(), nc, + &issued_error); + if (issued_error) + this->set_is_error(); + return r; } // Return the boolean constant value, if it has one. @@ -6751,6 +7156,9 @@ Binary_expression::do_numeric_constant_value(Numeric_constant* nc) bool Binary_expression::do_boolean_constant_value(bool* val) { + if (this->is_error_expression()) + return false; + bool is_comparison = false; switch (this->op_) { @@ -6845,49 +7253,13 @@ Binary_expression::do_discarding_value() Type* Binary_expression::do_type() { - if (this->classification() == EXPRESSION_ERROR) - return Type::make_error_type(); - - switch (this->op_) + if (this->type_ == NULL) { - case OPERATOR_EQEQ: - case OPERATOR_NOTEQ: - case OPERATOR_LT: - case OPERATOR_LE: - case OPERATOR_GT: - case OPERATOR_GE: - if (this->type_ == NULL) - this->type_ = Type::make_boolean_type(); - return this->type_; - - case OPERATOR_PLUS: - case OPERATOR_MINUS: - case OPERATOR_OR: - case OPERATOR_XOR: - case OPERATOR_MULT: - case OPERATOR_DIV: - case OPERATOR_MOD: - case OPERATOR_AND: - case OPERATOR_BITCLEAR: - case OPERATOR_OROR: - case OPERATOR_ANDAND: - { - Type* type; - if (!Binary_expression::operation_type(this->op_, - this->left_->type(), - this->right_->type(), - &type)) - return Type::make_error_type(); - return type; - } - - case OPERATOR_LSHIFT: - case OPERATOR_RSHIFT: - return this->left_->type(); - - default: - go_unreachable(); + go_assert(saw_errors()); + return Type::make_error_type(); } + + return this->type_; } // Set type for a binary expression. @@ -6895,16 +7267,17 @@ Binary_expression::do_type() void Binary_expression::do_determine_type(Gogo* gogo, const Type_context* context) { - Type* tleft = this->left_->type(); - Type* tright = this->right_->type(); - - // Both sides should have the same type, except for the shift - // operations. For a comparison, we should ignore the incoming - // type. + if (this->type_ != NULL) + return; + // For a shift operation, the type of the binary expression is the + // type of the left operand. If the left operand is a constant, + // then it gets its type from the context. bool is_shift_op = (this->op_ == OPERATOR_LSHIFT || this->op_ == OPERATOR_RSHIFT); + // For a comparison operation, the type of the binary expression is + // a boolean type. bool is_comparison = (this->op_ == OPERATOR_EQEQ || this->op_ == OPERATOR_NOTEQ || this->op_ == OPERATOR_LT @@ -6917,13 +7290,49 @@ Binary_expression::do_determine_type(Gogo* gogo, const Type_context* context) // boolean, numeric, and string constants as operands where it is legal to // use non-abstract boolean, numeric, and string constants, respectively. // Any issues with the operation will be resolved in the check_types pass. - bool is_constant_expr = (this->left_->is_constant() - && this->right_->is_constant()); + bool left_is_constant = this->left_->is_constant(); + bool right_is_constant = this->right_->is_constant(); + bool is_constant_expr = left_is_constant && right_is_constant; Type_context subcontext(*context); + if (is_comparison) + subcontext.type = NULL; + + Type* tleft; + bool left_is_untyped = this->left_->is_untyped(&tleft); + if (!left_is_untyped) + { + this->left_->determine_type(gogo, &subcontext); + tleft = this->left_->type(); + } + + Type* tright; + bool right_is_untyped = this->right_->is_untyped(&tright); + if (!right_is_untyped) + { + // For a shift operation, the right operand should always be an + // integer. + if (is_shift_op) + { + subcontext.type = Type::lookup_integer_type("uint"); + subcontext.may_be_abstract = false; + } - if (is_constant_expr && !is_shift_op) + this->right_->determine_type(gogo, &subcontext); + tright = this->right_->type(); + } + + // For each operand we have the real type or, if the operand is a + // untyped, a guess at the type. Use this to determine the types of + // untyped operands. + + subcontext = *context; + if (left_is_untyped && (right_is_untyped || is_shift_op) && is_constant_expr) { + // We evaluate the operands of an untyped expression as untyped + // values. Then we convert to the desired type. Otherwise we + // may, for example, mishandle a floating-point constant + // division as an integer division. subcontext.type = NULL; subcontext.may_be_abstract = true; } @@ -6935,10 +7344,15 @@ Binary_expression::do_determine_type(Gogo* gogo, const Type_context* context) } // Set the context for the left hand operand. + if (is_shift_op) { // The right hand operand of a shift plays no role in // determining the type of the left hand operand. + if (subcontext.type == NULL + && right_is_constant + && context->may_be_abstract) + subcontext.type = Type::make_abstract_integer_type(); } else if (!tleft->is_abstract()) subcontext.type = tleft; @@ -6965,22 +7379,26 @@ Binary_expression::do_determine_type(Gogo* gogo, const Type_context* context) subcontext.type = tright; else subcontext.type = tleft; - - if (subcontext.type != NULL && !context->may_be_abstract) - subcontext.type = subcontext.type->make_non_abstract_type(); } - this->left_->determine_type(gogo, &subcontext); + if (left_is_untyped) + { + this->left_->determine_type(gogo, &subcontext); + tleft = this->left_->type(); + } if (is_shift_op) { // We may have inherited an unusable type for the shift operand. // Give a useful error if that happened. - if (tleft->is_abstract() + if (left_is_untyped + && !is_constant_expr && subcontext.type != NULL && !subcontext.may_be_abstract && subcontext.type->interface_type() == NULL - && subcontext.type->integer_type() == NULL) + && subcontext.type->integer_type() == NULL + && !tleft->is_error() + && !tright->is_error()) this->report_error(("invalid context-determined non-integer type " "for left operand of shift")); @@ -6990,16 +7408,76 @@ Binary_expression::do_determine_type(Gogo* gogo, const Type_context* context) subcontext.may_be_abstract = false; } - this->right_->determine_type(gogo, &subcontext); + if (right_is_untyped) + { + this->right_->determine_type(gogo, &subcontext); + tright = this->right_->type(); + } + + if (this->left_->is_error_expression() + || tleft->is_error() + || this->right_->is_error_expression() + || tright->is_error()) + { + this->set_is_error(); + return; + } if (is_comparison) { - if (this->type_ != NULL && !this->type_->is_abstract()) - ; - else if (context->type != NULL && context->type->is_boolean_type()) + if (context->type != NULL && context->type->is_boolean_type()) this->type_ = context->type; else if (!context->may_be_abstract) this->type_ = Type::lookup_bool_type(); + else + this->type_ = Type::make_boolean_type(); + } + else + { + if (is_shift_op) + { + // Shifts only work with integers, so force an abstract + // floating-point type (such as 1.0 << 1) into an integer. + if (tleft->is_abstract() + && tleft->integer_type() == NULL + && context->type == NULL) + { + this->type_ = Type::make_abstract_integer_type(); + if (!context->may_be_abstract) + this->type_ = this->type_->make_non_abstract_type(); + } + else + this->type_ = tleft; + } + else + { + if (!Binary_expression::operation_type(this->op_, tleft, tright, + &this->type_)) + { + this->report_error("incompatible types in binary expression"); + this->type_ = Type::make_error_type(); + return; + } + } + + // If this is an untyped expression in a typed context, use the + // context type. If this doesn't work we'll report an error + // later. + if (this->type_->is_abstract() + && !context->may_be_abstract + && context->type != NULL) + { + if (context->type->interface_type() == NULL + && ((this->type_->is_numeric_type() + && context->type->is_numeric_type()) + || (this->type_->is_string_type() + && context->type->is_string_type()) + || (this->type_->is_boolean_type() + && context->type->is_boolean_type()))) + this->type_ = context->type; + else if (context->type->interface_type() != NULL) + this->type_ = this->type_->make_non_abstract_type(); + } } } @@ -7173,7 +7651,9 @@ Binary_expression::do_check_types(Gogo*) } else { - if (left_type->integer_type() == NULL) + if (left_type->integer_type() == NULL + && !left_type->is_abstract() + && !this->is_constant()) this->report_error(_("shift of non-integer operand")); if (right_type->is_string_type()) @@ -7344,6 +7824,7 @@ Binary_expression::do_get_backend(Translate_context* context) loc); Expression* crash = Runtime::make_call(gogo, Runtime::PANIC_SHIFT, loc, 0); + crash->determine_type_no_context(gogo); Bexpression* bcrash = crash->get_backend(context); Bfunction* bfn = context->function()->func_value()->get_decl(); ret = gogo->backend()->conditional_expression(bfn, btype, compare, @@ -7365,6 +7846,7 @@ Binary_expression::do_get_backend(Translate_context* context) Expression* crash = Runtime::make_call(gogo, Runtime::PANIC_DIVIDE, loc, 0); + crash->determine_type_no_context(gogo); Bexpression* bcrash = crash->get_backend(context); // right == 0 ? (panicdivide(), 0) : ret @@ -7748,13 +8230,12 @@ Expression::comparison(Translate_context* context, Type* result_type, Expression* descriptor = Expression::make_type_descriptor(right_type, location); - left = - Runtime::make_call(gogo, - (left_type->interface_type()->is_empty() - ? Runtime::EFACEVALEQ - : Runtime::IFACEVALEQ), - location, 3, left, descriptor, - pointer_arg); + left = Runtime::make_call(gogo, + (left_type->interface_type()->is_empty() + ? Runtime::EFACEVALEQ + : Runtime::IFACEVALEQ), + location, 3, left, descriptor, + pointer_arg); go_assert(op == OPERATOR_EQEQ || op == OPERATOR_NOTEQ); right = Expression::make_boolean(true, location); } @@ -7809,6 +8290,9 @@ Expression::comparison(Translate_context* context, Type* result_type, } } + left->determine_type_no_context(gogo); + right->determine_type_no_context(gogo); + Bexpression* left_bexpr = left->get_backend(context); Bexpression* right_bexpr = right->get_backend(context); @@ -8015,13 +8499,17 @@ String_concat_expression::do_flatten(Gogo* gogo, Named_object*, loc); Temporary_statement* ts = Statement::make_temporary(array_type, array, loc); + ts->determine_types(gogo); inserter->insert(ts); Expression* ref = Expression::make_temporary_reference(ts, loc); ref = Expression::make_unary(OPERATOR_AND, ref, loc); - Expression* call = - Runtime::make_call(gogo, Runtime::CONCATSTRINGS, loc, 3, - buf, ref, len->copy()); - return Expression::make_cast(type, call, loc); + Expression* call = + Runtime::make_call(gogo, Runtime::CONCATSTRINGS, loc, 3, buf, + ref, len->copy()); + Expression* ret = Expression::make_cast(type, call, loc); + Type_context context(type, false); + ret->determine_type(gogo, &context); + return ret; } void @@ -8093,7 +8581,7 @@ Bound_method_expression::do_determine_type(Gogo* gogo, const Type_context*) void Bound_method_expression::do_check_types(Gogo*) { - Named_object* fn = this->method_->named_object(); + Named_object* fn = this->function(); if (!fn->is_function() && !fn->is_function_declaration()) { this->report_error(_("object is not a method")); @@ -8223,12 +8711,13 @@ Bound_method_expression::create_thunk(Gogo* gogo, const Method* method, loc); call->set_varargs_are_lowered(); - Statement* s = Statement::make_return_from_call(call, loc); + Statement* s = Statement::make_return_from_call(new_no, call, loc); + s->determine_types(gogo); gogo->add_statement(s); Block* b = gogo->finish_block(loc); gogo->add_block(b, loc); - // This is called after lowering but before determine_types. + // This is called after lowering. gogo->lower_block(new_no, b); gogo->finish_function(loc); @@ -8388,6 +8877,7 @@ Bound_method_expression::do_flatten(Gogo* gogo, Named_object*, Expression* crash = Runtime::make_call(gogo, Runtime::PANIC_MEM, loc, 0); // Fix the type of the conditional expression by pretending to // evaluate to RET either way through the conditional. + crash->determine_type_no_context(gogo); crash = Expression::make_compound(crash, ret, loc); ret = Expression::make_conditional(nil_check, crash, ret, loc); } @@ -8395,6 +8885,8 @@ Bound_method_expression::do_flatten(Gogo* gogo, Named_object*, // RET is a pointer to a struct, but we want a function type. ret = Expression::make_unsafe_cast(this->type(), ret, loc); + ret->determine_type_no_context(gogo); + return ret; } @@ -8435,14 +8927,33 @@ class Selector_expression : public Parser_expression Selector_expression(Expression* left, const std::string& name, Location location) : Parser_expression(EXPRESSION_SELECTOR, location), - left_(left), name_(name) + left_(left), name_(name), resolved_(NULL) { } + // Return the resolved selector. This will typically be a + // Field_reference_expression or a Bound_method_expression or an + // Interface_field_reference_expression. + Expression* + resolved() + { return this->resolved_; } + protected: int do_traverse(Traverse* traverse) { return Expression::traverse(&this->left_, traverse); } + Type* + do_type(); + + void + do_determine_type(Gogo*, const Type_context*); + + bool + do_is_addressable() const; + + void + do_issue_nil_check(); + Expression* do_lower(Gogo*, Named_object*, Statement_inserter*, int); @@ -8464,20 +8975,66 @@ class Selector_expression : public Parser_expression Expression* left_; // The name on the right hand side. std::string name_; + // The resolved expression. + Expression* resolved_; }; -// Lower a selector expression once we know the real type of the left -// hand side. +void +Selector_expression::do_determine_type(Gogo* gogo, const Type_context* context) +{ + if (this->is_error_expression() || this->resolved_ != NULL) + return; + Expression* left = this->left_; + left->determine_type_no_context(gogo); + if (left->is_error_expression()) + this->set_is_error(); + else + { + if (left->is_type_expression()) + this->resolved_ = this->lower_method_expression(gogo); + else + this->resolved_ = Type::bind_field_or_method(gogo, left->type(), left, + this->name_, + this->location()); + this->resolved_->determine_type(gogo, context); + } +} + +Type* +Selector_expression::do_type() +{ + if (this->is_error_expression()) + return Type::make_error_type(); + go_assert(this->resolved_ != NULL); + return this->resolved_->type(); +} + +bool +Selector_expression::do_is_addressable() const +{ + if (this->is_error_expression()) + return true; + go_assert(this->resolved_ != NULL); + return this->resolved_->is_addressable(); +} + +void +Selector_expression::do_issue_nil_check() +{ + if (this->is_error_expression()) + return; + go_assert(this->resolved_ != NULL); + this->resolved_->issue_nil_check(); +} + +// Lower a selector expression to the resolved value. Expression* -Selector_expression::do_lower(Gogo* gogo, Named_object*, Statement_inserter*, - int) +Selector_expression::do_lower(Gogo*, Named_object*, Statement_inserter*, int) { - Expression* left = this->left_; - if (left->is_type_expression()) - return this->lower_method_expression(gogo); - return Type::bind_field_or_method(gogo, left->type(), left, this->name_, - this->location()); + if (this->is_error_expression() || this->resolved_ == NULL) + return Expression::make_error(this->location()); + return this->resolved_; } // Lower a method expression T.M or (*T).M. We turn this into a @@ -8671,17 +9228,14 @@ Selector_expression::lower_method_expression(Gogo* gogo) method_type->is_varargs(), location); - Statement* s = Statement::make_return_from_call(call, location); + Statement* s = Statement::make_return_from_call(no, call, location); + s->determine_types(gogo); gogo->add_statement(s); Block* b = gogo->finish_block(location); gogo->add_block(b, location); - // Lower the call in case there are multiple results. - gogo->lower_block(no, b); - gogo->flatten_block(no, b); - gogo->finish_function(location); return Expression::make_func_reference(no, NULL, location); @@ -8719,13 +9273,20 @@ Builtin_call_expression::Builtin_call_expression(Gogo* gogo, gogo_(gogo), code_(BUILTIN_INVALID), seen_(false), recover_arg_is_set_(false) { - Func_expression* fnexp = this->fn()->func_expression(); - if (fnexp == NULL) + const Named_object* no; + if (fn->is_error_expression()) { this->code_ = BUILTIN_INVALID; return; } - const std::string& name(fnexp->named_object()->name()); + else if (fn->func_expression() != NULL) + no = fn->func_expression()->named_object(); + else if (fn->unknown_expression() != NULL) + no = fn->unknown_expression()->named_object(); + else + go_unreachable(); + + const std::string& name(no->name()); if (name == "append") this->code_ = BUILTIN_APPEND; else if (name == "cap") @@ -8806,24 +9367,9 @@ Builtin_call_expression::do_lower(Gogo* gogo, Named_object* function, Location loc = this->location(); - if (this->is_varargs() && this->code_ != BUILTIN_APPEND) - { - this->report_error(_("invalid use of %<...%> with builtin function")); - return Expression::make_error(loc); - } - if (this->code_ == BUILTIN_OFFSETOF) { Expression* arg = this->one_arg(); - - if (arg->bound_method_expression() != NULL - || arg->interface_field_reference_expression() != NULL) - { - this->report_error(_("invalid use of method value as argument " - "of Offsetof")); - return this; - } - Field_reference_expression* farg = arg->field_reference_expression(); while (farg != NULL) { @@ -8846,7 +9392,15 @@ Builtin_call_expression::do_lower(Gogo* gogo, Named_object* function, { Numeric_constant nc; if (this->numeric_constant_value(&nc)) - return nc.expression(loc); + { + Expression* ret = nc.expression(loc); + Type_context subcontext; + if (this->type() != NULL) + subcontext = Type_context(this->type(), + this->type()->is_abstract()); + ret->determine_type(gogo, &subcontext); + return ret; + } } switch (this->code_) @@ -8855,25 +9409,7 @@ Builtin_call_expression::do_lower(Gogo* gogo, Named_object* function, break; case BUILTIN_NEW: - { - const Expression_list* args = this->args(); - if (args == NULL || args->size() < 1) - this->report_error(_("not enough arguments")); - else if (args->size() > 1) - this->report_error(_("too many arguments")); - else - { - Expression* arg = args->front(); - if (!arg->is_type_expression()) - { - go_error_at(arg->location(), "expected type"); - this->set_is_error(); - } - else - return Expression::make_allocation(arg->type(), loc); - } - } - break; + return Expression::make_allocation(this->one_arg()->type(), loc); case BUILTIN_MAKE: return this->lower_make(gogo, inserter); @@ -8893,32 +9429,13 @@ Builtin_call_expression::do_lower(Gogo* gogo, Named_object* function, case BUILTIN_DELETE: { const Expression_list* args = this->args(); - if (args == NULL || args->size() < 2) - this->report_error(_("not enough arguments")); - else if (args->size() > 2) - this->report_error(_("too many arguments")); - else if (args->front()->type()->map_type() == NULL) - this->report_error(_("argument 1 must be a map")); - else - { - Type* key_type = - args->front()->type()->map_type()->key_type(); - Expression_list::iterator pa = this->args()->begin(); - pa++; - Type* arg_type = (*pa)->type(); - std::string reason; - if (!Type::are_assignable(key_type, arg_type, &reason)) - { - if (reason.empty()) - go_error_at(loc, "argument 2 has incompatible type"); - else - go_error_at(loc, "argument 2 has incompatible type (%s)", - reason.c_str()); - this->set_is_error(); - } - else if (!Type::are_identical(key_type, arg_type, 0, NULL)) - *pa = Expression::make_cast(key_type, *pa, loc); - } + Type* key_type = + args->front()->type()->map_type()->key_type(); + Expression_list::iterator pa = this->args()->begin(); + pa++; + Type* arg_type = (*pa)->type(); + if (!Type::are_identical(key_type, arg_type, 0, NULL)) + *pa = Expression::make_cast(key_type, *pa, loc); } break; @@ -9036,6 +9553,7 @@ Builtin_call_expression::do_flatten(Gogo* gogo, Named_object* function, gogo->lower_expression(function, inserter, &len1); gogo->flatten_expression(function, inserter, &len1); Temporary_statement* l1tmp = Statement::make_temporary(int_type, len1, loc); + l1tmp->determine_types(gogo); inserter->insert(l1tmp); // l2 = len(arg2) @@ -9045,6 +9563,7 @@ Builtin_call_expression::do_flatten(Gogo* gogo, Named_object* function, gogo->lower_expression(function, inserter, &len2); gogo->flatten_expression(function, inserter, &len2); Temporary_statement* l2tmp = Statement::make_temporary(int_type, len2, loc); + l2tmp->determine_types(gogo); inserter->insert(l2tmp); // n = (l1 < l2 ? l1 : l2) @@ -9056,6 +9575,7 @@ Builtin_call_expression::do_flatten(Gogo* gogo, Named_object* function, l2ref->copy(), loc); Temporary_statement* ntmp = Statement::make_temporary(NULL, n, loc); + ntmp->determine_types(gogo); inserter->insert(ntmp); // sz = n * sizeof(elem_type) @@ -9084,6 +9604,7 @@ Builtin_call_expression::do_flatten(Gogo* gogo, Named_object* function, nref = Expression::make_temporary_reference(ntmp, loc); ret = Expression::make_compound(call, nref, loc); } + ret->determine_type_no_context(gogo); return ret; } break; @@ -9196,18 +9717,22 @@ Builtin_call_expression::do_flatten(Gogo* gogo, Named_object* function, loc); Temporary_statement* atemp = Statement::make_temporary(NULL, a, loc); + atemp->determine_types(gogo); inserter->insert(atemp); a = Expression::make_temporary_reference(atemp, loc); a = Expression::make_dereference(a, NIL_CHECK_NOT_NEEDED, loc); Statement* s = Statement::make_assignment(a, e3, loc); + s->determine_types(gogo); inserter->insert(s); e3 = Expression::make_temporary_reference(atemp, loc); } } - return Runtime::make_call(gogo, code, loc, 3, e1, e2, e3); + Expression* ret = Runtime::make_call(gogo, code, loc, 3, e1, e2, e3); + ret->determine_type_no_context(gogo); + return ret; } case BUILTIN_ADD: @@ -9219,7 +9744,10 @@ Builtin_call_expression::do_flatten(Gogo* gogo, Named_object* function, len = Expression::make_cast(uintptr_type, len, loc); Expression* add = Expression::make_binary(OPERATOR_PLUS, ptr, len, loc); - return Expression::make_cast(this->args()->front()->type(), add, loc); + Expression* ret = Expression::make_cast(this->args()->front()->type(), + add, loc); + ret->determine_type_no_context(gogo); + return ret; } case BUILTIN_SLICE: @@ -9320,7 +9848,9 @@ Builtin_call_expression::do_flatten(Gogo* gogo, Named_object* function, slice = Expression::make_conditional(cond, nil_slice, slice, loc); - return Expression::make_compound(check, slice, loc); + Expression* ret = Expression::make_compound(check, slice, loc); + ret->determine_type_no_context(gogo); + return ret; } } @@ -9335,27 +9865,13 @@ Builtin_call_expression::lower_make(Gogo* gogo, Statement_inserter* inserter) Location loc = this->location(); const Expression_list* args = this->args(); - if (args == NULL || args->size() < 1) - { - this->report_error(_("not enough arguments")); - return Expression::make_error(this->location()); - } Expression_list::const_iterator parg = args->begin(); Expression* first_arg = *parg; - if (!first_arg->is_type_expression()) - { - go_error_at(first_arg->location(), "expected type"); - this->set_is_error(); - return Expression::make_error(this->location()); - } + go_assert(first_arg->is_type_expression()); Type* type = first_arg->type(); - if (!type->in_heap()) - go_error_at(first_arg->location(), - "cannot make slice of go:notinheap type"); - bool is_slice = false; bool is_map = false; bool is_chan = false; @@ -9366,35 +9882,20 @@ Builtin_call_expression::lower_make(Gogo* gogo, Statement_inserter* inserter) else if (type->channel_type() != NULL) is_chan = true; else - { - this->report_error(_("invalid type for make function")); - return Expression::make_error(this->location()); - } - - Type_context int_context(Type::lookup_integer_type("int"), false); + go_unreachable(); ++parg; Expression* len_arg; bool len_small = false; if (parg == args->end()) { - if (is_slice) - { - this->report_error(_("length required when allocating a slice")); - return Expression::make_error(this->location()); - } + go_assert(!is_slice); len_arg = Expression::make_integer_ul(0, NULL, loc); len_small = true; } else { len_arg = *parg; - len_arg->determine_type(gogo, &int_context); - if (len_arg->type()->integer_type() == NULL) - { - go_error_at(len_arg->location(), "non-integer len argument in make"); - return Expression::make_error(this->location()); - } if (!this->check_int_value(len_arg, true, &len_small)) return Expression::make_error(this->location()); ++parg; @@ -9409,12 +9910,6 @@ Builtin_call_expression::lower_make(Gogo* gogo, Statement_inserter* inserter) if (is_slice && parg != args->end()) { cap_arg = *parg; - cap_arg->determine_type(gogo, &int_context); - if (cap_arg->type()->integer_type() == NULL) - { - go_error_at(cap_arg->location(), "non-integer cap argument in make"); - return Expression::make_error(this->location()); - } if (!this->check_int_value(cap_arg, false, &cap_small)) return Expression::make_error(this->location()); @@ -9431,11 +9926,7 @@ Builtin_call_expression::lower_make(Gogo* gogo, Statement_inserter* inserter) ++parg; } - if (parg != args->end()) - { - this->report_error(_("too many arguments to make")); - return Expression::make_error(this->location()); - } + go_assert(parg == args->end()); Location type_loc = first_arg->location(); @@ -9511,7 +10002,9 @@ Builtin_call_expression::lower_make(Gogo* gogo, Statement_inserter* inserter) else go_unreachable(); - return Expression::make_unsafe_cast(type, call, loc); + Expression* ret = Expression::make_unsafe_cast(type, call, loc); + ret->determine_type_no_context(gogo); + return ret; } // Flatten a call to the predeclared append function. We do this in @@ -9550,6 +10043,7 @@ Builtin_call_expression::flatten_append(Gogo* gogo, Named_object* function, } Type* int_type = Type::lookup_integer_type("int"); + Type_context int_context(int_type, false); Type* uint_type = Type::lookup_integer_type("uint"); // Implementing @@ -9568,6 +10062,7 @@ Builtin_call_expression::flatten_append(Gogo* gogo, Named_object* function, 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); + len->determine_type(gogo, &int_context); gogo->lower_expression(function, inserter, &len); gogo->flatten_expression(function, inserter, &len); Temporary_statement* l1tmp = Statement::make_temporary(int_type, len, loc); @@ -9599,12 +10094,14 @@ Builtin_call_expression::flatten_append(Gogo* gogo, Named_object* function, Expression* len_arg = makecall->args()->at(1); len_arg = Expression::make_cast(int_type, len_arg, loc); l2tmp = Statement::make_temporary(int_type, len_arg, loc); + l2tmp->determine_types(gogo); inserter->insert(l2tmp); Expression* cap_arg = makecall->args()->at(2); cap_arg = Expression::make_cast(int_type, cap_arg, loc); Temporary_statement* c2tmp = Statement::make_temporary(int_type, cap_arg, loc); + c2tmp->determine_types(gogo); inserter->insert(c2tmp); // Check bad len/cap here. @@ -9619,6 +10116,7 @@ Builtin_call_expression::flatten_append(Gogo* gogo, Named_object* function, Expression* check = Runtime::make_call(gogo, Runtime::CHECK_MAKE_SLICE, loc, 3, elem, len2, cap2); + check->determine_type_no_context(gogo); gogo->lower_expression(function, inserter, &check); gogo->flatten_expression(function, inserter, &check); Statement* s = Statement::make_statement(check, false); @@ -9640,9 +10138,11 @@ Builtin_call_expression::flatten_append(Gogo* gogo, Named_object* function, call_args = new Expression_list(); call_args->push_back(Expression::make_temporary_reference(s2tmp, loc)); len = Expression::make_call(lenref, call_args, false, loc); + len->determine_type(gogo, &int_context); gogo->lower_expression(function, inserter, &len); gogo->flatten_expression(function, inserter, &len); l2tmp = Statement::make_temporary(int_type, len, loc); + l2tmp->determine_types(gogo); inserter->insert(l2tmp); } @@ -9677,9 +10177,11 @@ Builtin_call_expression::flatten_append(Gogo* gogo, Named_object* function, // ntmp := l1tmp + len2 Expression* ref = Expression::make_temporary_reference(l1tmp, loc); Expression* sum = Expression::make_binary(OPERATOR_PLUS, ref, len2, loc); + sum->determine_type(gogo, &int_context); gogo->lower_expression(function, inserter, &sum); gogo->flatten_expression(function, inserter, &sum); Temporary_statement* ntmp = Statement::make_temporary(int_type, sum, loc); + ntmp->determine_types(gogo); inserter->insert(ntmp); // s1tmp = uint(ntmp) > uint(cap(s1tmp)) ? @@ -9693,9 +10195,11 @@ Builtin_call_expression::flatten_append(Gogo* gogo, Named_object* function, call_args = new Expression_list(); call_args->push_back(Expression::make_temporary_reference(s1tmp, loc)); Expression* cap = Expression::make_call(capref, call_args, false, loc); + cap->determine_type(gogo, &int_context); gogo->lower_expression(function, inserter, &cap); gogo->flatten_expression(function, inserter, &cap); Temporary_statement* c1tmp = Statement::make_temporary(int_type, cap, loc); + c1tmp->determine_types(gogo); inserter->insert(c1tmp); Expression* left = Expression::make_temporary_reference(ntmp, loc); @@ -9727,25 +10231,31 @@ Builtin_call_expression::flatten_append(Gogo* gogo, Named_object* function, { Expression* rhs = Expression::make_conditional(cond, call, ref, loc); + rhs->determine_type_no_context(gogo); gogo->lower_expression(function, inserter, &rhs); gogo->flatten_expression(function, inserter, &rhs); ref = Expression::make_temporary_reference(s1tmp, loc); Statement* assign = Statement::make_assignment(ref, rhs, loc); + assign->determine_types(gogo); inserter->insert(assign); } else { + cond->determine_type_no_context(gogo); gogo->lower_expression(function, inserter, &cond); gogo->flatten_expression(function, inserter, &cond); + call->determine_type_no_context(gogo); gogo->lower_expression(function, inserter, &call); gogo->flatten_expression(function, inserter, &call); + ref->determine_type_no_context(gogo); gogo->lower_expression(function, inserter, &ref); gogo->flatten_expression(function, inserter, &ref); Block* then_block = new Block(enclosing, loc); Assignment_statement* assign = Statement::make_assignment(assign_lhs, call, loc); + assign->determine_types(gogo); then_block->add_statement(assign); Block* else_block = new Block(enclosing, loc); @@ -9753,14 +10263,17 @@ Builtin_call_expression::flatten_append(Gogo* gogo, Named_object* function, // This assignment will not change the pointer value, so it does // not need a write barrier. assign->set_omit_write_barrier(); + assign->determine_types(gogo); else_block->add_statement(assign); Statement* s = Statement::make_if_statement(cond, then_block, else_block, loc); + s->determine_types(gogo); inserter->insert(s); ref = Expression::make_temporary_reference(s1tmp, loc); assign = Statement::make_assignment(ref, assign_lhs->copy(), loc); + assign->determine_types(gogo); inserter->insert(assign); } @@ -9854,6 +10367,7 @@ Builtin_call_expression::flatten_append(Gogo* gogo, Named_object* function, a1, a2, a3); } } + call->determine_type_no_context(gogo); gogo->lower_expression(function, inserter, &call); gogo->flatten_expression(function, inserter, &call); inserter->insert(Statement::make_statement(call, false)); @@ -9874,6 +10388,7 @@ Builtin_call_expression::flatten_append(Gogo* gogo, Named_object* function, Expression* lhs = Expression::make_array_index(ref, ref2, NULL, NULL, loc); lhs->array_index_expression()->set_needs_bounds_check(false); + lhs->determine_type_no_context(gogo); gogo->lower_expression(function, inserter, &lhs); gogo->flatten_expression(function, inserter, &lhs); Expression* elem = *pa; @@ -9894,6 +10409,7 @@ Builtin_call_expression::flatten_append(Gogo* gogo, Named_object* function, assign = gogo->assign_with_write_barrier(f, NULL, inserter, lhs, elem, loc); } + assign->determine_types(gogo); inserter->insert(assign); } } @@ -10099,6 +10615,10 @@ Builtin_call_expression::do_is_constant() const Expression* arg = this->one_arg(); if (arg == NULL) return false; + + // We may be called before the determine_types pass. + arg->determine_type_no_context(this->gogo_); + Type* arg_type = arg->type(); if (arg_type->is_error()) return true; @@ -10136,7 +10656,8 @@ Builtin_call_expression::do_is_constant() const Expression* arg = this->one_arg(); if (arg == NULL) return false; - return arg->field_reference_expression() != NULL; + return (arg->field_reference_expression() != NULL + || arg->classification() == Expression::EXPRESSION_SELECTOR); } case BUILTIN_COMPLEX: @@ -10213,6 +10734,10 @@ Builtin_call_expression::do_numeric_constant_value(Numeric_constant* nc) Expression* arg = this->one_arg(); if (arg == NULL) return false; + + // We may be called before the determine_types pass. + arg->determine_type_no_context(this->gogo_); + Type* arg_type = arg->type(); if (arg_type->is_error()) return false; @@ -10239,11 +10764,6 @@ Builtin_call_expression::do_numeric_constant_value(Numeric_constant* nc) if (this->seen_) return false; - // We may be replacing this expression with a constant - // during lowering, so verify the type to report any errors. - // It's OK to verify an array type more than once. - // FIXME: Remove this reference to go_get_gogo. - arg_type->verify(go_get_gogo()); if (!arg_type->is_error()) { Expression* e = arg_type->array_type()->length(); @@ -10266,6 +10786,10 @@ Builtin_call_expression::do_numeric_constant_value(Numeric_constant* nc) Expression* arg = this->one_arg(); if (arg == NULL) return false; + + // We may be called before the determine_types pass. + arg->determine_type_no_context(this->gogo_); + Type* arg_type = arg->type(); if (arg_type->is_error()) return false; @@ -10313,6 +10837,10 @@ Builtin_call_expression::do_numeric_constant_value(Numeric_constant* nc) Expression* arg = this->one_arg(); if (arg == NULL) return false; + + // We may be called before the determine_types pass. + arg->determine_type_no_context(this->gogo_); + Field_reference_expression* farg = arg->field_reference_expression(); if (farg == NULL) return false; @@ -10479,6 +11007,11 @@ Builtin_call_expression::do_type() { if (this->is_error_expression()) return Type::make_error_type(); + + Type* type = this->type(); + if (type != NULL) + return type; + switch (this->code_) { case BUILTIN_INVALID: @@ -10590,6 +11123,8 @@ Builtin_call_expression::do_determine_type(Gogo* gogo, this->fn()->determine_type_no_context(gogo); + this->simplify_multiple_results(gogo); + const Expression_list* args = this->args(); bool is_print; @@ -10597,6 +11132,11 @@ Builtin_call_expression::do_determine_type(Gogo* gogo, Type* trailing_arg_types = NULL; switch (this->code_) { + case BUILTIN_MAKE: + trailing_arg_types = Type::lookup_integer_type("int"); + is_print = false; + break; + case BUILTIN_PRINT: case BUILTIN_PRINTLN: // Do not force a large integer constant to "int". @@ -10605,28 +11145,105 @@ Builtin_call_expression::do_determine_type(Gogo* gogo, case BUILTIN_REAL: case BUILTIN_IMAG: - arg_type = Builtin_call_expression::complex_type(context->type); - if (arg_type == NULL) - arg_type = Type::lookup_complex_type("complex128"); - is_print = false; + { + // We need the argument to determine the type, so check it now + // before any call to the do_type method. + const Expression_list* args = this->args(); + if (args == NULL || args->size() < 1) + { + this->report_error(_("not enough arguments")); + return; + } + else if (args->size() > 1) + { + this->report_error(_("too many arguments")); + return; + } + + Type* dummy; + if (context->type != NULL + && context->type->is_numeric_type() + && this->is_untyped(&dummy)) + { + Type* type = context->type; + if (type->is_abstract() && !context->may_be_abstract) + type = type->make_non_abstract_type(); + this->set_type(type); + } + else if (context->may_be_abstract && this->is_constant()) + this->set_type(Type::make_abstract_float_type()); + + arg_type = Builtin_call_expression::complex_type(context->type); + if (arg_type == NULL) + { + if (context->may_be_abstract) + arg_type = Type::make_abstract_complex_type(); + else + arg_type = Type::lookup_complex_type("complex128"); + } + + if (!args->front()->is_untyped(&dummy)) + { + Type_context subcontext(arg_type, context->may_be_abstract); + args->front()->determine_type(gogo, &subcontext); + } + + is_print = false; + } break; case BUILTIN_COMPLEX: { + // We need the arguments to determine the type, so check them + // now before any call to the do_type method. + const Expression_list* args = this->args(); + if (args == NULL || args->size() < 2) + { + this->report_error(_("not enough arguments")); + return; + } + else if (args->size() > 2) + { + this->report_error(_("too many arguments")); + return; + } + + Type* dummy; + if (context->type != NULL + && context->type->is_numeric_type() + && this->is_untyped(&dummy)) + { + Type* type = context->type; + if (type->is_abstract() && !context->may_be_abstract) + type = type->make_non_abstract_type(); + this->set_type(type); + } + else if (context->may_be_abstract && this->is_constant()) + this->set_type(Type::make_abstract_complex_type()); + // For the complex function the type of one operand can // determine the type of the other, as in a binary expression. arg_type = Builtin_call_expression::real_imag_type(context->type); if (arg_type == NULL) - arg_type = Type::lookup_float_type("float64"); - if (args != NULL && args->size() == 2) { - Type* t1 = args->front()->type(); - Type* t2 = args->back()->type(); - if (!t1->is_abstract()) - arg_type = t1; - else if (!t2->is_abstract()) - arg_type = t2; + if (context->may_be_abstract) + arg_type = Type::make_abstract_float_type(); + else + arg_type = Type::lookup_float_type("float64"); + } + + Type_context subcontext(arg_type, context->may_be_abstract); + if (!args->front()->is_untyped(&dummy)) + { + args->front()->determine_type(gogo, &subcontext); + arg_type = args->front()->type(); + } + else if (!args->back()->is_untyped(&dummy)) + { + args->back()->determine_type(gogo, &subcontext); + arg_type = args->back()->type(); } + is_print = false; } break; @@ -10634,10 +11251,13 @@ Builtin_call_expression::do_determine_type(Gogo* gogo, 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(); + && !args->empty()) + { + args->front()->determine_type_no_context(gogo); + if (args->front()->type()->is_slice_type()) + trailing_arg_types = + args->front()->type()->array_type()->element_type(); + } is_print = false; break; @@ -10663,6 +11283,17 @@ Builtin_call_expression::do_determine_type(Gogo* gogo, is_print = false; break; + case BUILTIN_DELETE: + if (args != NULL && args->size() == 2) + { + args->front()->determine_type_no_context(gogo); + Map_type* mt = args->front()->type()->map_type(); + if (mt != NULL) + trailing_arg_types = mt->key_type(); + } + is_print = false; + break; + default: is_print = false; break; @@ -10677,17 +11308,17 @@ Builtin_call_expression::do_determine_type(Gogo* gogo, Type_context subcontext; subcontext.type = arg_type; - if (is_print) + if (is_print && (*pa)->is_constant()) { // We want to print large constants, we so can't just // use the appropriate nonabstract type. Use uint64 for // an integer if we know it is nonnegative, otherwise // use int64 for a integer, otherwise use float64 for a // float or complex128 for a complex. - Type* want_type = NULL; - Type* atype = (*pa)->type(); - if (atype->is_abstract()) + Type* atype; + if ((*pa)->is_untyped(&atype)) { + Type* want_type = NULL; if (atype->integer_type() != NULL) { Numeric_constant nc; @@ -10758,17 +11389,139 @@ Builtin_call_expression::check_one_arg() // Check argument types for a builtin function. void -Builtin_call_expression::do_check_types(Gogo*) +Builtin_call_expression::do_check_types(Gogo* gogo) { if (this->is_error_expression()) return; + + if (this->is_varargs() && this->code_ != BUILTIN_APPEND) + { + go_error_at(this->location(), + "invalid use of %<...%> with built-in function"); + this->set_is_error(); + return; + } + switch (this->code_) { case BUILTIN_INVALID: + return; + case BUILTIN_NEW: + if (this->check_one_arg()) + { + Expression* arg = this->one_arg(); + if (!arg->is_type_expression()) + { + go_error_at(arg->location(), "expected type"); + this->set_is_error(); + } + } + break; + case BUILTIN_MAKE: + { + const Expression_list* args = this->args(); + if (args == NULL || args->size() < 1) + { + this->report_error(_("not enough arguments")); + return; + } + + Expression* first_arg = args->front(); + if (!first_arg->is_type_expression()) + { + go_error_at(first_arg->location(), "expected type"); + this->set_is_error(); + return; + } + + Type* type = first_arg->type(); + if (!type->in_heap()) + go_error_at(first_arg->location(), + "cannot make slice of go:notinheap type"); + + bool is_slice = type->is_slice_type(); + if (!is_slice + && type->map_type() == NULL + && type->channel_type() == NULL) + { + this->report_error(_("invalid type for make function")); + return; + } + + Expression_list::const_iterator parg = args->begin(); + ++parg; + if (parg == args->end()) + { + if (is_slice) + { + this->report_error(_("length required when " + "allocating a slice")); + return; + } + } + else + { + if ((*parg)->type()->integer_type() == NULL) + { + go_error_at((*parg)->location(), + "non-integer len argument in make"); + return; + } + ++parg; + + if (is_slice && parg != args->end()) + { + if ((*parg)->type()->integer_type() == NULL) + { + go_error_at((*parg)->location(), + "non-integer cap argument in make"); + return; + } + ++parg; + } + } + + if (parg != args->end()) + { + this->report_error(_("too many arguments to make")); + return; + } + } + break; + case BUILTIN_DELETE: - return; + { + const Expression_list* args = this->args(); + if (args == NULL || args->size() < 2) + this->report_error(_("not enough arguments")); + else if (args->size() > 2) + this->report_error(_("too many arguments")); + else if (args->front()->type()->map_type() == NULL) + this->report_error(_("argument 1 must be a map")); + else + { + Type* key_type = + args->front()->type()->map_type()->key_type(); + Expression_list::iterator pa = this->args()->begin(); + pa++; + Type* arg_type = (*pa)->type(); + std::string reason; + if (!Type::are_assignable(key_type, arg_type, &reason)) + { + if (reason.empty()) + go_error_at(this->location(), + "argument 2 has incompatible type"); + else + go_error_at(this->location(), + "argument 2 has incompatible type (%s)", + reason.c_str()); + this->set_is_error(); + } + } + } + break; case BUILTIN_LEN: case BUILTIN_CAP: @@ -10834,8 +11587,13 @@ Builtin_call_expression::do_check_types(Gogo*) // an error anyhow, so we don't need one here. } else - this->report_error(_("unsupported argument type to " - "builtin function")); + { + // Report errors in the expression first. + (*p)->check_types(gogo); + if (!(*p)->is_error_expression()) + this->report_error(_("unsupported argument type to " + "builtin function")); + } } } } @@ -10873,7 +11631,20 @@ Builtin_call_expression::do_check_types(Gogo*) if (this->check_one_arg()) { Expression* arg = this->one_arg(); - if (arg->field_reference_expression() == NULL) + if (arg->classification() == Expression::EXPRESSION_SELECTOR) + { + Selector_expression* se = static_cast<Selector_expression*>(arg); + Expression* resolved = se->resolved(); + if (resolved != NULL) + arg = resolved; + } + if (arg->is_error_expression()) + ; + else if (arg->bound_method_expression() != NULL + || arg->interface_field_reference_expression() != NULL) + this->report_error(_("invalid use of method value as " + "argument of Offsetof")); + else if (arg->field_reference_expression() == NULL) this->report_error(_("argument must be a field reference")); } break; @@ -11039,14 +11810,11 @@ Builtin_call_expression::do_check_types(Gogo*) case BUILTIN_COMPLEX: { const Expression_list* args = this->args(); - if (args == NULL || args->size() < 2) - this->report_error(_("not enough arguments")); - else if (args->size() > 2) - this->report_error(_("too many arguments")); - else if (args->front()->is_error_expression() - || args->front()->type()->is_error() - || args->back()->is_error_expression() - || args->back()->type()->is_error()) + go_assert(args != NULL && args->size() == 2); + if (args->front()->is_error_expression() + || args->front()->type()->is_error() + || args->back()->is_error_expression() + || args->back()->type()->is_error()) this->set_is_error(); else if (!Type::are_identical(args->front()->type(), args->back()->type(), @@ -11285,8 +12053,9 @@ Builtin_call_expression::do_get_backend(Translate_context* context) go_unreachable(); } - return Expression::make_cast(int_type, val, - location)->get_backend(context); + Expression* e = Expression::make_cast(int_type, val, location); + e->determine_type_no_context(gogo); + return e->get_backend(context); } case BUILTIN_PRINT: @@ -11385,7 +12154,7 @@ Builtin_call_expression::do_get_backend(Translate_context* context) if (is_ln) { Expression* print_nl = - Runtime::make_call(gogo, Runtime::PRINTNL, location, 0); + Runtime::make_call(gogo, Runtime::PRINTNL, location, 0); print_stmts = Expression::make_compound(print_stmts, print_nl, location); } @@ -11394,6 +12163,8 @@ Builtin_call_expression::do_get_backend(Translate_context* context) location, 0); print_stmts = Expression::make_compound(print_stmts, unlock, location); + print_stmts->determine_type_no_context(gogo); + return print_stmts->get_backend(context); } @@ -11407,7 +12178,8 @@ Builtin_call_expression::do_get_backend(Translate_context* context) arg = Expression::convert_for_assignment(gogo, empty, arg, location); Expression* panic = - Runtime::make_call(gogo, Runtime::GOPANIC, location, 1, arg); + Runtime::make_call(gogo, Runtime::GOPANIC, location, 1, arg); + panic->determine_type_no_context(gogo); return panic->get_backend(context); } @@ -11434,6 +12206,7 @@ Builtin_call_expression::do_get_backend(Translate_context* context) location, 0); Expression* cond = Expression::make_conditional(arg, recover, nil, location); + cond->determine_type_no_context(gogo); return cond->get_backend(context); } @@ -11444,6 +12217,7 @@ Builtin_call_expression::do_get_backend(Translate_context* context) Expression* arg = args->front(); Expression* close = Runtime::make_call(gogo, Runtime::CLOSE, location, 1, arg); + close->determine_type_no_context(gogo); return close->get_backend(context); } @@ -11646,6 +12420,9 @@ Builtin_call_expression::do_export(Export_function_body* efb) const int Call_expression::do_traverse(Traverse* traverse) { + if (this->lowered_ != NULL) + return Expression::traverse(&this->lowered_, traverse); + // If we are calling a function in a different package that returns // an unnamed type, this may be the only chance we get to traverse // that type. We don't traverse this->type_ because it may be a @@ -11666,101 +12443,151 @@ Call_expression::do_traverse(Traverse* traverse) return TRAVERSE_CONTINUE; } -// Lower a call statement. +// Lower a Call_expression to a Builtin_call_expression. This happens +// early on, before determine_types. Expression* -Call_expression::do_lower(Gogo* gogo, Named_object* function, - Statement_inserter* inserter, int) -{ - Location loc = this->location(); +Call_expression::lower_builtin(Gogo* gogo) +{ + // This is called before determine_types, so we can't call + // this->fn_->type(). Fortunately builtin calls require a direct + // reference to the builtin. + Expression* fn = this->fn_; + Named_object* no; + if (fn->func_expression() != NULL) + no = fn->func_expression()->named_object(); + else if (fn->unknown_expression() != NULL) + { + no = fn->unknown_expression()->named_object(); + if (no->is_unknown()) + { + no = no->unknown_value()->real_named_object(); + if (no == NULL) + return this; + } + } + else + return this; - if (this->is_error_expression()) - return Expression::make_error(loc); + if (!no->is_function_declaration()) + return this; + if (!no->func_declaration_value()->type()->is_builtin()) + return this; + + if (fn->unknown_expression() != NULL) + fn = Expression::make_func_reference(no, NULL, fn->location()); + + Builtin_call_expression* bce = new Builtin_call_expression(gogo, fn, + this->args_, + this->is_varargs_, + this->location()); + if (this->is_deferred_) + bce->set_is_deferred(); + if (this->is_concurrent_) + bce->set_is_concurrent(); + return bce; +} - // A type cast can look like a function call. +// A type conversion can be a constant. + +bool +Call_expression::do_is_constant() const +{ + if (this->lowered_ != NULL) + return this->lowered_->is_constant(); if (this->fn_->is_type_expression() && this->args_ != NULL && this->args_->size() == 1) - { - if (this->expected_result_count_ != 0 - && this->expected_result_count_ != 1) - { - this->report_error(_("type conversion result count mismatch")); - return Expression::make_error(loc); - } - return Expression::make_cast(this->fn_->type(), this->args_->front(), - loc); - } + return this->args_->front()->is_constant(); + return false; +} - // Because do_type will return an error type and thus prevent future - // errors, check for that case now to ensure that the error gets - // reported. - Function_type* fntype = this->get_function_type(); - if (fntype == NULL) +bool +Call_expression::do_is_untyped(Type** ptype) const +{ + if (this->lowered_ != NULL) + return this->lowered_->is_untyped(ptype); + return false; +} + +bool +Call_expression::do_numeric_constant_value(Numeric_constant* nc) +{ + if (this->lowered_ != NULL) + return this->lowered_->numeric_constant_value(nc); + if (this->fn_->is_type_expression() + && this->args_ != NULL + && this->args_->size() == 1) { - if (!this->fn_->type()->is_error()) - this->report_error(_("expected function")); - this->set_is_error(); - return this; - } + // If we get here, it's before the determine_types pass, so we + // have to pull apart the type carefully. This is a hack that + // is needed because the finalize_methods needs to be able to + // determine whether the length of an array is 1. - // Handle an argument which is a call to a function which returns - // multiple results. - if (this->args_ != NULL - && this->args_->size() == 1 - && this->args_->front()->call_expression() != NULL) - { - size_t rc = this->args_->front()->call_expression()->result_count(); - if (rc > 1 - && ((fntype->parameters() != NULL - && (fntype->parameters()->size() == rc - || (fntype->is_varargs() - && fntype->parameters()->size() - 1 <= rc))) - || fntype->is_builtin())) + Type* type; + if (this->fn_->classification() == EXPRESSION_TYPE) + type = this->fn_->type(); + else if (this->fn_->unknown_expression() != NULL) { - Call_expression* call = this->args_->front()->call_expression(); - call->set_is_multi_value_arg(); - if (this->is_varargs_) + Named_object* no = this->fn_->unknown_expression()->named_object(); + if (no->is_unknown()) { - // It is not clear which result of a multiple result call - // 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. - go_error_at(call->location(), - _("multiple-value argument in single-value context")); - return Expression::make_error(call->location()); + no = no->unknown_value()->real_named_object(); + go_assert(no != NULL); } - - Expression_list* args = new Expression_list; - for (size_t i = 0; i < rc; ++i) - args->push_back(Expression::make_call_result(call, i)); - // We can't return a new call expression here, because this - // one may be referenced by Call_result expressions. We - // also can't delete the old arguments, because we may still - // traverse them somewhere up the call stack. FIXME. - this->args_ = args; + type = no->type_value(); } + else + return false; + + if (!type->is_numeric_type()) + return false; + if (!this->args_->front()->numeric_constant_value(nc)) + return false; + return nc->set_type(type, false, this->location()); } + return false; +} - // Recognize a call to a builtin function. - if (fntype->is_builtin()) +bool +Call_expression::do_discarding_value() +{ + if (this->fn_->is_type_expression()) { - Builtin_call_expression* bce = - new Builtin_call_expression(gogo, this->fn_, this->args_, - this->is_varargs_, loc); - if (this->is_deferred_) - bce->set_is_deferred(); - if (this->is_concurrent_) - bce->set_is_concurrent(); - return bce; + this->unused_value_error(); + return false; } + return true; +} + +// Lower a call statement. + +Expression* +Call_expression::do_lower(Gogo* gogo, Named_object*, + Statement_inserter* inserter, int) +{ + if (this->lowered_ != NULL) + return this->lowered_; + + Location loc = this->location(); + + if (this->is_error_expression()) + return Expression::make_error(loc); + + // Although we've already lowered calls to builtin functions, we may + // still see calls generated to builtins elsewhere in the lowering + // pass. It's simpler to handle them here. + Expression* builtin = this->lower_builtin(gogo); + if (builtin != this) + return builtin; // If this call returns multiple results, create a temporary // variable to hold them. if (this->result_count() > 1 && this->call_temp_ == NULL) { Struct_field_list* sfl = new Struct_field_list(); - const Typed_identifier_list* results = fntype->results(); + const Typed_identifier_list* results = + this->get_function_type()->results(); int i = 0; char buf[20]; @@ -11779,17 +12606,6 @@ Call_expression::do_lower(Gogo* gogo, Named_object* function, inserter->insert(this->call_temp_); } - // Handle a call to a varargs function by packaging up the extra - // parameters. - if (fntype->is_varargs()) - { - const Typed_identifier_list* parameters = fntype->parameters(); - go_assert(parameters != NULL && !parameters->empty()); - Type* varargs_type = parameters->back().type(); - this->lower_varargs(gogo, function, inserter, varargs_type, - parameters->size(), SLICE_STORAGE_MAY_ESCAPE); - } - // If this is call to a method, call the method directly passing the // object as the first parameter. Bound_method_expression* bme = this->fn_->bound_method_expression(); @@ -11832,6 +12648,9 @@ Call_expression::do_lower(Gogo* gogo, Named_object* function, first_arg = Expression::make_unsafe_cast(fatype, first_arg, loc); } + first_arg->determine_type_no_context(gogo); + first_arg->check_types(gogo); + Expression_list* new_args = new Expression_list(); new_args->push_back(first_arg); if (this->args_ != NULL) @@ -11863,107 +12682,6 @@ Call_expression::do_lower(Gogo* gogo, Named_object* function, return this; } -// Lower a call to a varargs function. FUNCTION is the function in -// which the call occurs--it's not the function we are calling. -// VARARGS_TYPE is the type of the varargs parameter, a slice type. -// PARAM_COUNT is the number of parameters of the function we are -// calling; the last of these parameters will be the varargs -// parameter. - -void -Call_expression::lower_varargs(Gogo* gogo, Named_object* function, - Statement_inserter* inserter, - Type* varargs_type, size_t param_count, - Slice_storage_escape_disp escape_disp) -{ - if (this->varargs_are_lowered_) - return; - - Location loc = this->location(); - - go_assert(param_count > 0); - go_assert(varargs_type->is_slice_type()); - - size_t arg_count = this->args_ == NULL ? 0 : this->args_->size(); - if (arg_count < param_count - 1) - { - // Not enough arguments; will be caught in check_types. - return; - } - - Expression_list* old_args = this->args_; - Expression_list* new_args = new Expression_list(); - bool push_empty_arg = false; - if (old_args == NULL || old_args->empty()) - { - go_assert(param_count == 1); - push_empty_arg = true; - } - else - { - Expression_list::const_iterator pa; - int i = 1; - for (pa = old_args->begin(); pa != old_args->end(); ++pa, ++i) - { - if (static_cast<size_t>(i) == param_count) - break; - new_args->push_back(*pa); - } - - // We have reached the varargs parameter. - - bool issued_error = false; - if (pa == old_args->end()) - push_empty_arg = true; - else if (pa + 1 == old_args->end() && this->is_varargs_) - new_args->push_back(*pa); - else if (this->is_varargs_) - { - if ((*pa)->type()->is_slice_type()) - this->report_error(_("too many arguments")); - else - { - go_error_at(this->location(), - _("invalid use of %<...%> with non-slice")); - this->set_is_error(); - } - return; - } - else - { - Type* element_type = varargs_type->array_type()->element_type(); - Expression_list* vals = new Expression_list; - for (; pa != old_args->end(); ++pa, ++i) - { - // Check types here so that we get a better message. - Type* patype = (*pa)->type(); - Location paloc = (*pa)->location(); - if (!this->check_argument_type(i, element_type, patype, - paloc, issued_error)) - continue; - vals->push_back(*pa); - } - 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); - } - } - - if (push_empty_arg) - new_args->push_back(Expression::make_nil(loc)); - - // We can't return a new call expression here, because this one may - // be referenced by Call_result expressions. FIXME. We can't - // delete OLD_ARGS because we may have both a Call_expression and a - // Builtin_call_expression which refer to them. FIXME. - this->args_ = new_args; - this->varargs_are_lowered_ = true; -} - // Flatten a call with multiple results into a temporary. Expression* @@ -12038,7 +12756,10 @@ Call_expression::do_flatten(Gogo* gogo, Named_object*, { Expression* ret = this->intrinsify(gogo, inserter); if (ret != NULL) - return ret; + { + ret->determine_type_no_context(gogo); + return ret; + } } // Add an implicit conversion to a boolean type, if needed. See the @@ -12925,6 +13646,7 @@ void Call_expression::set_expected_result_count(size_t count) { go_assert(this->expected_result_count_ == 0); + go_assert(!this->types_are_determined_); this->expected_result_count_ = count; } @@ -13001,29 +13723,16 @@ Call_expression::do_type() { if (this->is_error_expression()) return Type::make_error_type(); - if (this->type_ != NULL) - return this->type_; - - Type* ret; - Function_type* fntype = this->get_function_type(); - if (fntype == NULL) - return Type::make_error_type(); - - const Typed_identifier_list* results = fntype->results(); - if (results == NULL) - ret = Type::make_void_type(); - else if (results->size() == 1) - ret = results->begin()->type(); - else - ret = Type::make_call_multiple_result_type(); - - this->type_ = ret; - + if (this->lowered_ != NULL) + return this->lowered_->type(); + go_assert(this->type_ != NULL); return this->type_; } // Determine types for a call expression. We can use the function -// parameter types to set the types of the arguments. +// parameter types to set the types of the arguments. We simplify +// some of the call cases here, storing the result in the lowered_ +// field. void Call_expression::do_determine_type(Gogo* gogo, const Type_context* context) @@ -13031,63 +13740,159 @@ Call_expression::do_determine_type(Gogo* gogo, const Type_context* context) if (!this->determining_types()) return; + if (this->lowered_== NULL) + { + Expression* builtin = this->lower_builtin(gogo); + if (builtin != this) + this->lowered_ = builtin; + } + + if (this->lowered_ != NULL) + { + this->lowered_->determine_type(gogo, context); + return; + } + this->fn_->determine_type_no_context(gogo); + + // Simplify a type conversion. + + if (this->fn_->is_type_expression() + && this->args_ != NULL + && this->args_->size() == 1 + && (this->expected_result_count_ == 0 + || this->expected_result_count_ == 1)) + { + this->lowered_ = Expression::make_cast(this->fn_->type(), + this->args_->front(), + this->location()); + this->lowered_->determine_type(gogo, context); + return; + } + + // Get the type of the function we are calling. + Function_type* fntype = this->get_function_type(); - const Typed_identifier_list* parameters = NULL; - if (fntype != NULL) - parameters = fntype->parameters(); - if (this->args_ != NULL) + if (fntype == NULL) { - Typed_identifier_list::const_iterator pt; - if (parameters != NULL) - pt = parameters->begin(); - bool first = true; - for (Expression_list::const_iterator pa = this->args_->begin(); - pa != this->args_->end(); - ++pa) + // We report the error here so that we can reasonably return an + // error type in do_type. + if (!this->fn_->type()->is_error()) + this->report_error(_("expected function")); + else + this->set_is_error(); + if (this->args_ != NULL) { - if (first) - { - first = false; - // If this is a method, the first argument is the - // receiver. - if (fntype != NULL && fntype->is_method()) - { - Type* rtype = fntype->receiver()->type(); - // The receiver is always passed as a pointer. - if (rtype->points_to() == NULL) - rtype = Type::make_pointer_type(rtype); - Type_context subcontext(rtype, false); - (*pa)->determine_type(gogo, &subcontext); - continue; - } - } + for (Expression_list::iterator p = this->args_->begin(); + p != this->args_->end(); + ++p) + (*p)->determine_type_no_context(gogo); + } + return; + } + + // Simplify f(g()) where g() returns multiple results. + + this->simplify_multiple_results(gogo); + + // Set the type of this expression. + + go_assert(this->type_ == NULL); + const Typed_identifier_list* results = fntype->results(); + if (results == NULL || results->empty()) + this->type_ = Type::make_void_type(); + else if (results->size() == 1) + { + // If this is a call to a generated equality function, we + // determine the type based on the context. See the comment in + // Binary_expression::lower_array_comparison. + if (this->is_equal_function_ + && !context->may_be_abstract + && context->type != NULL + && context->type->is_boolean_type()) + this->type_ = context->type; + else + this->type_ = results->begin()->type(); + } + else + this->type_ = Type::make_call_multiple_result_type(); + + // Determine the types of the arguments. + + if (this->args_ == NULL) + { + if (fntype->is_varargs()) + { + if (!this->rewrite_varargs()) + this->set_is_error(); + } + return; + } - if (parameters != NULL && pt != parameters->end()) + const Typed_identifier_list* parameters = fntype->parameters(); + Typed_identifier_list::const_iterator pt; + if (parameters != NULL) + pt = parameters->begin(); + bool first = true; + for (Expression_list::const_iterator pa = this->args_->begin(); + pa != this->args_->end(); + ++pa) + { + if (first) + { + first = false; + // If this is a method, the first argument is the + // receiver. + if (fntype != NULL && fntype->is_method()) { - Type_context subcontext(pt->type(), false); + Type* rtype = fntype->receiver()->type(); + // The receiver is always passed as a pointer. + if (rtype->points_to() == NULL) + rtype = Type::make_pointer_type(rtype); + Type_context subcontext(rtype, false); (*pa)->determine_type(gogo, &subcontext); - ++pt; + continue; } - else - (*pa)->determine_type_no_context(gogo); } + + if ((this->is_varargs_ || this->varargs_are_lowered_) + && fntype->is_varargs() + && pa + 1 == this->args_->end() + && parameters != NULL + && pt + 1 == parameters->end()) + { + Type_context subcontext(pt->type(), false); + (*pa)->determine_type(gogo, &subcontext); + continue; + } + + if (!this->is_varargs_ + && fntype->is_varargs() + && parameters != NULL + && pt + 1 == parameters->end()) + { + go_assert(pt->type()->is_slice_type()); + Type_context subcontext(pt->type()->array_type()->element_type(), + false); + (*pa)->determine_type(gogo, &subcontext); + continue; + } + + if (parameters != NULL && pt != parameters->end()) + { + Type_context subcontext(pt->type(), false); + (*pa)->determine_type(gogo, &subcontext); + if (!fntype->is_varargs() || pt + 1 != parameters->end()) + ++pt; + } + else + (*pa)->determine_type_no_context(gogo); } - // If this is a call to a generated equality function, we determine - // the type based on the context. See the comment in - // Binary_expression::lower_array_comparison. - if (this->is_equal_function_ - && !context->may_be_abstract - && context->type != NULL - && context->type->is_boolean_type() - && context->type != Type::lookup_bool_type()) + if (fntype->is_varargs()) { - go_assert(this->type_ == NULL - || this->type_ == Type::lookup_bool_type() - || this->type_ == context->type - || this->type_->is_error()); - this->type_ = context->type; + if (!this->rewrite_varargs()) + this->set_is_error(); } } @@ -13106,26 +13911,164 @@ Call_expression::determining_types() } } +// Simplify f(g()) where g() returns multiple results. Called by +// do_determine_types of both Call_expression and +// Builtin_call_expression. + +void +Call_expression::simplify_multiple_results(Gogo* gogo) +{ + if (this->args_ == NULL || this->args_->size() != 1) + return; + + Call_expression* call = this->args_->front()->call_expression(); + if (call == NULL || call->is_builtin()) + return; + + call->determine_type_no_context(gogo); + size_t rc = call->result_count(); + Function_type* fntype = this->get_function_type(); + if (rc > 1 + && ((fntype->parameters() != NULL + && (fntype->parameters()->size() == rc + || (fntype->is_varargs() + && fntype->parameters()->size() - 1 <= rc))) + || fntype->is_builtin())) + { + if (this->is_varargs_) + { + go_error_at(call->location(), + "multiple-value argument in single-value context"); + this->set_is_error(); + } + + call->set_is_multi_value_arg(); + Expression_list* args = new Expression_list; + for (size_t i = 0; i < rc; ++i) + args->push_back(Expression::make_call_result(call, i)); + // We can't create a new Call_expression here because this + // one may be referred to by Call_result expressions. + this->args_ = args; + } +} + +// Lower a call to a varargs function by rewriting the value(s) passed +// to the varargs argument into a slice. Called during the +// determine_types pass. + +bool +Call_expression::rewrite_varargs() +{ + if (this->varargs_are_lowered_) + return true; + this->varargs_are_lowered_ = true; + + Function_type* fntype = this->get_function_type(); + + const Typed_identifier_list* parameters = fntype->parameters(); + go_assert(parameters != NULL && !parameters->empty()); + size_t param_count = parameters->size(); + + Type* varargs_type = parameters->back().type(); + go_assert(varargs_type->is_slice_type()); + + size_t arg_count = this->args_ == NULL ? 0 : this->args_->size(); + if (arg_count < param_count - 1) + { + if (!this->is_error_expression()) + this->report_error(_("not enough arguments")); + return false; + } + + bool ret = true; + Expression_list* old_args = this->args_; + Expression_list* new_args = new Expression_list(); + bool push_empty_arg = false; + if (old_args == NULL || old_args->empty()) + { + go_assert(param_count == 1); + push_empty_arg = true; + } + else + { + Expression_list::const_iterator pa; + size_t i = 1; + for (pa = old_args->begin(); pa != old_args->end(); ++pa, ++i) + { + if (i == param_count) + break; + new_args->push_back(*pa); + } + + // We have reached the varargs parameter. + + if (pa == old_args->end()) + push_empty_arg = true; + else if (pa + 1 == old_args->end() && this->is_varargs_) + new_args->push_back(*pa); + else if (this->is_varargs_) + { + if (!this->is_error_expression()) + { + if ((*pa)->type()->is_slice_type()) + this->report_error(_("too many arguments")); + else + { + go_error_at(this->location(), + "invalid use of %<...%> with non-slice"); + this->set_is_error(); + } + } + return false; + } + else + { + Type* element_type = varargs_type->array_type()->element_type(); + Expression_list* vals = new Expression_list; + for (; pa != old_args->end(); ++pa, ++i) + { + Type* patype = (*pa)->type(); + Location paloc = (*pa)->location(); + if (!this->check_argument_type(i, element_type, patype, paloc)) + { + ret = false; + continue; + } + vals->push_back(*pa); + } + Expression* val = + Expression::make_slice_composite_literal(varargs_type, vals, + this->location()); + new_args->push_back(val); + } + } + + if (push_empty_arg) + new_args->push_back(Expression::make_nil(this->location())); + + // We can't create a new Call_expression here because this + // one may be referred to by Call_result expressions. + this->args_ = new_args; + + return ret; +} + // Check types for parameter I. bool Call_expression::check_argument_type(int i, const Type* parameter_type, const Type* argument_type, - Location argument_location, - bool issued_error) + Location argument_location) { std::string reason; if (!Type::are_assignable(parameter_type, argument_type, &reason)) { - if (!issued_error) - { - if (reason.empty()) - go_error_at(argument_location, "argument %d has incompatible type", i); - else - go_error_at(argument_location, - "argument %d has incompatible type (%s)", - i, reason.c_str()); - } + if (reason.empty()) + go_error_at(argument_location, "argument %d has incompatible type", i); + else + go_error_at(argument_location, + "argument %d has incompatible type (%s)", + i, reason.c_str()); this->set_is_error(); return false; } @@ -13137,16 +14080,15 @@ Call_expression::check_argument_type(int i, const Type* parameter_type, void Call_expression::do_check_types(Gogo*) { - if (this->classification() == EXPRESSION_ERROR) + if (this->is_error_expression() + || this->fn_->is_error_expression() + || this->fn_->type()->is_error()) + return; + if (this->lowered_ != NULL) return; Function_type* fntype = this->get_function_type(); - if (fntype == NULL) - { - if (!this->fn_->type()->is_error()) - this->report_error(_("expected function")); - return; - } + go_assert(fntype != NULL); if (this->expected_result_count_ != 0 && this->expected_result_count_ != this->result_count()) @@ -13157,6 +14099,14 @@ Call_expression::do_check_types(Gogo*) return; } + if (this->is_varargs_ && !fntype->is_varargs()) + { + go_error_at(this->location(), + "invalid use of %<...%> calling non-variadic function"); + this->set_is_error(); + return; + } + bool is_method = fntype->is_method(); if (is_method) { @@ -13181,21 +14131,8 @@ Call_expression::do_check_types(Gogo*) } } - // Note that varargs was handled by the lower_varargs() method, so - // we don't have to worry about it here unless something is wrong. - if (this->is_varargs_ && !this->varargs_are_lowered_) - { - if (!fntype->is_varargs()) - { - go_error_at(this->location(), - _("invalid use of %<...%> calling non-variadic function")); - this->set_is_error(); - return; - } - } - const Typed_identifier_list* parameters = fntype->parameters(); - if (this->args_ == NULL || this->args_->size() == 0) + if (this->args_ == NULL || this->args_->empty()) { if (parameters != NULL && !parameters->empty()) this->report_error(_("not enough arguments")); @@ -13211,8 +14148,8 @@ Call_expression::do_check_types(Gogo*) { // This is F(G()) when G returns more than one result. If the // results can be matched to parameters, it would have been - // lowered in do_lower. If we get here we know there is a - // mismatch. + // rewritten in determine_types. If we get here we know there + // is a mismatch. if (this->args_->front()->call_expression()->result_count() < parameters->size()) this->report_error(_("not enough arguments")); @@ -13235,7 +14172,7 @@ Call_expression::do_check_types(Gogo*) return; } this->check_argument_type(i + 1, pt->type(), (*pa)->type(), - (*pa)->location(), false); + (*pa)->location()); } if (pa != this->args_->end()) this->report_error(_("too many arguments")); @@ -13676,6 +14613,19 @@ Expression::make_call_result(Call_expression* call, unsigned int index) // Class Index_expression. +// Report whether EXPR is a map index expression. This is called when +// types are determined but before lowering. + +bool +Index_expression::is_map_index(Expression* expr) +{ + if (expr->map_index_expression() != NULL) + return true; + if (expr->index_expression() != NULL) + return expr->index_expression()->left_->type()->map_type() != NULL; + return false; +} + // Traversal. int @@ -13691,12 +14641,206 @@ Index_expression::do_traverse(Traverse* traverse) return TRAVERSE_CONTINUE; } +void +Index_expression::do_determine_type(Gogo* gogo, const Type_context*) +{ + this->left_->determine_type_no_context(gogo); + + Type_context end_context; + Type* type = this->left_->type(); + if (type->array_type() != NULL + || (type->points_to() != NULL + && type->points_to()->array_type() != NULL + && !type->points_to()->is_slice_type()) + || type->is_string_type()) + { + Type_context index_context(Type::lookup_integer_type("int"), false); + this->start_->determine_type(gogo, &index_context); + end_context = index_context; + } + else if (type->map_type() != NULL) + { + Type_context key_context(type->map_type()->key_type(), false); + this->start_->determine_type(gogo, &key_context); + } + else if (type->is_error()) + this->set_is_error(); + else + { + if (this->cap_ != NULL) + this->report_error(_("invalid 3-index slice of object " + "that is not a slice")); + else if (this->end_ != NULL) + this->report_error(_("attempt to slice object that is not " + "array, slice, or string")); + else + this->report_error(_("attempt to index object that is not " + "array, slice, string, or map")); + + this->start_->determine_type_no_context(gogo); + } + + if (this->end_ != NULL) + this->end_->determine_type(gogo, &end_context); + if (this->cap_ != NULL) + this->cap_->determine_type(gogo, &end_context); +} + +Type* +Index_expression::do_type() +{ + if (this->is_error_expression()) + return Type::make_error_type(); + + Type* type = this->left_->type(); + if (this->end_ != NULL) + { + // A slice of an array is a slice type. A slice of a slice or + // string type is that same type. + Array_type* at = type->deref()->array_type(); + if (at != NULL && !at->is_slice_type()) + return Type::make_array_type(at->element_type(), NULL); + return type; + } + if (type->deref()->array_type() != NULL) + return type->deref()->array_type()->element_type(); + else if (type->is_string_type()) + return Type::lookup_integer_type("byte"); + else if (type->map_type() != NULL) + return type->map_type()->val_type(); + else + return Type::make_error_type(); +} + +void +Index_expression::do_check_types(Gogo*) +{ + if (this->is_error_expression()) + return; + + Type* ltype = this->left_->type(); + if (ltype->is_error()) + { + go_assert(saw_errors()); + return; + } + + if (this->left_->is_type_expression()) + { + this->report_error(_("attempt to index type expression")); + return; + } + + if (ltype->array_type() != NULL) + { + if (!Array_index_expression::check_indexes(this->left_, this->start_, + this->end_, this->cap_, + this->location())) + this->set_is_error(); + } + else if (ltype->points_to() != NULL + && ltype->points_to()->array_type() != NULL + && !ltype->points_to()->is_slice_type()) + { + Expression* deref = Expression::make_dereference(this->left_, + NIL_CHECK_DEFAULT, + this->location()); + if (!Array_index_expression::check_indexes(deref, this->start_, + this->end_, this->cap_, + this->location())) + this->set_is_error(); + delete deref; + } + else if (ltype->is_string_type()) + { + if (this->cap_ != NULL) + this->report_error(_("invalid 3-index slice of string")); + else + { + if (!String_index_expression::check_indexes(this->left_, + this->start_, + this->end_, + this->location())) + this->set_is_error(); + } + } + else if (ltype->map_type() != NULL) + { + if (this->end_ != NULL || this->cap_ != NULL) + this->report_error(_("invalid slice of map")); + else + { + Map_type* mt = ltype->map_type(); + std::string reason; + if (!Type::are_assignable(mt->key_type(), this->start_->type(), + &reason)) + { + if (reason.empty()) + this->report_error(_("incompatible type for map index")); + else + { + go_error_at(this->location(), + "incompatible type for map index (%s)", + reason.c_str()); + this->set_is_error(); + } + } + } + } + else + go_unreachable(); +} + +bool +Index_expression::do_is_addressable() const +{ + if (this->is_error_expression()) + return true; + + Type* type = this->left_->type(); + if (type->is_error()) + return true; + + // A slice index is addressable, and an index of an addressable + // array is addressable. + + bool is_pointer = false; + if (type->points_to() != NULL + && type->points_to()->array_type() != NULL + && !type->points_to()->is_slice_type()) + { + type = type->points_to(); + is_pointer = true; + } + + if (type->array_type() == NULL) + return false; + + if (this->end_ != NULL) + return false; + if (type->is_slice_type()) + return true; + return is_pointer || this->left_->is_addressable(); +} + +// We need to do a nil check of any pointer dereference. + +void +Index_expression::do_issue_nil_check() +{ + this->left_->issue_nil_check(); + this->needs_nil_check_ = true; +} + // Lower an index expression. This converts the generic index // expression into an array index, a string index, or a map index. Expression* Index_expression::do_lower(Gogo*, Named_object*, Statement_inserter*, int) { + if (this->is_error_expression()) + return Expression::make_error(this->location()); + Location location = this->location(); Expression* left = this->left_; Expression* start = this->start_; @@ -13709,11 +14853,6 @@ Index_expression::do_lower(Gogo*, Named_object*, Statement_inserter*, int) go_assert(saw_errors()); return Expression::make_error(location); } - else if (left->is_type_expression()) - { - go_error_at(location, "attempt to index type expression"); - return Expression::make_error(location); - } else if (type->array_type() != NULL) return Expression::make_array_index(left, start, end, cap, location); else if (type->points_to() != NULL @@ -13726,50 +14865,25 @@ Index_expression::do_lower(Gogo*, Named_object*, Statement_inserter*, int) // For an ordinary index into the array, the pointer will be // dereferenced. For a slice it will not--the resulting slice // will simply reuse the pointer, which is incorrect if that - // pointer is nil. - if (end != NULL || cap != NULL) + // pointer is nil. We may also be in a context that requires a + // nil check. + if (end != NULL || cap != NULL || this->needs_nil_check_) deref->issue_nil_check(); return Expression::make_array_index(deref, start, end, cap, location); } else if (type->is_string_type()) { - if (cap != NULL) - { - go_error_at(location, "invalid 3-index slice of string"); - return Expression::make_error(location); - } + go_assert(cap == NULL); return Expression::make_string_index(left, start, end, location); } else if (type->map_type() != NULL) { - if (end != NULL || cap != NULL) - { - go_error_at(location, "invalid slice of map"); - return Expression::make_error(location); - } + go_assert(end == NULL && cap == NULL); return Expression::make_map_index(left, start, location); } - else if (cap != NULL) - { - go_error_at(location, - "invalid 3-index slice of object that is not a slice"); - return Expression::make_error(location); - } - else if (end != NULL) - { - go_error_at(location, - ("attempt to slice object that is not " - "array, slice, or string")); - return Expression::make_error(location); - } else - { - go_error_at(location, - ("attempt to index object that is not " - "array, slice, string, or map")); - return Expression::make_error(location); - } + go_unreachable(); } // Write an indexed expression @@ -13888,39 +15002,66 @@ Array_index_expression::do_determine_type(Gogo* gogo, const Type_context*) void Array_index_expression::do_check_types(Gogo*) { + if (!Array_index_expression::check_indexes(this->array_, this->start_, + this->end_, this->cap_, + this->location())) + this->set_is_error(); +} + +// A static function to check array index types. This is also called +// by Index_expression::do_check_types. It reports whether type +// checking succeeded. + +bool +Array_index_expression::check_indexes(Expression* array, Expression* start, + Expression* end, Expression* cap, + Location loc) +{ + bool ret = true; + Numeric_constant nc; unsigned long v; - if (this->start_->type()->integer_type() == NULL - && !this->start_->type()->is_error() - && (!this->start_->type()->is_abstract() - || !this->start_->numeric_constant_value(&nc) + if (start->type()->integer_type() == NULL + && !start->type()->is_error() + && (!start->type()->is_abstract() + || !start->numeric_constant_value(&nc) || nc.to_unsigned_long(&v) == Numeric_constant::NC_UL_NOTINT)) - this->report_error(_("index must be integer")); - if (this->end_ != NULL - && this->end_->type()->integer_type() == NULL - && !this->end_->type()->is_error() - && !this->end_->is_nil_expression() - && !this->end_->is_error_expression() - && (!this->end_->type()->is_abstract() - || !this->end_->numeric_constant_value(&nc) + { + go_error_at(loc, "index must be integer"); + ret = false; + } + + if (end != NULL + && end->type()->integer_type() == NULL + && !end->type()->is_error() + && !end->is_nil_expression() + && !end->is_error_expression() + && (!end->type()->is_abstract() + || !end->numeric_constant_value(&nc) || nc.to_unsigned_long(&v) == Numeric_constant::NC_UL_NOTINT)) - this->report_error(_("slice end must be integer")); - if (this->cap_ != NULL - && this->cap_->type()->integer_type() == NULL - && !this->cap_->type()->is_error() - && !this->cap_->is_nil_expression() - && !this->cap_->is_error_expression() - && (!this->cap_->type()->is_abstract() - || !this->cap_->numeric_constant_value(&nc) + { + go_error_at(loc, "slice end must be integer"); + ret = false; + } + + if (cap != NULL + && cap->type()->integer_type() == NULL + && !cap->type()->is_error() + && !cap->is_nil_expression() + && !cap->is_error_expression() + && (!cap->type()->is_abstract() + || !cap->numeric_constant_value(&nc) || nc.to_unsigned_long(&v) == Numeric_constant::NC_UL_NOTINT)) - this->report_error(_("slice capacity must be integer")); + { + go_error_at(loc, "slice capacity must be integer"); + ret = false; + } - Array_type* array_type = this->array_->type()->array_type(); + Array_type* array_type = array->type()->array_type(); if (array_type == NULL) { - go_assert(this->array_->type()->is_error()); - this->set_is_error(); - return; + go_assert(array->type()->is_error()); + return false; } unsigned int int_bits = @@ -13934,62 +15075,66 @@ Array_index_expression::do_check_types(Gogo*) Numeric_constant inc; mpz_t ival; bool ival_valid = false; - if (this->start_->numeric_constant_value(&inc) && inc.to_int(&ival)) + if (start->numeric_constant_value(&inc) && inc.to_int(&ival)) { ival_valid = true; if (mpz_sgn(ival) < 0 || mpz_sizeinbase(ival, 2) >= int_bits || (lval_valid - && (this->end_ == NULL + && (end == NULL ? mpz_cmp(ival, lval) >= 0 : mpz_cmp(ival, lval) > 0))) { - go_error_at(this->start_->location(), "array index out of bounds"); - this->set_is_error(); + go_error_at(start->location(), "array index out of bounds"); + ret = false; } } - if (this->end_ != NULL && !this->end_->is_nil_expression()) + + if (end != NULL && !end->is_nil_expression()) { Numeric_constant enc; mpz_t eval; bool eval_valid = false; - if (this->end_->numeric_constant_value(&enc) && enc.to_int(&eval)) + if (end->numeric_constant_value(&enc) && enc.to_int(&eval)) { eval_valid = true; if (mpz_sgn(eval) < 0 || mpz_sizeinbase(eval, 2) >= int_bits || (lval_valid && mpz_cmp(eval, lval) > 0)) { - go_error_at(this->end_->location(), "array index out of bounds"); - this->set_is_error(); + go_error_at(end->location(), "array index out of bounds"); + ret = false; } else if (ival_valid && mpz_cmp(ival, eval) > 0) - this->report_error(_("inverted slice range")); + { + go_error_at(loc, "inverted slice range"); + ret = false; + } } Numeric_constant cnc; mpz_t cval; - if (this->cap_ != NULL - && this->cap_->numeric_constant_value(&cnc) && cnc.to_int(&cval)) + if (cap != NULL + && cap->numeric_constant_value(&cnc) && cnc.to_int(&cval)) { if (mpz_sgn(cval) < 0 || mpz_sizeinbase(cval, 2) >= int_bits || (lval_valid && mpz_cmp(cval, lval) > 0)) { - go_error_at(this->cap_->location(), "array index out of bounds"); - this->set_is_error(); + go_error_at(cap->location(), "array index out of bounds"); + ret = false; } else if (ival_valid && mpz_cmp(ival, cval) > 0) { - go_error_at(this->cap_->location(), + go_error_at(cap->location(), "invalid slice index: capacity less than start"); - this->set_is_error(); + ret = false; } else if (eval_valid && mpz_cmp(eval, cval) > 0) { - go_error_at(this->cap_->location(), + go_error_at(cap->location(), "invalid slice index: capacity less than length"); - this->set_is_error(); + ret = false; } mpz_clear(cval); } @@ -14004,15 +15149,22 @@ Array_index_expression::do_check_types(Gogo*) // A slice of an array requires an addressable array. A slice of a // slice is always possible. - if (this->end_ != NULL && !array_type->is_slice_type()) + if (end != NULL && !array_type->is_slice_type()) { - if (!this->array_->is_addressable()) - this->report_error(_("slice of unaddressable value")); + if (!array->is_addressable()) + { + go_error_at(loc, "slice of unaddressable value"); + ret = false; + } else - // Set the array address taken but not escape. The escape - // analysis will make it escape to heap when needed. - this->array_->address_taken(false); + { + // Set the array address taken but not escape. The escape + // analysis will make it escape to heap when needed. + array->address_taken(false); + } } + + return ret; } // The subexpressions of an array index must be evaluated in order. @@ -14113,6 +15265,7 @@ Array_index_expression::do_flatten(Gogo* gogo, Named_object*, { len = array_type->get_length(gogo, this->array_->copy()); temp = Statement::make_temporary(NULL, len, loc); + temp->determine_types(gogo); inserter->insert(temp); len = Expression::make_temporary_reference(temp, loc); } @@ -14122,6 +15275,7 @@ Array_index_expression::do_flatten(Gogo* gogo, Named_object*, { scap = array_type->get_capacity(gogo, this->array_->copy()); temp = Statement::make_temporary(NULL, scap, loc); + temp->determine_types(gogo); inserter->insert(temp); scap = Expression::make_temporary_reference(temp, loc); } @@ -14491,6 +15645,7 @@ String_index_expression::do_flatten(Gogo* gogo, Named_object*, Expression* len = Expression::make_string_info(string->copy(), STRING_INFO_LENGTH, loc); temp = Statement::make_temporary(NULL, len, loc); + temp->determine_types(gogo); inserter->insert(temp); len = Expression::make_temporary_reference(temp, loc); @@ -14559,62 +15714,90 @@ String_index_expression::do_determine_type(Gogo* gogo, const Type_context*) void String_index_expression::do_check_types(Gogo*) { + if (!String_index_expression::check_indexes(this->string_, this->start_, + this->end_, this->location())) + this->set_is_error(); +} + +// A static function to check string index types. This is also called +// by Index_expression::do_check_types. It reports whether type +// checking succeeded. + +bool +String_index_expression::check_indexes(Expression* string, Expression* start, + Expression* end, Location loc) +{ + bool ret = true; + Numeric_constant nc; unsigned long v; - if (this->start_->type()->integer_type() == NULL - && !this->start_->type()->is_error() - && (!this->start_->type()->is_abstract() - || !this->start_->numeric_constant_value(&nc) + if (start->type()->integer_type() == NULL + && !start->type()->is_error() + && (!start->type()->is_abstract() + || !start->numeric_constant_value(&nc) || nc.to_unsigned_long(&v) == Numeric_constant::NC_UL_NOTINT)) - this->report_error(_("index must be integer")); - if (this->end_ != NULL - && this->end_->type()->integer_type() == NULL - && !this->end_->type()->is_error() - && !this->end_->is_nil_expression() - && !this->end_->is_error_expression() - && (!this->end_->type()->is_abstract() - || !this->end_->numeric_constant_value(&nc) + { + go_error_at(loc, "index must be integer"); + ret = false; + } + + if (end != NULL + && end->type()->integer_type() == NULL + && !end->type()->is_error() + && !end->is_nil_expression() + && !end->is_error_expression() + && (!end->type()->is_abstract() + || !end->numeric_constant_value(&nc) || nc.to_unsigned_long(&v) == Numeric_constant::NC_UL_NOTINT)) - this->report_error(_("slice end must be integer")); + { + go_error_at(loc, "slice end must be integer"); + ret = false; + } std::string sval; - bool sval_valid = this->string_->string_constant_value(&sval); + bool sval_valid = string->string_constant_value(&sval); Numeric_constant inc; mpz_t ival; bool ival_valid = false; - if (this->start_->numeric_constant_value(&inc) && inc.to_int(&ival)) + if (start->numeric_constant_value(&inc) && inc.to_int(&ival)) { ival_valid = true; if (mpz_sgn(ival) < 0 || (sval_valid - && (this->end_ == NULL + && (end == NULL ? mpz_cmp_ui(ival, sval.length()) >= 0 : mpz_cmp_ui(ival, sval.length()) > 0))) { - go_error_at(this->start_->location(), "string index out of bounds"); - this->set_is_error(); + go_error_at(start->location(), "string index out of bounds"); + ret = false; } } - if (this->end_ != NULL && !this->end_->is_nil_expression()) + + if (end != NULL && !end->is_nil_expression()) { Numeric_constant enc; mpz_t eval; - if (this->end_->numeric_constant_value(&enc) && enc.to_int(&eval)) + if (end->numeric_constant_value(&enc) && enc.to_int(&eval)) { if (mpz_sgn(eval) < 0 || (sval_valid && mpz_cmp_ui(eval, sval.length()) > 0)) { - go_error_at(this->end_->location(), "string index out of bounds"); - this->set_is_error(); + go_error_at(end->location(), "string index out of bounds"); + ret = false; } else if (ival_valid && mpz_cmp(ival, eval) > 0) - this->report_error(_("inverted slice range")); + { + go_error_at(loc, "inverted slice range"); + ret = false; + } mpz_clear(eval); } } if (ival_valid) mpz_clear(ival); + + return ret; } // Get the backend representation for a string index. @@ -14764,6 +15947,29 @@ Map_index_expression::do_traverse(Traverse* traverse) return Expression::traverse(&this->index_, traverse); } +void +Map_index_expression::do_determine_type(Gogo* gogo, const Type_context*) +{ + this->map_->determine_type_no_context(gogo); + Map_type* mt = this->map_->type()->map_type(); + go_assert(mt != NULL); + Type_context index_context(mt->key_type(), false); + this->index_->determine_type(gogo, &index_context); + if (this->value_pointer_ != NULL) + this->value_pointer_->determine_type_no_context(gogo); +} + +void +Map_index_expression::do_check_types(Gogo*) +{ + // Types should have been checked before this was created, so this + // will probably never be called. Check it anyhow to be sure. + Map_type* mt = this->map_->type()->map_type(); + go_assert(mt != NULL); + if (!Type::are_assignable(mt->key_type(), this->index_->type(), NULL)) + this->report_error(_("incompatible type for map index")); +} + // We need to pass in a pointer to the key, so flatten the index into a // temporary variable if it isn't already. The value pointer will be // dereferenced and checked for nil, so flatten into a temporary to avoid @@ -14841,40 +16047,6 @@ Map_index_expression::do_type() return mt->val_type(); } -// Fix the type of a map index. - -void -Map_index_expression::do_determine_type(Gogo* gogo, const Type_context*) -{ - this->map_->determine_type_no_context(gogo); - Map_type* mt = this->get_map_type(); - Type* key_type = mt == NULL ? NULL : mt->key_type(); - Type_context subcontext(key_type, false); - this->index_->determine_type(gogo, &subcontext); -} - -// Check types of a map index. - -void -Map_index_expression::do_check_types(Gogo*) -{ - std::string reason; - Map_type* mt = this->get_map_type(); - if (mt == NULL) - return; - if (!Type::are_assignable(mt->key_type(), this->index_->type(), &reason)) - { - if (reason.empty()) - this->report_error(_("incompatible type for map index")); - else - { - go_error_at(this->location(), "incompatible type for map index (%s)", - reason.c_str()); - this->set_is_error(); - } - } -} - // Add explicit type conversions. void @@ -14987,6 +16159,7 @@ Map_index_expression::get_value_pointer(Gogo* gogo) this->value_pointer_ = Expression::make_unsafe_cast(Type::make_pointer_type(val_type), map_index, this->location()); + this->value_pointer_->determine_type_no_context(gogo); } return this->value_pointer_; @@ -15115,6 +16288,7 @@ Field_reference_expression::do_lower(Gogo* gogo, Named_object* function, e = Expression::make_unary(OPERATOR_AND, e, loc); Expression* call = Runtime::make_call(gogo, Runtime::FIELDTRACK, loc, 1, e); + call->determine_type_no_context(gogo); gogo->lower_expression(function, inserter, &call); inserter->insert(Statement::make_statement(call, false)); @@ -15424,12 +16598,13 @@ Interface_field_reference_expression::create_thunk(Gogo* gogo, loc); call->set_varargs_are_lowered(); - Statement* s = Statement::make_return_from_call(call, loc); + Statement* s = Statement::make_return_from_call(new_no, call, loc); + s->determine_types(gogo); gogo->add_statement(s); Block* b = gogo->finish_block(loc); gogo->add_block(b, loc); - // This is called after lowering but before determine_types. + // This is called after lowering. gogo->lower_block(new_no, b); gogo->finish_function(loc); @@ -15514,6 +16689,7 @@ Interface_field_reference_expression::do_get_backend(Translate_context* context) Bexpression* bnil_check = nil_check->get_backend(context); Expression* crash = Runtime::make_call(gogo, Runtime::PANIC_MEM, loc, 0); + crash->determine_type_no_context(gogo); Bexpression* bcrash = crash->get_backend(context); Bfunction* bfn = context->function()->func_value()->get_decl(); @@ -15802,34 +16978,65 @@ Struct_construction_expression::do_determine_type(Gogo* gogo, // Check types. void -Struct_construction_expression::do_check_types(Gogo*) +Struct_construction_expression::do_check_types(Gogo* gogo) { - if (this->vals() == NULL) - return; + Struct_construction_expression::check_value_types(gogo, this->type_, + this->vals(), + this->location()); +} - Struct_type* st = this->type_->struct_type(); - if (this->vals()->size() > st->field_count()) +// Check types. This static function is also called by +// Composite_literal_expression::do_check_types. Reports whether type +// checking succeeded. + +bool +Struct_construction_expression::check_value_types(Gogo* gogo, + Type* type, + Expression_list* vals, + Location loc) +{ + if (vals == NULL || vals->empty()) + return true; + + Struct_type* st = type->struct_type(); + if (vals->size() > st->field_count()) { - this->report_error(_("too many expressions for struct")); - return; + go_error_at(loc, "too many expressions for struct"); + return false; } + bool imported_type = + (type->named_type() != NULL + && type->named_type()->named_object()->package() != NULL); + + bool ret = true; const Struct_field_list* fields = st->fields(); - Expression_list::const_iterator pv = this->vals()->begin(); + Expression_list::const_iterator pv = 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 == vals->end()) { - this->report_error(_("too few expressions for struct")); - break; + go_error_at(loc, "too few expressions for struct"); + return false; } if (*pv == NULL) continue; + if (imported_type + && (Gogo::is_hidden_name(pf->field_name()) + || pf->is_embedded_builtin(gogo))) + { + go_error_at(loc, + "assignment of unexported field %qs in %qs literal", + Gogo::message_name(pf->field_name()).c_str(), + type->named_type()->message_name().c_str()); + ret = false; + } + std::string reason; if (!Type::are_assignable(pf->type(), (*pv)->type(), &reason)) { @@ -15842,10 +17049,11 @@ Struct_construction_expression::do_check_types(Gogo*) ("incompatible type for field %d in " "struct construction (%s)"), i + 1, reason.c_str()); - this->set_is_error(); + ret = false; } } - go_assert(pv == this->vals()->end()); + go_assert(pv == vals->end()); + return ret; } // Copy. @@ -16524,6 +17732,59 @@ Map_construction_expression::do_traverse(Traverse* traverse) return TRAVERSE_CONTINUE; } +void +Map_construction_expression::do_determine_type(Gogo* gogo, const Type_context*) +{ + Map_type* mt = this->type_->map_type(); + go_assert(mt != NULL); + Type_context key_context(mt->key_type(), false); + Type_context val_context(mt->val_type(), false); + if (this->vals_ != NULL) + { + for (Expression_list::const_iterator pv = this->vals_->begin(); + pv != this->vals_->end(); + ++pv) + { + (*pv)->determine_type(gogo, &key_context); + ++pv; + (*pv)->determine_type(gogo, &val_context); + } + } +} + +void +Map_construction_expression::do_check_types(Gogo*) +{ + // Types should have been checked before this was created, so this + // will probably never be called. Check it anyhow to be sure. + + if (this->vals_ == NULL) + return; + + Map_type* mt = this->type_->map_type(); + go_assert(mt != NULL); + Type* key_type = mt->key_type(); + Type* val_type = mt->val_type(); + for (Expression_list::const_iterator pv = this->vals_->begin(); + pv != this->vals_->end(); + ++pv) + { + if (!Type::are_assignable(key_type, (*pv)->type(), NULL)) + { + go_error_at((*pv)->location(), + "incompatible type for key in map composite literal"); + this->set_is_error(); + } + ++pv; + if (!Type::are_assignable(val_type, (*pv)->type(), NULL)) + { + go_error_at((*pv)->location(), + "incompatible type for value in map composite literal"); + this->set_is_error(); + } + } +} + // Flatten constructor initializer into a temporary variable since // we need to take its address for __go_construct_map. @@ -16604,68 +17865,13 @@ Map_construction_expression::do_flatten(Gogo* gogo, Named_object*, Statement::make_temporary(NULL, constructor, loc); constructor->issue_nil_check(); this->constructor_temp_->set_is_address_taken(); + this->constructor_temp_->determine_types(gogo); inserter->insert(this->constructor_temp_); } return this; } -// Final type determination. - -void -Map_construction_expression::do_determine_type(Gogo* gogo, const Type_context*) -{ - if (this->vals_ == NULL) - return; - - Map_type* mt = this->type_->map_type(); - Type_context key_context(mt->key_type(), false); - Type_context val_context(mt->val_type(), false); - for (Expression_list::const_iterator pv = this->vals_->begin(); - pv != this->vals_->end(); - ++pv) - { - (*pv)->determine_type(gogo, &key_context); - ++pv; - (*pv)->determine_type(gogo, &val_context); - } -} - -// Check types. - -void -Map_construction_expression::do_check_types(Gogo*) -{ - if (this->vals_ == NULL) - return; - - Map_type* mt = this->type_->map_type(); - int i = 0; - Type* key_type = mt->key_type(); - Type* val_type = mt->val_type(); - for (Expression_list::const_iterator pv = this->vals_->begin(); - pv != this->vals_->end(); - ++pv, ++i) - { - if (!Type::are_assignable(key_type, (*pv)->type(), NULL)) - { - 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)) - { - go_error_at((*pv)->location(), - ("incompatible type for element %d value " - "in map construction"), - i + 1); - this->set_is_error(); - } - } -} - // Copy. Expression* @@ -16752,9 +17958,11 @@ Map_construction_expression::do_get_backend(Translate_context* context) Expression* val_offset = Expression::make_struct_field_offset(this->element_type_, valfield); + Gogo* gogo = context->gogo(); Expression* map_ctor = - Runtime::make_call(context->gogo(), Runtime::CONSTRUCT_MAP, loc, 5, + Runtime::make_call(gogo, Runtime::CONSTRUCT_MAP, loc, 5, descriptor, count, entry_size, val_offset, ventries); + map_ctor->determine_type_no_context(gogo); return map_ctor->get_backend(context); } @@ -16795,7 +18003,7 @@ class Composite_literal_key_expression : public Parser_expression public: Composite_literal_key_expression(const std::string& name, Location location) : Parser_expression(EXPRESSION_COMPOSITE_LITERAL_KEY, location), - name_(name) + name_(name), expr_(NULL) { } const std::string& @@ -16803,6 +18011,12 @@ class Composite_literal_key_expression : public Parser_expression { return this->name_; } protected: + Type* + do_type(); + + void + do_determine_type(Gogo*, const Type_context*); + Expression* do_lower(Gogo*, Named_object*, Statement_inserter*, int); @@ -16818,17 +18032,26 @@ class Composite_literal_key_expression : public Parser_expression private: // The name. std::string name_; + // After we look up the name, a corresponding expression. + Expression* expr_; }; -// Lower a composite literal key. We will never get here for keys in -// composite literals of struct types, because that is prevented by -// Composite_literal_expression::do_traverse. So if we do get here, -// this must be a regular name reference after all. +// Determine the type of a composite literal key. We will never get +// here for keys in composite literals of struct types, because they +// will be handled by Composite_literal_expression::do_determine_type. +// So if we get here, this must be a regular name reference after all. -Expression* -Composite_literal_key_expression::do_lower(Gogo* gogo, Named_object*, - Statement_inserter*, int) +void +Composite_literal_key_expression::do_determine_type( + Gogo* gogo, + const Type_context* context) { + if (this->expr_ != NULL) + { + // Already resolved. + return; + } + Named_object* no = gogo->lookup(this->name_, NULL); if (no == NULL) { @@ -16841,10 +18064,32 @@ Composite_literal_key_expression::do_lower(Gogo* gogo, Named_object*, { go_error_at(this->location(), "reference to undefined name %qs", Gogo::message_name(this->name_).c_str()); - return Expression::make_error(this->location()); + this->set_is_error(); + return; } } - return Expression::make_unknown_reference(no, this->location()); + + this->expr_ = Expression::make_unknown_reference(no, this->location()); + this->expr_->determine_type(gogo, context); +} + +Type* +Composite_literal_key_expression::do_type() +{ + if (this->is_error_expression()) + return Type::make_error_type(); + go_assert(this->expr_ != NULL); + return this->expr_->type(); +} + +Expression* +Composite_literal_key_expression::do_lower(Gogo*, Named_object*, + Statement_inserter*, int) +{ + if (this->is_error_expression()) + return Expression::make_error(this->location()); + go_assert(this->expr_ != NULL); + return this->expr_; } // Dump a composite literal key. @@ -16941,98 +18186,170 @@ Composite_literal_expression::do_traverse(Traverse* traverse) return TRAVERSE_CONTINUE; } -// Lower a generic composite literal into a specific version based on -// the type. - -Expression* -Composite_literal_expression::do_lower(Gogo* gogo, Named_object* function, - Statement_inserter* inserter, int) +void +Composite_literal_expression::do_determine_type(Gogo* gogo, + const Type_context*) { + // Resolve the type if this composite literal is within another + // composite literal and has omitted the type. The DEPTH_ field + // tells us how deeply this one is embedded. Type* type = this->type_; - for (int depth = 0; depth < this->depth_; ++depth) { type = type->deref(); if (type->array_type() != NULL) type = type->array_type()->element_type(); else if (type->map_type() != NULL) - { - if (this->key_path_[depth]) - type = type->map_type()->key_type(); - else - type = type->map_type()->val_type(); - } + { + if (this->key_path_[depth]) + type = type->map_type()->key_type(); + else + type = type->map_type()->val_type(); + } else { if (!type->is_error()) - go_error_at(this->location(), - ("may only omit types within composite literals " - "of slice, array, or map type")); - return Expression::make_error(this->location()); + this->report_error(_("may only omit types within composite " + "literals of slice, array, or map type")); + else + { + go_assert(saw_errors()); + this->set_is_error(); + } + return; } } - Type *pt = type->points_to(); - bool is_pointer = false; - if (pt != NULL) + this->type_ = type; + this->depth_ = 0; + + type = type->deref(); + + if (this->vals_ == NULL || this->vals_->empty()) { - is_pointer = true; - type = pt; + // No value types to determine. + if (type->array_type() != NULL + && type->array_type()->length() != NULL + && type->array_type()->length()->is_nil_expression()) + this->resolve_array_length(type); + return; } - Expression* ret; - if (type->is_error()) - return Expression::make_error(this->location()); - else if (type->struct_type() != NULL) - ret = this->lower_struct(gogo, type); - else if (type->array_type() != NULL) - ret = this->lower_array(type); - else if (type->map_type() != NULL) - ret = this->lower_map(gogo, function, inserter, type); - else + if (type->struct_type() != NULL && this->has_keys_) { - go_error_at(this->location(), - ("expected struct, slice, array, or map type " - "for composite literal")); - return Expression::make_error(this->location()); + // Rewrite the value list by removing the struct field keys. We + // do this now rather than during lowering because handling + // struct keys is painful. We don't need to do this for + // slice/array/map literals, because it's easy to determine + // their types with or without the keys. + if (!this->resolve_struct_keys(gogo, type)) + { + this->set_is_error(); + delete this->vals_; + this->vals_ = NULL; + this->has_keys_ = false; + return; + } } - if (is_pointer) - ret = Expression::make_heap_expression(ret, this->location()); - - return ret; -} - -// Lower a struct composite literal. - -Expression* -Composite_literal_expression::lower_struct(Gogo* gogo, Type* type) -{ - Location location = this->location(); - Struct_type* st = type->struct_type(); - if (this->vals_ == NULL || !this->has_keys_) + if (type->struct_type() != NULL) { - if (this->vals_ != NULL - && !this->vals_->empty() - && type->named_type() != NULL - && type->named_type()->named_object()->package() != NULL) + const Struct_field_list* fields = type->struct_type()->fields(); + Expression_list::const_iterator pv = this->vals_->begin(); + for (Struct_field_list::const_iterator pf = fields->begin(); + pf != fields->end(); + ++pf, ++pv) { - for (Struct_field_list::const_iterator pf = st->fields()->begin(); - pf != st->fields()->end(); - ++pf) + if (pv == this->vals_->end()) + return; + if (*pv != NULL) { - if (Gogo::is_hidden_name(pf->field_name()) - || pf->is_embedded_builtin(gogo)) - 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()); + Type_context subcontext(pf->type(), false); + (*pv)->determine_type(gogo, &subcontext); } } + // Extra values are an error we will report in the check_types + // pass; we still want to determine the type to avoid knockon + // errors. + for (; pv != this->vals_->end(); ++pv) + (*pv)->determine_type_no_context(gogo); + } + else if (type->array_type() != NULL) + { + Array_type* at = type->array_type(); + Type_context intcontext(Type::lookup_integer_type("int"), false); + Type_context subcontext(at->element_type(), false); + for (Expression_list::const_iterator pv = this->vals_->begin(); + pv != this->vals_->end(); + ++pv) + { + if (this->has_keys_) + { + if (*pv != NULL) + (*pv)->determine_type(gogo, &intcontext); + ++pv; + if (pv == this->vals_->end()) + break; + } + + if (*pv != NULL) + (*pv)->determine_type(gogo, &subcontext); + } + + if (at->length() != NULL && at->length()->is_nil_expression()) + this->resolve_array_length(type); + } + else if (type->map_type() != NULL) + { + if (!this->has_keys_) + { + this->report_error(_("map composite literal must have keys")); + return; + } - return new Struct_construction_expression(type, this->vals_, location); + Map_type* mt = type->map_type(); + Type_context key_context(mt->key_type(), false); + Type_context val_context(mt->val_type(), false); + for (Expression_list::const_iterator pv = this->vals_->begin(); + pv != this->vals_->end(); + ++pv) + { + if (*pv != NULL) + (*pv)->determine_type(gogo, &key_context); + ++pv; + if (*pv != NULL) + (*pv)->determine_type(gogo, &val_context); + } + } + else + { + // We'll report this as an error in the check_types pass. + // Determine types to avoid knockon errors. + for (Expression_list::const_iterator pv = this->vals_->begin(); + pv != this->vals_->end(); + ++pv) + { + if (*pv != NULL) + (*pv)->determine_type_no_context(gogo); + } } +} + +Type* +Composite_literal_expression::do_type() +{ + if (this->is_error_expression()) + return Type::make_error_type(); + go_assert(this->depth_ == 0); + return this->type_; +} + +// Resolve the field keys of a struct composite literal. +bool +Composite_literal_expression::resolve_struct_keys(Gogo* gogo, Type* type) +{ + Struct_type* st = type->struct_type(); size_t field_count = st->field_count(); std::vector<Expression*> vals(field_count); std::vector<unsigned long>* traverse_order = new(std::vector<unsigned long>); @@ -17052,8 +18369,8 @@ Composite_literal_expression::lower_struct(Gogo* gogo, Type* type) if (name_expr == NULL) { go_error_at(val->location(), - "mixture of field and value initializers"); - return Expression::make_error(location); + "mixture of field and value initializers"); + return false; } bool bad_key = false; @@ -17075,7 +18392,8 @@ Composite_literal_expression::lower_struct(Gogo* gogo, Type* type) // this incorrect lookup as a usage of the object's package. no = name_expr->unknown_expression()->named_object(); if (no->package() != NULL - && no->package() != type->named_type()->named_object()->package()) + && (no->package() + != type->named_type()->named_object()->package())) no->package()->forget_usage(name_expr); } break; @@ -17114,7 +18432,7 @@ Composite_literal_expression::lower_struct(Gogo* gogo, Type* type) if (bad_key) { go_error_at(name_expr->location(), "expected struct field name"); - return Expression::make_error(location); + return false; } if (no != NULL) @@ -17145,32 +18463,23 @@ Composite_literal_expression::lower_struct(Gogo* gogo, Type* type) if (sf == NULL) { 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); + Gogo::message_name(name).c_str(), + (type->named_type() != NULL + ? type->named_type()->message_name().c_str() + : "unnamed struct")); + return false; } if (vals[index] != NULL) { 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); + "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 false; } - if (type->named_type() != NULL - && type->named_type()->named_object()->package() != NULL - && (Gogo::is_hidden_name(sf->field_name()) - || sf->is_embedded_builtin(gogo))) - 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(static_cast<unsigned long>(index)); } @@ -17189,7 +18498,7 @@ Composite_literal_expression::lower_struct(Gogo* gogo, Type* type) (type->named_type() != NULL ? type->named_type()->message_name().c_str() : "unnamed struct")); - return Expression::make_error(location); + return false; } Expression_list* list = new Expression_list; @@ -17197,9 +18506,200 @@ Composite_literal_expression::lower_struct(Gogo* gogo, Type* type) for (size_t i = 0; i < field_count; ++i) list->push_back(vals[i]); + this->vals_ = list; + this->traverse_order_ = traverse_order; + this->has_keys_ = false; + + return true; +} + +// Handle [...]{...} + +void +Composite_literal_expression::resolve_array_length(Type* type) +{ + size_t size; + if (this->vals_ == NULL || this->vals_->empty()) + size = 0; + else if (!this->has_keys_) + size = this->vals_->size(); + else + { + unsigned long index = 0; + size = 0; + for (Expression_list::const_iterator pv = this->vals_->begin(); + pv != this->vals_->end(); + pv += 2) + { + Expression* index_expr = *pv; + if (index_expr != NULL) + { + Numeric_constant nc; + unsigned long iv; + if (!index_expr->numeric_constant_value(&nc) + || nc.to_unsigned_long(&iv) != Numeric_constant::NC_UL_VALID) + { + // We will report an error when lowering. + break; + } + index = iv; + } + + if (index >= size) + size = index + 1; + + ++index; + } + } + + Expression* elen = Expression::make_integer_ul(size, NULL, this->location()); + this->type_ = Type::make_array_type(type->array_type()->element_type(), + elen); +} + +void +Composite_literal_expression::do_check_types(Gogo* gogo) +{ + if (this->is_error_expression() || this->type_->is_error()) + { + go_assert(saw_errors()); + return; + } + go_assert(this->depth_ == 0); + + Type* type = this->type_->deref(); + if (type->struct_type() != NULL) + { + go_assert(!this->has_keys_); + if (!Struct_construction_expression::check_value_types(gogo, type, + this->vals_, + this->location())) + this->set_is_error(); + } + else if (type->array_type() != NULL) + { + Type* element_type = type->array_type()->element_type(); + if (element_type->is_error()) + { + go_assert(saw_errors()); + return; + } + if (this->vals_ == NULL || this->vals_->empty()) + return; + int i = 0; + for (Expression_list::const_iterator pv = this->vals_->begin(); + pv != this->vals_->end(); + ++pv, ++i) + { + if (this->has_keys_) + { + // We check the key type in the lowering pass. + ++pv; + if (pv == this->vals_->end()) + break; + } + if (*pv != NULL + && !Type::are_assignable(element_type, (*pv)->type(), NULL)) + { + go_error_at((*pv)->location(), + ("incompatible type for element %d " + "in composite literal"), + i + 1); + this->set_is_error(); + } + } + } + else if (type->map_type() != NULL) + { + if (this->vals_ == NULL || this->vals_->empty()) + return; + if (!this->has_keys_) + { + this->report_error(_("map composite literal must have keys")); + return; + } + int i = 0; + Map_type* mt = type->map_type(); + Type* key_type = mt->key_type(); + Type* val_type = mt->val_type(); + for (Expression_list::const_iterator pv = this->vals_->begin(); + pv != this->vals_->end(); + ++pv, ++i) + { + if (*pv != NULL + && !Type::are_assignable(key_type, (*pv)->type(), NULL)) + { + 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)) + { + go_error_at((*pv)->location(), + ("incompatible type for element %d value " + "in map construction"), + i + 1); + this->set_is_error(); + } + } + } + else + { + this->report_error(_("expected struct, slice, array, or map type " + "for composite literal")); + } +} + +// Lower a generic composite literal into a specific version based on +// the type. + +Expression* +Composite_literal_expression::do_lower(Gogo* gogo, Named_object* function, + Statement_inserter* inserter, int) +{ + if (this->is_error_expression() || this->type_->is_error()) + return Expression::make_error(this->location()); + go_assert(this->depth_ == 0); + + Type* type = this->type_; + Type *pt = type->points_to(); + bool is_pointer = false; + if (pt != NULL) + { + is_pointer = true; + type = pt; + } + + Expression* ret; + if (type->is_error()) + return Expression::make_error(this->location()); + else if (type->struct_type() != NULL) + ret = this->lower_struct(type); + else if (type->array_type() != NULL) + ret = this->lower_array(type); + else if (type->map_type() != NULL) + ret = this->lower_map(gogo, function, inserter, type); + else + go_unreachable(); + + if (is_pointer) + ret = Expression::make_heap_expression(ret, this->location()); + + return ret; +} + +// Lower a struct composite literal. + +Expression* +Composite_literal_expression::lower_struct(Type* type) +{ + go_assert(!this->has_keys_); Struct_construction_expression* ret = - new Struct_construction_expression(type, list, location); - ret->set_traverse_order(traverse_order); + new Struct_construction_expression(type, this->vals_, this->location()); + ret->set_traverse_order(this->traverse_order_); return ret; } @@ -17376,32 +18876,9 @@ Composite_literal_expression::make_array( Location location = this->location(); Array_type* at = type->array_type(); - if (at->length() != NULL && at->length()->is_nil_expression()) - { - size_t size; - if (vals == NULL) - size = 0; - else if (indexes != NULL) - size = indexes->back() + 1; - else - { - size = vals->size(); - Integer_type* it = Type::lookup_integer_type("int")->integer_type(); - if (sizeof(size) <= static_cast<size_t>(it->bits() * 8) - && size >> (it->bits() - 1) != 0) - { - go_error_at(location, "too many elements in composite literal"); - return Expression::make_error(location); - } - } - - Expression* elen = Expression::make_integer_ul(size, NULL, location); - at = Type::make_array_type(at->element_type(), elen); - type = at; - } - else if (at->length() != NULL - && !at->length()->is_error_expression() - && this->vals_ != NULL) + if (at->length() != NULL + && !at->length()->is_error_expression() + && this->vals_ != NULL) { Numeric_constant nc; unsigned long val; @@ -17452,11 +18929,7 @@ Composite_literal_expression::lower_map(Gogo* gogo, Named_object* function, bool saw_true = false; if (this->vals_ != NULL) { - if (!this->has_keys_) - { - go_error_at(location, "map composite literal must have keys"); - return Expression::make_error(location); - } + go_assert(this->has_keys_); for (Expression_list::iterator p = this->vals_->begin(); p != this->vals_->end(); @@ -17522,8 +18995,9 @@ Composite_literal_expression::lower_map(Gogo* gogo, Named_object* function, mit->second.push_back(*p); } } - else if ((*p)->numeric_constant_value(&nval)) // Check numeric keys. + else if ((*p)->numeric_constant_value(&nval)) { + // Check numeric keys. unsigned int h = nval.hash(0); Unordered_map(unsigned int, std::vector<Expression*>)::iterator mit; mit = nt.find(h); @@ -18086,7 +19560,9 @@ Receive_expression::do_get_backend(Translate_context* context) recv_addr = Expression::make_unary(OPERATOR_AND, recv_addr, loc); Expression* recv = Runtime::make_call(gogo, Runtime::CHANRECV1, loc, 2, this->channel_, recv_addr); - return Expression::make_compound(recv, recv_ref, loc)->get_backend(context); + Expression* ret = Expression::make_compound(recv, recv_ref, loc); + ret->determine_type_no_context(gogo); + return ret->get_backend(context); } // Export a receive expression. @@ -18830,8 +20306,7 @@ class Interface_value_expression : public Expression { return this->type_; } void - do_determine_type(Gogo*, const Type_context*) - { go_unreachable(); } + do_determine_type(Gogo*, const Type_context*); Expression* do_copy() @@ -18866,6 +20341,13 @@ Interface_value_expression::do_traverse(Traverse* traverse) return TRAVERSE_CONTINUE; } +void +Interface_value_expression::do_determine_type(Gogo* gogo, const Type_context*) +{ + this->first_field_->determine_type_no_context(gogo); + this->obj_->determine_type_no_context(gogo); +} + Bexpression* Interface_value_expression::do_get_backend(Translate_context* context) { @@ -18926,7 +20408,7 @@ class Interface_mtable_expression : public Expression void do_determine_type(Gogo*, const Type_context*) - { go_unreachable(); } + { } Expression* do_copy() |