diff options
Diffstat (limited to 'gcc/go')
-rw-r--r-- | gcc/go/gofrontend/MERGE | 2 | ||||
-rw-r--r-- | gcc/go/gofrontend/expressions.cc | 3684 | ||||
-rw-r--r-- | gcc/go/gofrontend/expressions.h | 236 | ||||
-rw-r--r-- | gcc/go/gofrontend/go.cc | 21 | ||||
-rw-r--r-- | gcc/go/gofrontend/gogo.cc | 209 | ||||
-rw-r--r-- | gcc/go/gofrontend/gogo.h | 18 | ||||
-rw-r--r-- | gcc/go/gofrontend/parse.cc | 15 | ||||
-rw-r--r-- | gcc/go/gofrontend/runtime.cc | 10 | ||||
-rw-r--r-- | gcc/go/gofrontend/statements.cc | 1198 | ||||
-rw-r--r-- | gcc/go/gofrontend/statements.h | 84 | ||||
-rw-r--r-- | gcc/go/gofrontend/types.cc | 118 | ||||
-rw-r--r-- | gcc/go/gofrontend/types.h | 22 | ||||
-rw-r--r-- | gcc/go/gofrontend/wb.cc | 12 |
13 files changed, 4034 insertions, 1595 deletions
diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index 5e8677b..b41ac99 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -f5d708fd905d3f91d848a0ea25c77119f8af0c36 +61b29a99dadf33c48a0a063f50f61e877fb419b8 The first line of this file holds the git revision number of the last merge done from the gofrontend repository. 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() diff --git a/gcc/go/gofrontend/expressions.h b/gcc/go/gofrontend/expressions.h index d5df724..8763772 100644 --- a/gcc/go/gofrontend/expressions.h +++ b/gcc/go/gofrontend/expressions.h @@ -596,7 +596,8 @@ class Expression { return this->do_is_static_initializer(); } // If this is not a numeric constant, return false. If it is one, - // return true, and set VAL to hold the value. + // return true, and set VAL to hold the value. This method can be + // called before the determine_types pass. bool numeric_constant_value(Numeric_constant* val) { return this->do_numeric_constant_value(val); } @@ -633,8 +634,7 @@ class Expression // Return whether this expression really represents a type. bool - is_type_expression() const - { return this->classification_ == EXPRESSION_TYPE; } + is_type_expression() const; // If this is a const reference, return the Const_expression // structure. Otherwise, return NULL. This is a controlled dynamic @@ -735,6 +735,10 @@ class Expression unary_expression() { return this->convert<Unary_expression, EXPRESSION_UNARY>(); } + const Unary_expression* + unary_expression() const + { return this->convert<const Unary_expression, EXPRESSION_UNARY>(); } + // If this is a binary expression, return the Binary_expression // structure. Otherwise return NULL. Binary_expression* @@ -1022,10 +1026,8 @@ class Expression void determine_type_no_context(Gogo*); - // Return the current type of the expression. This may be changed - // by determine_type. This should not be called before the lowering - // pass, unless the is_type_expression method returns true (i.e., - // this is an EXPRESSION_TYPE). + // Return the type of the expression. This should not be called + // before the determine_types pass. Type* type() { return this->do_type(); } @@ -1472,17 +1474,6 @@ class Parser_expression : public Expression virtual Expression* do_lower(Gogo*, Named_object*, Statement_inserter*, int) = 0; - Type* - do_type(); - - void - do_determine_type(Gogo*, const Type_context*) - { go_unreachable(); } - - void - do_check_types(Gogo*) - { go_unreachable(); } - Bexpression* do_get_backend(Translate_context*) { go_unreachable(); } @@ -1495,7 +1486,8 @@ class Const_expression : public Expression public: Const_expression(Named_object* constant, Location location) : Expression(EXPRESSION_CONST_REFERENCE, location), - constant_(constant), type_(NULL), seen_(false) + constant_(constant), type_(NULL), iota_value_(0), seen_(false), + is_iota_(false) { } Named_object* @@ -1510,6 +1502,10 @@ class Const_expression : public Expression void check_for_init_loop(); + // Set the iota value if this is a reference to iota. + void + set_iota_value(int); + protected: int do_traverse(Traverse*); @@ -1576,9 +1572,14 @@ class Const_expression : public Expression // The type of this reference. This is used if the constant has an // abstract type. Type* type_; + // If this const is a reference to the predeclared iota value, the + // value to use. + int iota_value_; // Used to prevent infinite recursion when a constant incorrectly // refers to itself. mutable bool seen_; + // Whether this const is a reference to the predeclared iota value. + bool is_iota_; }; // An expression which is simply a variable. @@ -1976,8 +1977,7 @@ class Type_conversion_expression : public Expression do_boolean_constant_value(bool*); Type* - do_type() - { return this->type_; } + do_type(); void do_determine_type(Gogo*, const Type_context*); @@ -2074,7 +2074,7 @@ class Unary_expression : public Expression Unary_expression(Operator op, Expression* expr, Location location) : Expression(EXPRESSION_UNARY, location), op_(op), escapes_(true), create_temp_(false), is_gc_root_(false), - is_slice_init_(false), expr_(expr), + is_slice_init_(false), expr_(expr), type_(NULL), issue_nil_check_(NIL_CHECK_DEFAULT) { } @@ -2131,7 +2131,7 @@ class Unary_expression : public Expression // could be done, false if not. On overflow, issues an error and // sets *ISSUED_ERROR. static bool - eval_constant(Operator op, const Numeric_constant* unc, + eval_constant(Type*, Operator op, const Numeric_constant* unc, Location, Numeric_constant* nc, bool *issued_error); static Expression* @@ -2246,6 +2246,8 @@ class Unary_expression : public Expression bool is_slice_init_; // The operand. Expression* expr_; + // The type of the expression. Not used for AND and MULT. + Type* type_; // Whether or not to issue a nil check for this expression if its address // is being taken. Nil_check_classification issue_nil_check_; @@ -2372,15 +2374,15 @@ class Binary_expression : public Expression static bool eval_integer(Operator op, const Numeric_constant*, const Numeric_constant*, - Location, Numeric_constant*); + Location, Numeric_constant*, bool* issued_error); static bool eval_float(Operator op, const Numeric_constant*, const Numeric_constant*, - Location, Numeric_constant*); + Location, Numeric_constant*, bool* issued_error); static bool eval_complex(Operator op, const Numeric_constant*, const Numeric_constant*, - Location, Numeric_constant*); + Location, Numeric_constant*, bool* issued_error); static bool compare_integer(const Numeric_constant*, const Numeric_constant*, int*); @@ -2412,7 +2414,7 @@ class Binary_expression : public Expression Expression* left_; // The right hand side operand. Expression* right_; - // The type of a comparison operation. + // The type of the expression. Type* type_; }; @@ -2493,8 +2495,8 @@ class Call_expression : public Expression Call_expression(Expression* fn, Expression_list* args, bool is_varargs, Location location) : Expression(EXPRESSION_CALL, location), - fn_(fn), args_(args), type_(NULL), call_(NULL), call_temp_(NULL) - , expected_result_count_(0), is_varargs_(is_varargs), + fn_(fn), args_(args), type_(NULL), lowered_(NULL), call_(NULL), + call_temp_(NULL), expected_result_count_(0), is_varargs_(is_varargs), varargs_are_lowered_(false), types_are_determined_(false), is_deferred_(false), is_concurrent_(false), is_equal_function_(false), issued_error_(false), is_multi_value_arg_(false), is_flattened_(false) @@ -2530,7 +2532,8 @@ class Call_expression : public Expression // Set the number of results expected from this call. This is used // when the call appears in a context that expects multiple results, - // such as a, b = f(). + // such as a, b = f(). This must be called before the + // determine_types pass. void set_expected_result_count(size_t); @@ -2616,6 +2619,10 @@ class Call_expression : public Expression inline const Builtin_call_expression* builtin_call_expression() const; + // Lower to a Builtin_call_expression if appropriate. + Expression* + lower_builtin(Gogo*); + protected: int do_traverse(Traverse*); @@ -2627,12 +2634,20 @@ class Call_expression : public Expression do_flatten(Gogo*, Named_object*, Statement_inserter*); bool - do_discarding_value() - { return true; } + do_discarding_value(); virtual Type* do_type(); + virtual bool + do_is_constant() const; + + bool + do_is_untyped(Type**) const; + + bool + do_numeric_constant_value(Numeric_constant*); + virtual void do_determine_type(Gogo*, const Type_context*); @@ -2665,17 +2680,26 @@ class Call_expression : public Expression set_args(Expression_list* args) { this->args_ = args; } - // Let a builtin expression lower varargs. - void - lower_varargs(Gogo*, Named_object* function, Statement_inserter* inserter, - Type* varargs_type, size_t param_count, - Slice_storage_escape_disp escape_disp); - // Let a builtin expression check whether types have been // determined. bool determining_types(); + // Let a builtin expression retrieve the expected type. + Type* + type() + { return this->type_; } + + // Let a builtin expression set the expected type. + void + set_type(Type* type) + { this->type_ = type; } + + // Let a builtin expression simply f(g()) where g returns multiple + // results. + void + simplify_multiple_results(Gogo*); + void export_arguments(Export_function_body*) const; @@ -2687,7 +2711,10 @@ class Call_expression : public Expression private: bool - check_argument_type(int, const Type*, const Type*, Location, bool); + rewrite_varargs(); + + bool + check_argument_type(int, const Type*, const Type*, Location); Expression* intrinsify(Gogo*, Statement_inserter*); @@ -2706,6 +2733,8 @@ class Call_expression : public Expression Expression_list* args_; // The type of the expression, to avoid recomputing it. Type* type_; + // If not NULL, this is a lowered version of this Call_expression. + Expression* lowered_; // The backend expression for the call, used for a call which returns a tuple. Bexpression* call_; // A temporary variable to store this call if the function returns a tuple. @@ -3087,7 +3116,8 @@ class Unknown_expression : public Parser_expression public: Unknown_expression(Named_object* named_object, Location location) : Parser_expression(EXPRESSION_UNKNOWN_REFERENCE, location), - named_object_(named_object), no_error_message_(false) + named_object_(named_object), lowered_(NULL), iota_value_(0), + no_error_message_(false), is_iota_(false) { } // The associated named object. @@ -3106,7 +3136,38 @@ class Unknown_expression : public Parser_expression set_no_error_message() { this->no_error_message_ = true; } + // Set the iota value if this is a reference to iota. + void + set_iota_value(int); + protected: + int + do_traverse(Traverse*); + + Type* + do_type(); + + void + do_determine_type(Gogo*, const Type_context*); + + bool + do_is_constant() const; + + bool + do_is_untyped(Type**) const; + + virtual bool + do_numeric_constant_value(Numeric_constant*); + + virtual bool + do_string_constant_value(std::string*); + + virtual bool + do_boolean_constant_value(bool*); + + bool + do_is_addressable() const; + Expression* do_lower(Gogo*, Named_object*, Statement_inserter*, int); @@ -3120,9 +3181,15 @@ class Unknown_expression : public Parser_expression private: // The unknown name. Named_object* named_object_; + // The fully resolved expression. + Expression* lowered_; + // The iota value if this turns out to be a reference to iota. + int iota_value_; // True if we should not give errors if this is undefined. This is // used if there was a parse failure. bool no_error_message_; + // True if this could be a reference to iota. + bool is_iota_; }; // An index expression. This is lowered to an array index, a string @@ -3134,9 +3201,15 @@ class Index_expression : public Parser_expression Index_expression(Expression* left, Expression* start, Expression* end, Expression* cap, Location location) : Parser_expression(EXPRESSION_INDEX, location), - left_(left), start_(start), end_(end), cap_(cap) + left_(left), start_(start), end_(end), cap_(cap), + needs_nil_check_(false) { } + // Return the expression being indexed. + Expression* + left() const + { return this->left_; } + // Dump an index expression, i.e. an expression of the form // expr[expr], expr[expr:expr], or expr[expr:expr:expr] to a dump context. static void @@ -3144,24 +3217,44 @@ class Index_expression : public Parser_expression const Expression* start, const Expression* end, const Expression* cap); + // Report whether EXPR is a map index expression. + static bool + is_map_index(Expression* expr); + protected: int do_traverse(Traverse*); + Type* + do_type(); + + void + do_determine_type(Gogo*, const Type_context*); + + void + do_check_types(Gogo*); + + bool + do_is_addressable() const; + Expression* do_lower(Gogo*, Named_object*, Statement_inserter*, int); Expression* do_copy() { - return new Index_expression(this->left_->copy(), this->start_->copy(), - (this->end_ == NULL - ? NULL - : this->end_->copy()), - (this->cap_ == NULL - ? NULL - : this->cap_->copy()), - this->location()); + Index_expression* ret = + new Index_expression(this->left_->copy(), this->start_->copy(), + (this->end_ == NULL + ? NULL + : this->end_->copy()), + (this->cap_ == NULL + ? NULL + : this->cap_->copy()), + this->location()); + if (this->needs_nil_check_) + ret->needs_nil_check_ = true; + return ret; } // This shouldn't be called--we don't know yet. @@ -3173,8 +3266,8 @@ class Index_expression : public Parser_expression do_dump_expression(Ast_dump_context*) const; void - do_issue_nil_check() - { this->left_->issue_nil_check(); } + do_issue_nil_check(); + private: // The expression being indexed. Expression* left_; @@ -3187,6 +3280,9 @@ class Index_expression : public Parser_expression // default capacity, non-NULL for indices and slices that specify the // capacity. Expression* cap_; + // True if this needs a nil check. This changes how we handle + // dereferencing a pointer to an array. + bool needs_nil_check_; }; // An array index. This is used for both indexing and slicing. @@ -3234,6 +3330,11 @@ class Array_index_expression : public Expression set_needs_bounds_check(bool b) { this->needs_bounds_check_ = b; } + // Check indexes. + static bool + check_indexes(Expression* array, Expression* start, Expression* len, + Expression* cap, Location); + protected: int do_traverse(Traverse*); @@ -3339,6 +3440,11 @@ class String_index_expression : public Expression end() const { return this->end_; } + // Check indexes. + static bool + check_indexes(Expression* string, Expression* start, Expression* len, + Location); + protected: int do_traverse(Traverse*); @@ -3832,7 +3938,8 @@ class Composite_literal_expression : public Parser_expression Location location) : Parser_expression(EXPRESSION_COMPOSITE_LITERAL, location), type_(type), depth_(depth), vals_(vals), has_keys_(has_keys), - all_are_names_(all_are_names), key_path_(std::vector<bool>(depth)) + all_are_names_(all_are_names), key_path_(std::vector<bool>(depth)), + traverse_order_(NULL) {} @@ -3848,6 +3955,15 @@ class Composite_literal_expression : public Parser_expression int do_traverse(Traverse* traverse); + Type* + do_type(); + + void + do_determine_type(Gogo*, const Type_context*); + + void + do_check_types(Gogo*); + Expression* do_lower(Gogo*, Named_object*, Statement_inserter*, int); @@ -3858,8 +3974,14 @@ class Composite_literal_expression : public Parser_expression do_dump_expression(Ast_dump_context*) const; private: + bool + resolve_struct_keys(Gogo*, Type* type); + + void + resolve_array_length(Type*); + Expression* - lower_struct(Gogo*, Type*); + lower_struct(Type*); Expression* lower_array(Type*); @@ -3888,6 +4010,10 @@ class Composite_literal_expression : public Parser_expression // a value. This is used to decide which type to use when given a map literal // with omitted key types. std::vector<bool> key_path_; + // If not NULL, the order in which to traverse vals_ for a struct + // composite literal. This is used so that we implement the order + // of evaluation rules correctly. + std::vector<unsigned long>* traverse_order_; }; // Helper/mixin class for struct and array construction expressions; @@ -3948,6 +4074,10 @@ class Struct_construction_expression : public Expression, bool is_constant_struct() const; + // Check types of a struct composite literal. + static bool + check_value_types(Gogo*, Type*, Expression_list*, Location); + protected: int do_traverse(Traverse* traverse); diff --git a/gcc/go/gofrontend/go.cc b/gcc/go/gofrontend/go.cc index 66d4816..86fe77c 100644 --- a/gcc/go/gofrontend/go.cc +++ b/gcc/go/gofrontend/go.cc @@ -118,36 +118,39 @@ go_parse_input_files(const char** filenames, unsigned int filename_count, ::gogo->add_linkname(p->first, p->second.is_exported, p->second.ext_name, p->second.loc); + // Lower calls to builtin functions. + ::gogo->lower_builtin_calls(); + // Finalize method lists and build stub methods for named types. ::gogo->finalize_methods(); // Check that functions have a terminating statement. ::gogo->check_return_statements(); - // Now that we have seen all the names, lower the parse tree into a - // form which is easier to use. - ::gogo->lower_parse_tree(); - // At this point we have handled all inline functions, so we no // longer need the linemap. ::gogo->linemap()->stop(); - // Create function descriptors as needed. - ::gogo->create_function_descriptors(); + // Work out types of unspecified constants and variables. + ::gogo->determine_types(); // Now that we have seen all the names, verify that types are // correct. ::gogo->verify_types(); - // Work out types of unspecified constants and variables. - ::gogo->determine_types(); - // Check types and issue errors as appropriate. ::gogo->check_types(); + // Now that we have seen all the names and we know all the types, + // lower the parse tree into a form which is easier to use. + ::gogo->lower_parse_tree(); + if (only_check_syntax) return; + // Create function descriptors as needed. + ::gogo->create_function_descriptors(); + // Record global variable initializer dependencies. ::gogo->record_global_init_refs(); diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc index 3c021b9..7a6b9e3 100644 --- a/gcc/go/gofrontend/gogo.cc +++ b/gcc/go/gofrontend/gogo.cc @@ -2998,10 +2998,7 @@ Lower_parse_tree::constant(Named_object* no, bool) return TRAVERSE_CONTINUE; nc->set_lowering(); - go_assert(this->iota_value_ == -1); - this->iota_value_ = nc->iota_value(); nc->traverse_expression(this); - this->iota_value_ = -1; nc->clear_lowering(); @@ -3018,8 +3015,6 @@ Lower_parse_tree::constant(Named_object* no, bool) int Lower_parse_tree::function(Named_object* no) { - no->func_value()->set_closure_type(); - go_assert(this->function_ == NULL); this->function_ = no; int t = no->func_value()->traverse(this); @@ -3482,6 +3477,43 @@ Gogo::create_function_descriptors() this->traverse(&cfd); } +// Lower calls to builtin functions. We need to do this early because +// some builtin calls are constant expressions. In particular we need +// to do this before finalize_methods, because finalize_methods calls +// is_direct_iface_type, which needs to know whether something like +// [unsafe.Sizeof(byte(0))]*byte is a direct-iface type. + +class Lower_builtin_calls : public Traverse +{ + public: + Lower_builtin_calls(Gogo* gogo) + : Traverse(traverse_expressions), + gogo_(gogo) + { } + + int + expression(Expression**); + + private: + Gogo* gogo_; +}; + +int +Lower_builtin_calls::expression(Expression** pexpr) +{ + Call_expression* ce = (*pexpr)->call_expression(); + if (ce != NULL) + *pexpr = ce->lower_builtin(this->gogo_); + return TRAVERSE_CONTINUE; +} + +void +Gogo::lower_builtin_calls() +{ + Lower_builtin_calls lbc(this); + this->traverse(&lbc); +} + // Finalize the methods of an interface type. int @@ -3625,47 +3657,7 @@ Gogo::finalize_methods_for_type(Type* type) void Gogo::determine_types() { - Bindings* bindings = this->current_bindings(); - for (Bindings::const_definitions_iterator p = bindings->begin_definitions(); - p != bindings->end_definitions(); - ++p) - { - if ((*p)->is_function()) - (*p)->func_value()->determine_types(this); - else if ((*p)->is_variable()) - (*p)->var_value()->determine_type(this); - else if ((*p)->is_const()) - (*p)->const_value()->determine_type(this); - - // See if a variable requires us to build an initialization - // function. We know that we will see all global variables - // here. - if (!this->need_init_fn_ && (*p)->is_variable()) - { - Variable* variable = (*p)->var_value(); - - // If this is a global variable which requires runtime - // initialization, we need an initialization function. - if (!variable->is_global()) - ; - else if (variable->init() == NULL) - ; - else if (variable->type()->interface_type() != NULL) - this->need_init_fn_ = true; - else if (variable->init()->is_constant()) - ; - else if (!variable->init()->is_composite_literal()) - this->need_init_fn_ = true; - else if (variable->init()->is_nonconstant_composite_literal()) - this->need_init_fn_ = true; - - // If this is a global variable which holds a pointer value, - // then we need an initialization function to register it as a - // GC root. - if (variable->is_global() && variable->type()->has_pointer()) - this->need_init_fn_ = true; - } - } + this->current_bindings()->determine_types(this); // Determine the types of constants in packages. for (Packages::const_iterator p = this->packages_.begin(); @@ -3756,6 +3748,7 @@ Check_types_traverse::variable(Named_object* named_object) no->message_name().c_str()); } } + if (!var->is_used() && !var->is_global() && !var->is_parameter() @@ -3763,8 +3756,15 @@ Check_types_traverse::variable(Named_object* named_object) && !var->type()->is_error() && (init == NULL || !init->is_error_expression()) && !Lex::is_invalid_identifier(named_object->name())) - go_error_at(var->location(), "%qs declared but not used", - named_object->message_name().c_str()); + { + // Avoid giving an error if the initializer is invalid. + if (init != NULL) + init->check_types(this->gogo_); + + if (init == NULL || !init->is_error_expression()) + go_error_at(var->location(), "%qs declared but not used", + named_object->message_name().c_str()); + } } return TRAVERSE_CONTINUE; } @@ -3788,6 +3788,11 @@ Check_types_traverse::constant(Named_object* named_object, bool) go_error_at(constant->location(), "invalid constant type"); constant->set_error(); } + else if (constant->expr()->is_error_expression()) + { + go_assert(saw_errors()); + constant->set_error(); + } else if (!constant->expr()->is_constant()) { go_error_at(constant->expr()->location(), "expression is not constant"); @@ -4396,6 +4401,7 @@ Shortcuts::convert_shortcut(Block* enclosing, Expression** pshortcut) Statement* if_statement = Statement::make_if_statement(cond, block, NULL, loc); + if_statement->determine_types(this->gogo_); retblock->add_statement(if_statement); *pshortcut = Expression::make_temporary_reference(ts, loc); @@ -4817,7 +4823,7 @@ Build_recover_thunks::function(Named_object* orig_no) // Any varargs call has already been lowered. call->set_varargs_are_lowered(); - Statement* s = Statement::make_return_from_call(call, location); + Statement* s = Statement::make_return_from_call(new_no, call, location); s->determine_types(this->gogo_); gogo->add_statement(s); @@ -5894,6 +5900,7 @@ Function::traverse(Traverse* traverse) void Function::determine_types(Gogo* gogo) { + this->set_closure_type(); if (this->block_ != NULL) this->block_->determine_types(gogo); } @@ -7465,8 +7472,8 @@ Function_declaration::import_function_body(Gogo* gogo, Named_object* no) if (!Block::import_block(outer, &ifb, start_loc)) return; - gogo->lower_block(no, outer); outer->determine_types(gogo); + gogo->lower_block(no, outer); gogo->add_imported_inline_function(no); } @@ -7670,9 +7677,13 @@ Variable::has_type() const Type* Variable::type_from_tuple(Expression* expr, bool report_error) const { - if (expr->map_index_expression() != NULL) + if (Index_expression::is_map_index(expr)) { - Map_type* mt = expr->map_index_expression()->get_map_type(); + Map_type* mt; + if (expr->map_index_expression() != NULL) + mt = expr->map_index_expression()->get_map_type(); + else + mt = expr->index_expression()->left()->type()->map_type(); if (mt == NULL) return Type::make_error_type(); return mt->val_type(); @@ -7701,7 +7712,9 @@ Variable::type_from_range(Expression* expr, bool get_index_type, bool report_error) const { Type* t = expr->type(); - if (t->array_type() != NULL + if (t->is_error_type()) + return t; + else if (t->array_type() != NULL || (t->points_to() != NULL && t->points_to()->array_type() != NULL && !t->points_to()->is_slice_type())) @@ -8211,14 +8224,50 @@ Named_constant::traverse_expression(Traverse* traverse) return Expression::traverse(&this->expr_, traverse); } +// Set the iota value in a constant expression. + +class Set_iota_value : public Traverse +{ + public: + Set_iota_value(int iota_value) + : Traverse(traverse_expressions), + iota_value_(iota_value) + { } + + int + expression(Expression**); + + private: + int iota_value_; +}; + +int +Set_iota_value::expression(Expression** pexpr) +{ + Expression* expr = *pexpr; + if (expr->const_expression() != NULL) + expr->const_expression()->set_iota_value(this->iota_value_); + else if (expr->unknown_expression() != NULL) + { + // This case can happen for an array length that is not set in + // the determine types pass. + expr->unknown_expression()->set_iota_value(this->iota_value_); + } + return TRAVERSE_CONTINUE; +} + // Determine the type of the constant. void Named_constant::determine_type(Gogo* gogo) { + if (this->type_is_determined_) + return; + this->type_is_determined_ = true; + if (this->type_ != NULL) { - Type_context context(this->type_, false); + Type_context context(this->type_, this->type_->is_abstract()); this->expr_->determine_type(gogo, &context); } else @@ -8229,6 +8278,9 @@ Named_constant::determine_type(Gogo* gogo) this->type_ = this->expr_->type(); go_assert(this->type_ != NULL); } + + Set_iota_value siv(this->iota_value_); + this->traverse_expression(&siv); } // Indicate that we found and reported an error for this constant. @@ -9353,6 +9405,55 @@ Bindings::traverse(Traverse* traverse, bool is_global) return TRAVERSE_CONTINUE; } +// Determine types for the objects. + +void +Bindings::determine_types(Gogo* gogo) +{ + // We don't use an iterator because the traversal can add new + // bindings. + for (size_t i = 0; i < this->named_objects_.size(); ++i) + { + Named_object* no = this->named_objects_[i]; + if (no->is_function()) + no->func_value()->determine_types(gogo); + else if (no->is_variable()) + no->var_value()->determine_type(gogo); + else if (no->is_const()) + no->const_value()->determine_type(gogo); + + // See if a variable requires us to build an initialization + // function. We know that we will see all global variables + // here. + if (!gogo->need_init_fn() && no->is_variable()) + { + Variable* variable = no->var_value(); + + // If this is a global variable which requires runtime + // initialization, we need an initialization function. + + if (!variable->is_global()) + continue; + + if (variable->init() == NULL) + ; + else if (variable->type()->interface_type() != NULL) + gogo->set_need_init_fn(); + else if (variable->init()->is_constant()) + ; + else if (!variable->init()->is_composite_literal()) + gogo->set_need_init_fn(); + else if (variable->init()->is_nonconstant_composite_literal()) + gogo->set_need_init_fn(); + + // If this global variable holds a pointer value, we need an + // initialization function to register it as a GC root. + if (variable->type()->has_pointer()) + gogo->set_need_init_fn(); + } + } +} + void Bindings::debug_dump() { diff --git a/gcc/go/gofrontend/gogo.h b/gcc/go/gofrontend/gogo.h index f254a61..d69f83b 100644 --- a/gcc/go/gofrontend/gogo.h +++ b/gcc/go/gofrontend/gogo.h @@ -703,6 +703,11 @@ class Gogo void record_interface_type(Interface_type*); + // Whether we need an initialization function. + bool + need_init_fn() const + { return this->need_init_fn_; } + // Note that we need an initialization function. void set_need_init_fn() @@ -820,6 +825,10 @@ class Gogo void create_function_descriptors(); + // Lower calls to builtin functions. + void + lower_builtin_calls(); + // Finalize the method lists and build stub methods for named types. void finalize_methods(); @@ -2569,7 +2578,8 @@ class Named_constant Named_constant(Type* type, Expression* expr, int iota_value, Location location) : type_(type), expr_(expr), iota_value_(iota_value), location_(location), - lowering_(false), is_sink_(false), bconst_(NULL) + lowering_(false), is_sink_(false), type_is_determined_(false), + bconst_(NULL) { } Type* @@ -2655,6 +2665,8 @@ class Named_constant bool lowering_; // Whether this constant is blank named and needs only type checking. bool is_sink_; + // Whether we have determined the type of the constants. + bool type_is_determined_; // The backend representation of the constant value. Bexpression* bconst_; }; @@ -3276,6 +3288,10 @@ class Bindings int traverse(Traverse*, bool is_global); + // Determine types for the objects. + void + determine_types(Gogo*); + // Iterate over definitions. This does not include things which // were only declared. diff --git a/gcc/go/gofrontend/parse.cc b/gcc/go/gofrontend/parse.cc index d741058..a4e4ae3 100644 --- a/gcc/go/gofrontend/parse.cc +++ b/gcc/go/gofrontend/parse.cc @@ -2318,6 +2318,7 @@ Parse::simple_var_decl_or_assignment(const std::string& name, go_error_at(id_location, "%qs repeated on left side of %s", Gogo::message_name(id).c_str(), ":="); + id = this->gogo_->pack_hidden_name("_", false); } til.push_back(Typed_identifier(id, NULL, location)); } @@ -2330,10 +2331,12 @@ Parse::simple_var_decl_or_assignment(const std::string& name, id = this->gogo_->pack_hidden_name(id, is_id_exported); ins = uniq_idents.insert(id); + std::string name = id; if (!ins.second && !Gogo::is_sink_name(id)) { dup_name = Gogo::message_name(id); dup_loc = id_location; + id = this->gogo_->pack_hidden_name("_", false); } til.push_back(Typed_identifier(id, NULL, location)); } @@ -3511,9 +3514,9 @@ Parse::id_to_expression(const std::string& name, Location location, if (is_composite_literal_key) { // This is a composite literal key, which means that it - // could just be a struct field name, so avoid confusiong by + // could just be a struct field name, so avoid confusion by // not adding it to the bindings. We'll look up the name - // later during the lowering phase if necessary. + // later during the determine types phase if necessary. return Expression::make_composite_literal_key(name, location); } named_object = this->gogo_->add_unknown_name(name, location); @@ -4496,12 +4499,12 @@ Parse::return_stat() Expression_list* vals = NULL; if (this->expression_may_start_here()) vals = this->expression_list(NULL, false, true); - this->gogo_->add_statement(Statement::make_return_statement(vals, location)); + Named_object* function = this->gogo_->current_function(); + this->gogo_->add_statement(Statement::make_return_statement(function, vals, + location)); - if (vals == NULL - && this->gogo_->current_function()->func_value()->results_are_named()) + if (vals == NULL && function->func_value()->results_are_named()) { - Named_object* function = this->gogo_->current_function(); Function::Results* results = function->func_value()->result_variables(); for (Function::Results::const_iterator p = results->begin(); p != results->end(); diff --git a/gcc/go/gofrontend/runtime.cc b/gcc/go/gofrontend/runtime.cc index 274aa4a..e4dbd26 100644 --- a/gcc/go/gofrontend/runtime.cc +++ b/gcc/go/gofrontend/runtime.cc @@ -256,8 +256,8 @@ runtime_function_type(Runtime_function_type bft) // Convert an expression to the type to pass to a runtime function. static Expression* -convert_to_runtime_function_type(Runtime_function_type bft, Expression* e, - Location loc) +convert_to_runtime_function_type(Gogo* gogo, Runtime_function_type bft, + Expression* e, Location loc) { switch (bft) { @@ -284,6 +284,8 @@ convert_to_runtime_function_type(Runtime_function_type bft, Expression* e, case RFT_POINTER: { Type* t = runtime_function_type(bft); + Type_context context(t, false); + e->determine_type(gogo, &context); if (!Type::are_identical(t, e->type(), true, NULL)) e = Expression::make_cast(t, e, loc); return e; @@ -414,7 +416,7 @@ Runtime::runtime_declaration(Function code) // Make a call to a runtime function. Call_expression* -Runtime::make_call(Gogo*, Runtime::Function code, Location loc, +Runtime::make_call(Gogo* gogo, Runtime::Function code, Location loc, int param_count, ...) { go_assert(code < Runtime::NUMBER_OF_FUNCTIONS); @@ -436,7 +438,7 @@ Runtime::make_call(Gogo*, Runtime::Function code, Location loc, { Expression* e = va_arg(ap, Expression*); Runtime_function_type rft = pb->parameter_types[i]; - args->push_back(convert_to_runtime_function_type(rft, e, loc)); + args->push_back(convert_to_runtime_function_type(gogo, rft, e, loc)); } va_end(ap); diff --git a/gcc/go/gofrontend/statements.cc b/gcc/go/gofrontend/statements.cc index 5d652a1..e9675eb 100644 --- a/gcc/go/gofrontend/statements.cc +++ b/gcc/go/gofrontend/statements.cc @@ -134,7 +134,7 @@ Statement::import_statement(Import_function_body* ifb, Location loc) // After lowering return statements have no expressions. The // return expressions are assigned to result parameters. ifb->advance(6); - return Statement::make_return_statement(NULL, loc); + return Statement::make_return_statement(ifb->function(), NULL, loc); } else if (ifb->match_c_string("var $t")) return Temporary_statement::do_import(ifb, loc); @@ -278,6 +278,12 @@ Variable_declaration_statement::do_traverse(Traverse*) return TRAVERSE_CONTINUE; } +void +Variable_declaration_statement::do_determine_types(Gogo* gogo) +{ + this->var_->var_value()->determine_type(gogo); +} + // Lower the variable's initialization expression. Statement* @@ -327,6 +333,8 @@ Variable_declaration_statement::do_add_conversions() Bstatement* Variable_declaration_statement::do_get_backend(Translate_context* context) { + if (this->var_->is_redefinition()) + return context->backend()->error_statement(); Bfunction* bfunction = context->function()->func_value()->get_decl(); Variable* var = this->var_->var_value(); Bvariable* bvar = this->var_->get_backend_variable(context->gogo(), @@ -969,7 +977,9 @@ Assignment_statement::do_lower(Gogo* gogo, Named_object*, Block* enclosing, Expression::make_dereference(call, Expression::NIL_CHECK_NOT_NEEDED, loc); ref = Expression::make_temporary_reference(val_temp, loc); - b->add_statement(Statement::make_assignment(indir, ref, loc)); + Statement* s = Statement::make_assignment(indir, ref, loc); + s->determine_types(gogo); + b->add_statement(s); return Statement::make_block_statement(b, loc); } @@ -1017,45 +1027,59 @@ Assignment_statement::do_determine_types(Gogo* gogo) this->rhs_->determine_type(gogo, &context); } -// Check types for an assignment. +// Check types for an assignment from RHS to LHS. Returns true if the +// assignment is OK. -void -Assignment_statement::do_check_types(Gogo*) +bool +Assignment_statement::check_assignment_types(Expression* lhs, + Type* rhs_type, + Location loc) { // The left hand side must be either addressable, a map index // expression, or the blank identifier. - if (!this->lhs_->is_addressable() - && this->lhs_->map_index_expression() == NULL - && !this->lhs_->is_sink_expression()) + if (!lhs->is_addressable() + && !Index_expression::is_map_index(lhs) + && !lhs->is_sink_expression()) { - if (!this->lhs_->type()->is_error()) - this->report_error(_("invalid left hand side of assignment")); - return; + if (!lhs->type()->is_error()) + go_error_at(lhs->location(), "invalid left hand side of assignment"); + return false; } - Type* lhs_type = this->lhs_->type(); - Type* rhs_type = this->rhs_->type(); + Type* lhs_type = lhs->type(); - // Invalid assignment of nil to the blank identifier. - if (lhs_type->is_sink_type() - && rhs_type->is_nil_type()) + // Check for invalid assignment of nil to the blank identifier. + if (lhs_type->is_sink_type() && rhs_type->is_nil_type()) { - this->report_error(_("use of untyped nil")); - return; + go_error_at(loc, "use of untyped nil"); + return false; } std::string reason; if (!Type::are_assignable(lhs_type, rhs_type, &reason)) { if (reason.empty()) - go_error_at(this->location(), "incompatible types in assignment"); + go_error_at(loc, "incompatible types in assignment"); else - go_error_at(this->location(), "incompatible types in assignment (%s)", + go_error_at(loc, "incompatible types in assignment (%s)", reason.c_str()); - this->set_is_error(); + return false; } - if (lhs_type->is_error() || rhs_type->is_error()) + if (lhs_type->is_error_type() || rhs_type->is_error_type()) + return false; + + return true; +} + +// Check types for an assignment. + +void +Assignment_statement::do_check_types(Gogo*) +{ + if (!Assignment_statement::check_assignment_types(this->lhs_, + this->rhs_->type(), + this->location())) this->set_is_error(); } @@ -1173,6 +1197,12 @@ class Assignment_operation_statement : public Statement int do_traverse(Traverse*); + void + do_determine_types(Gogo*); + + void + do_check_types(Gogo*); + Statement* do_lower(Gogo*, Named_object*, Block*, Statement_inserter*); @@ -1184,6 +1214,9 @@ class Assignment_operation_statement : public Statement do_dump_statement(Ast_dump_context*) const; private: + Operator + get_binop(); + // The operator (OPERATOR_PLUSEQ, etc.). Operator op_; // Left hand side. @@ -1202,11 +1235,137 @@ Assignment_operation_statement::do_traverse(Traverse* traverse) return this->traverse_expression(traverse, &this->rhs_); } +void +Assignment_operation_statement::do_determine_types(Gogo* gogo) +{ + this->lhs_->determine_type_no_context(gogo); + Type* rhs_context_type = this->lhs_->type(); + if (rhs_context_type->is_sink_type()) + rhs_context_type = NULL; + Type_context context(rhs_context_type, false); + this->rhs_->determine_type(gogo, &context); +} + +// Get the binary operator from the assignment operator. + +Operator +Assignment_operation_statement::get_binop() +{ + switch (this->op_) + { + case OPERATOR_PLUSEQ: + return OPERATOR_PLUS; + case OPERATOR_MINUSEQ: + return OPERATOR_MINUS; + case OPERATOR_OREQ: + return OPERATOR_OR; + case OPERATOR_XOREQ: + return OPERATOR_XOR; + case OPERATOR_MULTEQ: + return OPERATOR_MULT; + case OPERATOR_DIVEQ: + return OPERATOR_DIV; + case OPERATOR_MODEQ: + return OPERATOR_MOD; + case OPERATOR_LSHIFTEQ: + return OPERATOR_LSHIFT; + case OPERATOR_RSHIFTEQ: + return OPERATOR_RSHIFT; + case OPERATOR_ANDEQ: + return OPERATOR_AND; + case OPERATOR_BITCLEAREQ: + return OPERATOR_BITCLEAR; + default: + go_unreachable(); + } +} + +void +Assignment_operation_statement::do_check_types(Gogo*) +{ + if (this->lhs_->is_sink_expression()) + { + this->report_error(_("cannot use %<_%> as value")); + return; + } + + + Type* lhs_type = this->lhs_->type(); + Type* rhs_type = this->rhs_->type(); + + if (!this->lhs_->is_addressable() + && !Index_expression::is_map_index(this->lhs_)) + { + if (!lhs_type->is_error()) + this->report_error(_("invalid left hand side of assignment")); + this->set_is_error(); + return; + } + + if (this->op_ != OPERATOR_LSHIFTEQ && this->op_ != OPERATOR_RSHIFTEQ) + { + if (!Type::are_compatible_for_binop(lhs_type, rhs_type)) + { + this->report_error(_("incompatible type in binary expression")); + return; + } + if (!Binary_expression::check_operator_type(this->get_binop(), lhs_type, + rhs_type, this->location())) + { + this->set_is_error(); + return; + } + if (this->op_ == OPERATOR_DIVEQ || this->op_ == OPERATOR_MODEQ) + { + Numeric_constant rconst; + unsigned long rval; + if (lhs_type->integer_type() != NULL + && this->rhs_->numeric_constant_value(&rconst) + && rconst.to_unsigned_long(&rval) == Numeric_constant::NC_UL_VALID + && rval == 0) + { + this->report_error(_("integer division by zero")); + return; + } + } + } + else + { + if (lhs_type->integer_type() == NULL) + { + this->report_error(_("shift of non-integer operand")); + return; + } + + if (rhs_type->is_string_type() + || (!rhs_type->is_abstract() + && rhs_type->integer_type() == NULL)) + { + this->report_error(_("shift count not integer")); + return; + } + + Numeric_constant nc; + if (this->rhs_->numeric_constant_value(&nc)) + { + mpz_t val; + if (!nc.to_int(&val)) + { + this->report_error(_("shift count not integer")); + return; + } + if (mpz_sgn(val) < 0) + this->report_error(_("negative shift count")); + mpz_clear(val); + } + } +} + // Lower an assignment operation statement to a regular assignment // statement. Statement* -Assignment_operation_statement::do_lower(Gogo*, Named_object*, +Assignment_operation_statement::do_lower(Gogo* gogo, Named_object*, Block* enclosing, Statement_inserter*) { Location loc = this->location(); @@ -1229,48 +1388,10 @@ Assignment_operation_statement::do_lower(Gogo*, Named_object*, Expression* lval = this->lhs_->copy(); - Operator op; - switch (this->op_) - { - case OPERATOR_PLUSEQ: - op = OPERATOR_PLUS; - break; - case OPERATOR_MINUSEQ: - op = OPERATOR_MINUS; - break; - case OPERATOR_OREQ: - op = OPERATOR_OR; - break; - case OPERATOR_XOREQ: - op = OPERATOR_XOR; - break; - case OPERATOR_MULTEQ: - op = OPERATOR_MULT; - break; - case OPERATOR_DIVEQ: - op = OPERATOR_DIV; - break; - case OPERATOR_MODEQ: - op = OPERATOR_MOD; - break; - case OPERATOR_LSHIFTEQ: - op = OPERATOR_LSHIFT; - break; - case OPERATOR_RSHIFTEQ: - op = OPERATOR_RSHIFT; - break; - case OPERATOR_ANDEQ: - op = OPERATOR_AND; - break; - case OPERATOR_BITCLEAREQ: - op = OPERATOR_BITCLEAR; - break; - default: - go_unreachable(); - } - - Expression* binop = Expression::make_binary(op, lval, this->rhs_, loc); + Expression* binop = Expression::make_binary(this->get_binop(), lval, + this->rhs_, loc); Statement* s = Statement::make_assignment(this->lhs_, binop, loc); + s->determine_types(gogo); if (b->statements()->empty()) { delete b; @@ -1322,6 +1443,12 @@ class Tuple_assignment_statement : public Statement int do_traverse(Traverse* traverse); + void + do_determine_types(Gogo*); + + void + do_check_types(Gogo*); + Statement* do_lower(Gogo*, Named_object*, Block*, Statement_inserter*); @@ -1349,15 +1476,53 @@ Tuple_assignment_statement::do_traverse(Traverse* traverse) return this->traverse_expression_list(traverse, this->rhs_); } +void +Tuple_assignment_statement::do_determine_types(Gogo* gogo) +{ + Expression_list::iterator pr = this->rhs_->begin(); + for (Expression_list::iterator pl = this->lhs_->begin(); + pl != this->lhs_->end(); + ++pl, ++pr) + { + go_assert(pr != this->rhs_->end()); + (*pl)->determine_type_no_context(gogo); + Type* rhs_context_type = (*pl)->type(); + if (rhs_context_type->is_sink_type()) + rhs_context_type = NULL; + Type_context context(rhs_context_type, false); + (*pr)->determine_type(gogo, &context); + } + go_assert(pr == this->rhs_->end()); +} + +void +Tuple_assignment_statement::do_check_types(Gogo*) +{ + Expression_list::iterator pr = this->rhs_->begin(); + for (Expression_list::iterator pl = this->lhs_->begin(); + pl != this->lhs_->end(); + ++pl, ++pr) + { + go_assert(pr != this->rhs_->end()); + if (!Assignment_statement::check_assignment_types(*pl, (*pr)->type(), + this->location())) + this->set_is_error(); + } + go_assert(pr == this->rhs_->end()); +} + // Lower a tuple assignment. We use temporary variables to split it // up into a set of single assignments. Statement* -Tuple_assignment_statement::do_lower(Gogo*, Named_object*, Block* enclosing, - Statement_inserter*) +Tuple_assignment_statement::do_lower(Gogo* gogo, Named_object*, + Block* enclosing, Statement_inserter*) { Location loc = this->location(); + if (this->classification() == STATEMENT_ERROR) + return Statement::make_error_statement(loc); + Block* b = new Block(enclosing, loc); // First move out any subexpressions on the left hand side. The @@ -1417,7 +1582,9 @@ Tuple_assignment_statement::do_lower(Gogo*, Named_object*, Block* enclosing, continue; Expression* ref = Expression::make_temporary_reference(*ptemp, loc); - b->add_statement(Statement::make_assignment(*plhs, ref, loc)); + Statement* s = Statement::make_assignment(*plhs, ref, loc); + s->determine_types(gogo); + b->add_statement(s); ++ptemp; } go_assert(ptemp == temps.end() || saw_errors()); @@ -1464,6 +1631,12 @@ public: int do_traverse(Traverse* traverse); + void + do_determine_types(Gogo*); + + void + do_check_types(Gogo*); + Statement* do_lower(Gogo*, Named_object*, Block*, Statement_inserter*); @@ -1494,6 +1667,45 @@ Tuple_map_assignment_statement::do_traverse(Traverse* traverse) return this->traverse_expression(traverse, &this->map_index_); } +void +Tuple_map_assignment_statement::do_determine_types(Gogo* gogo) +{ + this->val_->determine_type_no_context(gogo); + this->present_->determine_type_no_context(gogo); + this->map_index_->determine_type_no_context(gogo); +} + +void +Tuple_map_assignment_statement::do_check_types(Gogo*) +{ + Expression* map_expr = this->map_index_; + Map_type* map_type; + if (map_expr->map_index_expression() != NULL) + map_type = map_expr->map_index_expression()->get_map_type(); + else if (map_expr->index_expression() != NULL) + map_type = map_expr->index_expression()->left()->type()->map_type(); + else + { + this->report_error(_("expected map index on right hand side")); + return; + } + if (map_type == NULL || map_type->is_error()) + { + go_assert(saw_errors()); + this->set_is_error(); + return; + } + + if (!Assignment_statement::check_assignment_types(this->val_, + map_type->val_type(), + this->location())) + this->set_is_error(); + if (!Assignment_statement::check_assignment_types(this->present_, + Type::make_boolean_type(), + this->location())) + this->set_is_error(); +} + // Lower a tuple map assignment. Statement* @@ -1502,15 +1714,13 @@ Tuple_map_assignment_statement::do_lower(Gogo* gogo, Named_object*, { Location loc = this->location(); + if (this->classification() == STATEMENT_ERROR) + return Statement::make_error_statement(loc); + Map_index_expression* map_index = this->map_index_->map_index_expression(); - if (map_index == NULL) - { - this->report_error(_("expected map index on right hand side")); - return Statement::make_error_statement(loc); - } + go_assert(map_index != NULL); Map_type* map_type = map_index->get_map_type(); - if (map_type == NULL) - return Statement::make_error_statement(loc); + go_assert(map_type != NULL); // Avoid copy for string([]byte) conversions used in map keys. // mapaccess doesn't keep the reference, so this is safe. @@ -1607,11 +1817,13 @@ Tuple_map_assignment_statement::do_lower(Gogo* gogo, Named_object*, Expression* res = Expression::make_call_result(call, 0); res = Expression::make_unsafe_cast(val_ptr_type, res, loc); Statement* s = Statement::make_assignment(ref, res, loc); + s->determine_types(gogo); b->add_statement(s); ref = Expression::make_temporary_reference(present_temp, loc); ref->set_is_lvalue(); res = Expression::make_call_result(call, 1); s = Statement::make_assignment(ref, res, loc); + s->determine_types(gogo); b->add_statement(s); // val = *val__ptr_temp @@ -1619,11 +1831,13 @@ Tuple_map_assignment_statement::do_lower(Gogo* gogo, Named_object*, Expression* ind = Expression::make_dereference(ref, Expression::NIL_CHECK_NOT_NEEDED, loc); s = Statement::make_assignment(this->val_, ind, loc); + s->determine_types(gogo); b->add_statement(s); // present = present_temp ref = Expression::make_temporary_reference(present_temp, loc); s = Statement::make_assignment(this->present_, ref, loc); + s->determine_types(gogo); b->add_statement(s); return Statement::make_block_statement(b, loc); @@ -1669,6 +1883,12 @@ class Tuple_receive_assignment_statement : public Statement int do_traverse(Traverse* traverse); + void + do_determine_types(Gogo*); + + void + do_check_types(Gogo*); + Statement* do_lower(Gogo*, Named_object*, Block*, Statement_inserter*); @@ -1699,6 +1919,39 @@ Tuple_receive_assignment_statement::do_traverse(Traverse* traverse) return this->traverse_expression(traverse, &this->channel_); } +void +Tuple_receive_assignment_statement::do_determine_types(Gogo* gogo) +{ + this->val_->determine_type_no_context(gogo); + this->closed_->determine_type_no_context(gogo); + this->channel_->determine_type_no_context(gogo); +} + +void +Tuple_receive_assignment_statement::do_check_types(Gogo*) +{ + Channel_type* ct = this->channel_->type()->channel_type(); + if (ct == NULL) + { + this->report_error(_("expected channel")); + return; + } + if (!ct->may_receive()) + { + this->report_error(_("invalid receive on send-only channel")); + return; + } + + if (!Assignment_statement::check_assignment_types(this->val_, + ct->element_type(), + this->location())) + this->set_is_error(); + if (!Assignment_statement::check_assignment_types(this->closed_, + Type::make_boolean_type(), + this->location())) + this->set_is_error(); +} + // Lower to a function call. Statement* @@ -1708,17 +1961,11 @@ Tuple_receive_assignment_statement::do_lower(Gogo* gogo, Named_object*, { Location loc = this->location(); + if (this->classification() == STATEMENT_ERROR) + return Statement::make_error_statement(loc); + Channel_type* channel_type = this->channel_->type()->channel_type(); - if (channel_type == NULL) - { - this->report_error(_("expected channel")); - return Statement::make_error_statement(loc); - } - if (!channel_type->may_receive()) - { - this->report_error(_("invalid receive on send-only channel")); - return Statement::make_error_statement(loc); - } + go_assert(channel_type != NULL && channel_type->may_receive()); Block* b = new Block(enclosing, loc); @@ -1750,16 +1997,19 @@ Tuple_receive_assignment_statement::do_lower(Gogo* gogo, Named_object*, ref = Expression::make_temporary_reference(closed_temp, loc); ref->set_is_lvalue(); Statement* s = Statement::make_assignment(ref, call, loc); + s->determine_types(gogo); b->add_statement(s); // val = val_temp ref = Expression::make_temporary_reference(val_temp, loc); s = Statement::make_assignment(this->val_, ref, loc); + s->determine_types(gogo); b->add_statement(s); // closed = closed_temp ref = Expression::make_temporary_reference(closed_temp, loc); s = Statement::make_assignment(this->closed_, ref, loc); + s->determine_types(gogo); b->add_statement(s); return Statement::make_block_statement(b, loc); @@ -1808,6 +2058,12 @@ class Tuple_type_guard_assignment_statement : public Statement int do_traverse(Traverse*); + void + do_determine_types(Gogo*); + + void + do_check_types(Gogo*); + Statement* do_lower(Gogo*, Named_object*, Block*, Statement_inserter*); @@ -1847,6 +2103,34 @@ Tuple_type_guard_assignment_statement::do_traverse(Traverse* traverse) return this->traverse_expression(traverse, &this->expr_); } +void +Tuple_type_guard_assignment_statement::do_determine_types(Gogo* gogo) +{ + this->val_->determine_type_no_context(gogo); + this->ok_->determine_type_no_context(gogo); + this->expr_->determine_type_no_context(gogo); +} + +void +Tuple_type_guard_assignment_statement::do_check_types(Gogo*) +{ + Type* expr_type = this->expr_->type(); + if (expr_type->interface_type() == NULL) + { + if (!expr_type->is_error() && !this->type_->is_error()) + this->report_error(_("type assertion only valid for interface types")); + return; + } + + if (!Assignment_statement::check_assignment_types(this->val_, this->type_, + this->location())) + this->set_is_error(); + if (!Assignment_statement::check_assignment_types(this->ok_, + Type::make_boolean_type(), + this->location())) + this->set_is_error(); +} + // Lower to a function call. Statement* @@ -1856,13 +2140,11 @@ Tuple_type_guard_assignment_statement::do_lower(Gogo* gogo, Named_object*, { Location loc = this->location(); + if (this->classification() == STATEMENT_ERROR) + return Statement::make_error_statement(loc); + Type* expr_type = this->expr_->type(); - if (expr_type->interface_type() == NULL) - { - if (!expr_type->is_error() && !this->type_->is_error()) - this->report_error(_("type assertion only valid for interface types")); - return Statement::make_error_statement(loc); - } + go_assert(expr_type->interface_type() != NULL); Block* b = new Block(enclosing, loc); @@ -1907,12 +2189,14 @@ Tuple_type_guard_assignment_statement::do_lower(Gogo* gogo, Named_object*, Expression* res = Expression::make_call_result(call, 0); res = Expression::make_unsafe_cast(this->type_, res, loc); Statement* s = Statement::make_assignment(this->val_, res, loc); + s->determine_types(gogo); b->add_statement(s); res = Expression::make_call_result(call, 1); if (!this->ok_->type()->is_boolean_type()) res = Expression::make_cast(Type::lookup_bool_type(), res, loc); s = Statement::make_assignment(this->ok_, res, loc); + s->determine_types(gogo); b->add_statement(s); } @@ -1971,11 +2255,13 @@ Tuple_type_guard_assignment_statement::lower_to_object_type( Expression* ok_ref = Expression::make_temporary_reference(ok_temp, loc); s = Statement::make_assignment(ok_ref, call, loc); } + s->determine_types(gogo); b->add_statement(s); // val = val_temp ref = Expression::make_temporary_reference(val_temp, loc); s = Statement::make_assignment(this->val_, ref, loc); + s->determine_types(gogo); b->add_statement(s); // ok = ok_temp @@ -1983,6 +2269,7 @@ Tuple_type_guard_assignment_statement::lower_to_object_type( { ref = Expression::make_temporary_reference(ok_temp, loc); s = Statement::make_assignment(this->ok_, ref, loc); + s->determine_types(gogo); b->add_statement(s); } } @@ -2050,35 +2337,12 @@ Expression_statement::do_check_types(Gogo*) bool Expression_statement::do_may_fall_through() const { + // The builtin function panic does not return. const Call_expression* call = this->expr_->call_expression(); - if (call != NULL) - { - const Expression* fn = call->fn(); - // panic is still an unknown named object. - const Unknown_expression* ue = fn->unknown_expression(); - if (ue != NULL) - { - Named_object* no = ue->named_object(); - - if (no->is_unknown()) - no = no->unknown_value()->real_named_object(); - if (no != NULL) - { - Function_type* fntype; - if (no->is_function()) - fntype = no->func_value()->type(); - else if (no->is_function_declaration()) - fntype = no->func_declaration_value()->type(); - else - fntype = NULL; - - // The builtin function panic does not return. - if (fntype != NULL && fntype->is_builtin() && no->name() == "panic") - return false; - } - } - } - return true; + if (call == NULL) + return true; + const Builtin_call_expression* bce = call->builtin_call_expression(); + return bce == NULL || bce->code() != Builtin_call_expression::BUILTIN_PANIC; } // Export an expression statement. @@ -2225,6 +2489,12 @@ class Inc_dec_statement : public Statement do_traverse(Traverse* traverse) { return this->traverse_expression(traverse, &this->expr_); } + void + do_determine_types(Gogo*); + + void + do_check_types(Gogo*); + Statement* do_lower(Gogo*, Named_object*, Block*, Statement_inserter*); @@ -2242,17 +2512,36 @@ class Inc_dec_statement : public Statement bool is_inc_; }; +void +Inc_dec_statement::do_determine_types(Gogo* gogo) +{ + this->expr_->determine_type_no_context(gogo); +} + +void +Inc_dec_statement::do_check_types(Gogo*) +{ + if (!this->expr_->is_addressable() + && !Index_expression::is_map_index(this->expr_)) + { + if (!this->expr_->type()->is_error()) + this->report_error(_("invalid left hand side of assignment")); + this->set_is_error(); + return; + } + if (!this->expr_->type()->is_numeric_type()) + { + this->report_error(_("increment or decrement of non-numeric type")); + return; + } +} + // Lower to += or -=. Statement* Inc_dec_statement::do_lower(Gogo*, Named_object*, Block*, Statement_inserter*) { Location loc = this->location(); - if (!this->expr_->type()->is_numeric_type()) - { - this->report_error("increment or decrement of non-numeric type"); - return Statement::make_error_statement(loc); - } Expression* oexpr = Expression::make_integer_ul(1, this->expr_->type(), loc); Operator op = this->is_inc_ ? OPERATOR_PLUSEQ : OPERATOR_MINUSEQ; return Statement::make_assignment_operation(op, this->expr_, oexpr, loc); @@ -2370,12 +2659,16 @@ void Thunk_statement::do_check_types(Gogo*) { if (!this->call_->discarding_value()) - return; + { + this->set_is_error(); + return; + } Call_expression* ce = this->call_->call_expression(); if (ce == NULL) { if (!this->call_->is_error_expression()) this->report_error("expected call expression"); + this->set_is_error(); return; } } @@ -2888,6 +3181,7 @@ Thunk_statement::build_thunk(Gogo* gogo, const std::string& thunk_name, Statement* call_statement = Statement::make_statement(call, true); + call_statement->determine_types(gogo); gogo->add_statement(call_statement); // If this is a defer statement, the label comes immediately after @@ -2898,7 +3192,10 @@ Thunk_statement::build_thunk(Gogo* gogo, const std::string& thunk_name, Expression_list* vals = new Expression_list(); vals->push_back(Expression::make_boolean(false, location)); - gogo->add_statement(Statement::make_return_statement(vals, location)); + Statement* s = Statement::make_return_statement(function, vals, + location); + s->determine_types(gogo); + gogo->add_statement(s); } Block* b = gogo->finish_block(location); @@ -2983,6 +3280,7 @@ Go_statement::do_get_backend(Translate_context* context) Gogo* gogo = context->gogo(); Expression* call = Runtime::make_call(gogo, Runtime::GO, this->location(), 2, fn, arg); + call->determine_type_no_context(gogo); Bexpression* bcall = call->get_backend(context); Bfunction* bfunction = context->function()->func_value()->get_decl(); return context->backend()->expression_statement(bfunction, bcall); @@ -3024,7 +3322,7 @@ Defer_statement::do_get_backend(Translate_context* context) Expression* call; if (this->on_stack_) { - if (context->gogo()->debug_optimization()) + if (gogo->debug_optimization()) go_debug(loc, "stack allocated defer"); Type* defer_type = Defer_statement::defer_struct_type(); @@ -3037,6 +3335,7 @@ Defer_statement::do_get_backend(Translate_context* context) else call = Runtime::make_call(gogo, Runtime::DEFERPROC, loc, 3, ds, fn, arg); + call->determine_type_no_context(gogo); Bexpression* bcall = call->get_backend(context); Bfunction* bfunction = context->function()->func_value()->get_decl(); return context->backend()->expression_statement(bfunction, bcall); @@ -3082,80 +3381,97 @@ Statement::make_defer_statement(Call_expression* call, // Class Return_statement. -// Lower a return statement. If we are returning a function call -// which returns multiple values which match the current function, -// split up the call's results. If the return statement lists -// explicit values, implement this statement by assigning the values -// to the result variables and change this statement to a naked -// return. This lets panic/recover work correctly. - -Statement* -Return_statement::do_lower(Gogo* gogo, Named_object* function, - Block* enclosing, Statement_inserter*) +void +Return_statement::do_determine_types(Gogo* gogo) { - if (this->is_lowered_) - return this; + if (this->types_are_determined_) + return; + this->types_are_determined_ = true; - Expression_list* vals = this->vals_; - this->vals_ = NULL; - this->is_lowered_ = true; + size_t vals_count = this->vals_ == NULL ? 0 : this->vals_->size(); + if (vals_count == 0) + return; - Location loc = this->location(); + Function::Results* results = + this->function_->func_value()->result_variables(); + size_t results_count = results == NULL ? 0 : results->size(); - size_t vals_count = vals == NULL ? 0 : vals->size(); - Function::Results* results = function->func_value()->result_variables(); + // If the current function has multiple return values, and we are + // returning a single call expression, split up the call expression. + if (results_count > 1 + && vals_count == 1 + && this->vals_->front()->call_expression() != NULL) + { + Call_expression* call = this->vals_->front()->call_expression(); + call->set_expected_result_count(results_count); + call->determine_type_no_context(gogo); + delete this->vals_; + this->vals_ = new Expression_list(); + for (size_t i = 0; i < results_count; ++i) + this->vals_->push_back(Expression::make_call_result(call, i)); + vals_count = results_count; + } + + if (vals_count != results_count) + { + // This is an error which we will report later. Determine all + // types to avoid knockon errors. + for (Expression_list::const_iterator pe = this->vals_->begin(); + pe != this->vals_->end(); + ++pe) + (*pe)->determine_type_no_context(gogo); + return; + } + + Expression_list::const_iterator pe = this->vals_->begin(); + for (Function::Results::const_iterator pr = results->begin(); + pr != results->end(); + ++pr, ++pe) + { + Type* rvtype = (*pr)->result_var_value()->type(); + Type_context context(rvtype, false); + (*pe)->determine_type(gogo, &context); + } +} + +void +Return_statement::do_check_types(Gogo*) +{ + size_t vals_count = this->vals_ == NULL ? 0 : this->vals_->size(); + Function::Results* results = + this->function_->func_value()->result_variables(); size_t results_count = results == NULL ? 0 : results->size(); if (vals_count == 0) { - if (results_count > 0 && !function->func_value()->results_are_named()) - { - this->report_error(_("not enough arguments to return")); - return this; - } - return this; + if (results_count > 0 + && !this->function_->func_value()->results_are_named()) + this->report_error(_("not enough arguments to return")); + return; } if (results_count == 0) { this->report_error(_("return with value in function " "with no return type")); - return this; - } - - // If the current function has multiple return values, and we are - // returning a single call expression, split up the call expression. - if (results_count > 1 - && vals->size() == 1 - && vals->front()->call_expression() != NULL) - { - Call_expression* call = vals->front()->call_expression(); - call->set_expected_result_count(results_count); - delete vals; - vals = new Expression_list; - for (size_t i = 0; i < results_count; ++i) - vals->push_back(Expression::make_call_result(call, i)); - vals_count = results_count; + delete this->vals_; + this->vals_ = NULL; + return; } if (vals_count < results_count) { this->report_error(_("not enough arguments to return")); - return this; + return; } if (vals_count > results_count) { this->report_error(_("too many values in return statement")); - return this; + return; } - Block* b = new Block(enclosing, loc); - - Expression_list* lhs = new Expression_list(); - Expression_list* rhs = new Expression_list(); - - Expression_list::const_iterator pe = vals->begin(); + Expression_list::const_iterator pe = this->vals_->begin(); int i = 1; for (Function::Results::const_iterator pr = results->begin(); pr != results->end(); @@ -3164,22 +3480,9 @@ Return_statement::do_lower(Gogo* gogo, Named_object* function, Named_object* rv = *pr; Expression* e = *pe; - // Check types now so that we give a good error message. The - // result type is known. We determine the expression type - // early. - - Type *rvtype = rv->result_var_value()->type(); - Type_context type_context(rvtype, false); - e->determine_type(gogo, &type_context); - std::string reason; - if (Type::are_assignable(rvtype, e->type(), &reason)) - { - Expression* ve = Expression::make_var_reference(rv, e->location()); - lhs->push_back(ve); - rhs->push_back(e); - } - else + if (!Type::are_assignable(rv->result_var_value()->type(), e->type(), + &reason)) { if (reason.empty()) go_error_at(e->location(), @@ -3188,21 +3491,77 @@ Return_statement::do_lower(Gogo* gogo, Named_object* function, go_error_at(e->location(), "incompatible type for return value %d (%s)", i, reason.c_str()); + this->set_is_error(); } } - go_assert(lhs->size() == rhs->size()); +} + +// Lower a return statement. If we are returning a function call +// which returns multiple values which match the current function, +// split up the call's results. If the return statement lists +// explicit values, implement this statement by assigning the values +// to the result variables and change this statement to a naked +// return. This lets panic/recover work correctly. + +Statement* +Return_statement::do_lower(Gogo* gogo, Named_object*, + Block* enclosing, Statement_inserter*) +{ + Location loc = this->location(); + + if (this->classification() == STATEMENT_ERROR) + return Statement::make_error_statement(loc); + + if (this->is_lowered_) + return this; + + Expression_list* vals = this->vals_; + this->vals_ = NULL; + this->is_lowered_ = true; + + size_t vals_count = vals == NULL ? 0 : vals->size(); + + if (vals_count == 0) + return this; + + Function::Results* results = + this->function_->func_value()->result_variables(); + size_t results_count = results == NULL ? 0 : results->size(); + + go_assert(vals_count == results_count); + + Block* b = new Block(enclosing, loc); + + Expression_list* lhs = new Expression_list(); + Expression_list* rhs = new Expression_list(); + + Expression_list::const_iterator pe = vals->begin(); + for (Function::Results::const_iterator pr = results->begin(); + pr != results->end(); + ++pr, ++pe) + { + Named_object* rv = *pr; + Expression* e = *pe; + Expression* ve = Expression::make_var_reference(rv, e->location()); + lhs->push_back(ve); + rhs->push_back(e); + } - if (lhs->empty()) - ; - else if (lhs->size() == 1) + if (lhs->size() == 1) { - b->add_statement(Statement::make_assignment(lhs->front(), rhs->front(), - loc)); + Statement* s = Statement::make_assignment(lhs->front(), rhs->front(), + loc); + s->determine_types(gogo); + b->add_statement(s); delete lhs; delete rhs; } else - b->add_statement(Statement::make_tuple_assignment(lhs, rhs, loc)); + { + Statement* s = Statement::make_tuple_assignment(lhs, rhs, loc); + s->determine_types(gogo); + b->add_statement(s); + } b->add_statement(this); @@ -3261,16 +3620,17 @@ Return_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const // Make a return statement. Return_statement* -Statement::make_return_statement(Expression_list* vals, +Statement::make_return_statement(Named_object* function, Expression_list* vals, Location location) { - return new Return_statement(vals, location); + return new Return_statement(function, vals, location); } // Make a statement that returns the result of a call expression. Statement* -Statement::make_return_from_call(Call_expression* call, Location location) +Statement::make_return_from_call(Named_object* function, Call_expression* call, + Location location) { size_t rc = call->result_count(); if (rc == 0) @@ -3285,7 +3645,7 @@ Statement::make_return_from_call(Call_expression* call, Location location) for (size_t i = 0; i < rc; ++i) vals->push_back(Expression::make_call_result(call, i)); } - return Statement::make_return_statement(vals, location); + return Statement::make_return_statement(function, vals, location); } } @@ -3942,7 +4302,8 @@ Case_clauses::Case_clause::is_constant() const // test. We branch to FINISH_LABEL at the end of the statements. void -Case_clauses::Case_clause::lower(Block* b, Temporary_statement* val_temp, +Case_clauses::Case_clause::lower(Gogo* gogo, Block* b, + Temporary_statement* val_temp, Unnamed_label* start_label, Unnamed_label* finish_label) const { @@ -3980,6 +4341,7 @@ Case_clauses::Case_clause::lower(Block* b, Temporary_statement* val_temp, // if !COND { goto NEXT_CASE_LABEL } cond = Expression::make_unary(OPERATOR_NOT, cond, loc); s = Statement::make_if_statement(cond, then_block, NULL, loc); + s->determine_types(gogo); b->add_statement(s); } @@ -4024,11 +4386,11 @@ Case_clauses::Case_clause::check_types(Type* type) p != this->cases_->end(); ++p) { - if (!Type::are_assignable(type, (*p)->type(), NULL) - && !Type::are_assignable((*p)->type(), type, NULL)) + std::string reason; + if (!Type::are_compatible_for_comparison(true, type, (*p)->type(), + &reason)) { - go_error_at((*p)->location(), - "type mismatch between switch value and case clause"); + go_error_at(this->location_, "%s", reason.c_str()); return false; } } @@ -4179,7 +4541,7 @@ Case_clauses::is_constant() const // Lower case clauses for a nonconstant switch. void -Case_clauses::lower(Block* b, Temporary_statement* val_temp, +Case_clauses::lower(Gogo* gogo, Block* b, Temporary_statement* val_temp, Unnamed_label* break_label) const { // The default case. @@ -4217,7 +4579,7 @@ Case_clauses::lower(Block* b, Temporary_statement* val_temp, } if (!p->is_default()) - p->lower(b, val_temp, start_label, finish_label); + p->lower(gogo, b, val_temp, start_label, finish_label); else { // We have to move the default case to the end, so that we @@ -4229,7 +4591,7 @@ Case_clauses::lower(Block* b, Temporary_statement* val_temp, } if (default_case != NULL) - default_case->lower(b, val_temp, default_start_label, + default_case->lower(gogo, b, val_temp, default_start_label, default_finish_label); } @@ -4341,12 +4703,6 @@ class Constant_switch_statement : public Statement int do_traverse(Traverse*); - void - do_determine_types(Gogo*); - - void - do_check_types(Gogo*); - Bstatement* do_get_backend(Translate_context*); @@ -4372,24 +4728,6 @@ Constant_switch_statement::do_traverse(Traverse* traverse) return this->clauses_->traverse(traverse); } -// Determine types. - -void -Constant_switch_statement::do_determine_types(Gogo* gogo) -{ - this->val_->determine_type_no_context(gogo); - this->clauses_->determine_types(gogo, this->val_->type()); -} - -// Check types. - -void -Constant_switch_statement::do_check_types(Gogo*) -{ - if (!this->clauses_->check_types(this->val_->type())) - this->set_is_error(); -} - // Convert to GENERIC. Bstatement* @@ -4452,11 +4790,50 @@ Switch_statement::do_traverse(Traverse* traverse) return this->clauses_->traverse(traverse); } +void +Switch_statement::do_determine_types(Gogo* gogo) +{ + if (this->val_ != NULL) + this->val_->determine_type_no_context(gogo); + this->clauses_->determine_types(gogo, + (this->val_ == NULL + ? NULL + : this->val_->type())); +} + +void +Switch_statement::do_check_types(Gogo*) +{ + if (this->val_ != NULL + && (this->val_->is_error_expression() + || this->val_->type()->is_error())) + return; + + if (this->val_ != NULL + && !this->val_->type()->is_comparable() + && !Type::are_compatible_for_comparison(true, this->val_->type(), + Type::make_nil_type(), NULL)) + { + go_error_at(this->val_->location(), + "cannot switch on value whose type may not be compared"); + this->set_is_error(); + return; + } + + Type* type; + if (this->val_ != NULL) + type = this->val_->type(); + else + type = Type::make_boolean_type(); + if (!this->clauses_->check_types(type)) + this->set_is_error(); +} + // Lower a Switch_statement to a Constant_switch_statement or a series // of if statements. Statement* -Switch_statement::do_lower(Gogo*, Named_object*, Block* enclosing, +Switch_statement::do_lower(Gogo* gogo, Named_object*, Block* enclosing, Statement_inserter*) { Location loc = this->location(); @@ -4476,16 +4853,6 @@ Switch_statement::do_lower(Gogo*, Named_object*, Block* enclosing, return new Constant_switch_statement(this->val_, this->clauses_, this->break_label_, loc); - if (this->val_ != NULL - && !this->val_->type()->is_comparable() - && !Type::are_compatible_for_comparison(true, this->val_->type(), - Type::make_nil_type(), NULL)) - { - go_error_at(this->val_->location(), - "cannot switch on value whose type may not be compared"); - return Statement::make_error_statement(loc); - } - Block* b = new Block(enclosing, loc); if (this->clauses_->empty()) @@ -4507,7 +4874,7 @@ Switch_statement::do_lower(Gogo*, Named_object*, Block* enclosing, Temporary_statement* val_temp = Statement::make_temporary(type, val, loc); b->add_statement(val_temp); - this->clauses_->lower(b, val_temp, this->break_label()); + this->clauses_->lower(gogo, b, val_temp, this->break_label()); Statement* s = Statement::make_unnamed_label_statement(this->break_label_); b->add_statement(s); @@ -4588,27 +4955,19 @@ Type_case_clauses::Type_case_clause::traverse(Traverse* traverse) return TRAVERSE_CONTINUE; } -// Lower one clause in a type switch. Add statements to the block B. -// The type descriptor we are switching on is in DESCRIPTOR_TEMP. -// BREAK_LABEL is the label at the end of the type switch. -// *STMTS_LABEL, if not NULL, is a label to put at the start of the -// statements. - void -Type_case_clauses::Type_case_clause::lower(Gogo* gogo, - Type* switch_val_type, - Block* b, - Temporary_statement* descriptor_temp, - Unnamed_label* break_label, - Unnamed_label** stmts_label) const +Type_case_clauses::Type_case_clause::determine_types(Gogo* gogo) { - Location loc = this->location_; + if (this->statements_ != NULL) + this->statements_->determine_types(gogo); +} - Unnamed_label* next_case_label = NULL; +bool +Type_case_clauses::Type_case_clause::check_types(Type* switch_val_type) +{ if (!this->is_default_) { Type* type = this->type_; - std::string reason; if (switch_val_type->interface_type() != NULL && !type->is_nil_constant_as_type() @@ -4621,7 +4980,31 @@ Type_case_clauses::Type_case_clause::lower(Gogo* gogo, else go_error_at(this->location_, "impossible type switch case (%s)", reason.c_str()); + return false; } + } + return true; +} + +// Lower one clause in a type switch. Add statements to the block B. +// The type descriptor we are switching on is in DESCRIPTOR_TEMP. +// BREAK_LABEL is the label at the end of the type switch. +// *STMTS_LABEL, if not NULL, is a label to put at the start of the +// statements. + +void +Type_case_clauses::Type_case_clause::lower(Gogo* gogo, + Block* b, + Temporary_statement* descriptor_temp, + Unnamed_label* break_label, + Unnamed_label** stmts_label) const +{ + Location loc = this->location_; + + Unnamed_label* next_case_label = NULL; + if (!this->is_default_) + { + Type* type = this->type_; Expression* ref = Expression::make_temporary_reference(descriptor_temp, loc); @@ -4670,6 +5053,7 @@ Type_case_clauses::Type_case_clause::lower(Gogo* gogo, Statement* s = Statement::make_goto_unnamed_statement(dest, loc); then_block->add_statement(s); s = Statement::make_if_statement(cond, then_block, NULL, loc); + s->determine_types(gogo); b->add_statement(s); } @@ -4774,6 +5158,29 @@ Type_case_clauses::traverse(Traverse* traverse) return TRAVERSE_CONTINUE; } +void +Type_case_clauses::determine_types(Gogo* gogo) +{ + for (Type_clauses::iterator p = this->clauses_.begin(); + p != this->clauses_.end(); + ++p) + p->determine_types(gogo); +} + +bool +Type_case_clauses::check_types(Type* switch_val_type) +{ + bool ret = true; + for (Type_clauses::iterator p = this->clauses_.begin(); + p != this->clauses_.end(); + ++p) + { + if (!p->check_types(switch_val_type)) + ret = false; + } + return ret; +} + // Check for duplicate types. void @@ -4802,8 +5209,7 @@ Type_case_clauses::check_duplicates() const // BREAK_LABEL is the label at the end of the type switch. void -Type_case_clauses::lower(Gogo* gogo, Type* switch_val_type, - Block* b, +Type_case_clauses::lower(Gogo* gogo, Block* b, Temporary_statement* descriptor_temp, Unnamed_label* break_label) const { @@ -4815,8 +5221,7 @@ Type_case_clauses::lower(Gogo* gogo, Type* switch_val_type, ++p) { if (!p->is_default()) - p->lower(gogo, switch_val_type, b, descriptor_temp, break_label, - &stmts_label); + p->lower(gogo, b, descriptor_temp, break_label, &stmts_label); else { // We are generating a series of tests, which means that we @@ -4827,8 +5232,7 @@ Type_case_clauses::lower(Gogo* gogo, Type* switch_val_type, go_assert(stmts_label == NULL); if (default_case != NULL) - default_case->lower(gogo, switch_val_type, b, descriptor_temp, break_label, - NULL); + default_case->lower(gogo, b, descriptor_temp, break_label, NULL); } // Return true if these clauses may fall through to the statements @@ -4875,6 +5279,31 @@ Type_switch_statement::do_traverse(Traverse* traverse) return TRAVERSE_CONTINUE; } +void +Type_switch_statement::do_determine_types(Gogo* gogo) +{ + this->expr_->determine_type_no_context(gogo); + this->clauses_->determine_types(gogo); +} + +void +Type_switch_statement::do_check_types(Gogo*) +{ + if (this->clauses_ != NULL) + this->clauses_->check_duplicates(); + + Type* expr_type = this->expr_->type(); + if (expr_type->interface_type() == NULL) + { + if (!expr_type->is_error()) + this->report_error(_("cannot type switch on non-interface value")); + this->set_is_error(); + } + + if (!this->clauses_->check_types(expr_type)) + this->set_is_error(); +} + // Lower a type switch statement to a series of if statements. The gc // compiler is able to generate a table in some cases. However, that // does not work for us because we may have type descriptors in @@ -4887,19 +5316,11 @@ Type_switch_statement::do_lower(Gogo* gogo, Named_object*, Block* enclosing, { const Location loc = this->location(); - if (this->clauses_ != NULL) - this->clauses_->check_duplicates(); + if (this->classification() == STATEMENT_ERROR) + return Statement::make_error_statement(loc); Block* b = new Block(enclosing, loc); - Type* val_type = this->expr_->type(); - if (val_type->interface_type() == NULL) - { - if (!val_type->is_error()) - this->report_error(_("cannot type switch on non-interface value")); - return Statement::make_error_statement(loc); - } - Temporary_statement* val_temp = Statement::make_temporary(NULL, this->expr_, loc); b->add_statement(val_temp); @@ -4917,10 +5338,11 @@ Type_switch_statement::do_lower(Gogo* gogo, Named_object*, Block* enclosing, Expression::make_temporary_reference(descriptor_temp, loc); lhs->set_is_lvalue(); Statement* s = Statement::make_assignment(lhs, td, loc); + s->determine_types(gogo); b->add_statement(s); if (this->clauses_ != NULL) - this->clauses_->lower(gogo, val_type, b, descriptor_temp, this->break_label()); + this->clauses_->lower(gogo, b, descriptor_temp, this->break_label()); s = Statement::make_unnamed_label_statement(this->break_label_); b->add_statement(s); @@ -5090,7 +5512,7 @@ Send_statement::do_get_backend(Translate_context* context) Channel_type* channel_type = this->channel_->type()->channel_type(); Type* element_type = channel_type->element_type(); - Expression* val = Expression::convert_for_assignment(context->gogo(), + Expression* val = Expression::convert_for_assignment(gogo, element_type, this->val_, loc); @@ -5159,8 +5581,8 @@ Send_statement::do_get_backend(Translate_context* context) Expression* call = Runtime::make_call(gogo, Runtime::CHANSEND, loc, 2, this->channel_, val); - - context->gogo()->lower_expression(context->function(), NULL, &call); + call->determine_type_no_context(gogo); + gogo->lower_expression(context->function(), NULL, &call); Bexpression* bcall = call->get_backend(context); Bfunction* bfunction = context->function()->func_value()->get_decl(); Bstatement* s = context->backend()->expression_statement(bfunction, bcall); @@ -5259,7 +5681,7 @@ Select_clauses::Select_clause::lower(Gogo* gogo, Named_object* function, loc); if (this->is_send_) - this->lower_send(b, scase, chanref); + this->lower_send(gogo, b, scase, chanref); else this->lower_recv(gogo, function, b, scase, chanref, recvok); @@ -5272,7 +5694,8 @@ Select_clauses::Select_clause::lower(Gogo* gogo, Named_object* function, // Lower a send clause in a select statement. void -Select_clauses::Select_clause::lower_send(Block* b, Expression* scase, +Select_clauses::Select_clause::lower_send(Gogo* gogo, Block* b, + Expression* scase, Expression* chanref) { Location loc = this->location_; @@ -5300,7 +5723,7 @@ Select_clauses::Select_clause::lower_send(Block* b, Expression* scase, Type* unsafe_pointer_type = Type::make_pointer_type(Type::make_void_type()); valaddr = Expression::make_cast(unsafe_pointer_type, valaddr, loc); - this->set_case(b, scase, chanref, valaddr); + this->set_case(gogo, b, scase, chanref, valaddr); } // Lower a receive clause in a select statement. @@ -5326,7 +5749,7 @@ Select_clauses::Select_clause::lower_recv(Gogo* gogo, Named_object* function, Type* unsafe_pointer_type = Type::make_pointer_type(Type::make_void_type()); valaddr = Expression::make_cast(unsafe_pointer_type, valaddr, loc); - this->set_case(b, scase, chanref, valaddr); + this->set_case(gogo, b, scase, chanref, valaddr); // If the block of statements is executed, arrange for the received // value to move from VAL to the place where the statements expect @@ -5345,7 +5768,9 @@ Select_clauses::Select_clause::lower_recv(Gogo* gogo, Named_object* function, { init = new Block(b, loc); valref = Expression::make_temporary_reference(val, loc); - init->add_statement(Statement::make_assignment(this->val_, valref, loc)); + Statement* s = Statement::make_assignment(this->val_, valref, loc); + s->determine_types(gogo); + init->add_statement(s); } if (this->closedvar_ != NULL) @@ -5359,8 +5784,9 @@ Select_clauses::Select_clause::lower_recv(Gogo* gogo, Named_object* function, if (init == NULL) init = new Block(b, loc); Expression* cref = Expression::make_temporary_reference(recvok, loc); - init->add_statement(Statement::make_assignment(this->closed_, cref, - loc)); + Statement* s = Statement::make_assignment(this->closed_, cref, loc); + s->determine_types(gogo); + init->add_statement(s); } if (init != NULL) @@ -5378,7 +5804,8 @@ Select_clauses::Select_clause::lower_recv(Gogo* gogo, Named_object* function, // pass to the runtime function selectgo. void -Select_clauses::Select_clause::set_case(Block* b, +Select_clauses::Select_clause::set_case(Gogo* gogo, + Block* b, Expression* scase, Expression* chanref, Expression* elem) @@ -5392,6 +5819,7 @@ Select_clauses::Select_clause::set_case(Block* b, Type* unsafe_pointer_type = Type::make_pointer_type(Type::make_void_type()); chanref = Expression::make_unsafe_cast(unsafe_pointer_type, chanref, loc); Statement* s = Statement::make_assignment(ref, chanref, loc); + s->determine_types(gogo); b->add_statement(s); if (elem != NULL) @@ -5400,6 +5828,7 @@ Select_clauses::Select_clause::set_case(Block* b, go_assert(scase_type->field(field_index)->is_field_name("elem")); ref = Expression::make_field_reference(scase->copy(), field_index, loc); s = Statement::make_assignment(ref, elem, loc); + s->determine_types(gogo); b->add_statement(s); } } @@ -5409,7 +5838,16 @@ Select_clauses::Select_clause::set_case(Block* b, void Select_clauses::Select_clause::determine_types(Gogo* gogo) { - go_assert(this->is_lowered_); + if (this->channel_ != NULL) + this->channel_->determine_type_no_context(gogo); + if (this->val_ != NULL) + this->val_->determine_type_no_context(gogo); + if (this->closed_ != NULL) + this->closed_->determine_type_no_context(gogo); + if (this->var_ != NULL && this->var_->is_variable()) + this->var_->var_value()->determine_type(gogo); + if (this->closedvar_ != NULL && this->closedvar_->is_variable()) + this->closedvar_->var_value()->determine_type(gogo); if (this->statements_ != NULL) this->statements_->determine_types(gogo); } @@ -5673,6 +6111,7 @@ Select_clauses::get_backend(Translate_context* context, Gogo* gogo = context->gogo(); Expression* crash = Runtime::make_call(gogo, Runtime::UNREACHABLE, location, 0); + crash->determine_type_no_context(gogo); Bexpression* bcrash = crash->get_backend(context); clauses[count] = context->backend()->expression_statement(bfunction, bcrash); @@ -5740,6 +6179,7 @@ Select_statement::do_lower(Gogo* gogo, Named_object* function, { Expression* call = Runtime::make_call(gogo, Runtime::BLOCK, loc, 0); Statement *s = Statement::make_statement(call, false); + s->determine_types(gogo); b->add_statement(s); this->is_lowered_ = true; return Statement::make_block_statement(b, loc); @@ -5823,11 +6263,13 @@ Select_statement::do_lower(Gogo* gogo, Named_object* function, Expression* result = Expression::make_call_result(call, 0); Expression* ref = Expression::make_temporary_reference(this->index_, loc); Statement* s = Statement::make_assignment(ref, result, loc); + s->determine_types(gogo); b->add_statement(s); result = Expression::make_call_result(call, 1); ref = Expression::make_temporary_reference(recvok, loc); s = Statement::make_assignment(ref, result, loc); + s->determine_types(gogo); b->add_statement(s); this->is_lowered_ = true; @@ -5857,8 +6299,10 @@ Select_statement::lower_one_case(Gogo* gogo, Block* b) Block* bnil = new Block(b, loc); Expression* call = Runtime::make_call(gogo, Runtime::BLOCK, loc, 0); Statement* s = Statement::make_statement(call, false); + s->determine_types(gogo); bnil->add_statement(s); Statement* ifs = Statement::make_if_statement(cond, bnil, NULL, loc); + ifs->determine_types(gogo); b->add_statement(ifs); chanref = chanref->copy(); @@ -5866,6 +6310,7 @@ Select_statement::lower_one_case(Gogo* gogo, Block* b) if (scase.is_send()) { s = Statement::make_send_statement(chanref, scase.val(), cloc); + s->determine_types(gogo); b->add_statement(s); } else @@ -5888,6 +6333,7 @@ Select_statement::lower_one_case(Gogo* gogo, Block* b) } else s = Statement::make_statement(recv, false); + s->determine_types(gogo); b->add_statement(s); } else @@ -5918,6 +6364,7 @@ Select_statement::lower_one_case(Gogo* gogo, Block* b) } s = Statement::make_tuple_receive_assignment(lhs, lhs2, chanref, cloc); + s->determine_types(gogo); b->add_statement(s); if (scase.var() != NULL) @@ -6000,12 +6447,14 @@ Select_statement::lower_two_case(Gogo* gogo, Block* b) Statement::make_temporary(Type::make_boolean_type(), Expression::make_call_result(call, 0), loc); + selected_temp->determine_types(gogo); b->add_statement(selected_temp); Temporary_statement* ok_temp = Statement::make_temporary(Type::make_boolean_type(), Expression::make_call_result(call, 1), loc); + ok_temp->determine_types(gogo); b->add_statement(ok_temp); cond = Expression::make_temporary_reference(selected_temp, loc); @@ -6017,6 +6466,7 @@ Select_statement::lower_two_case(Gogo* gogo, Block* b) Statement* as = Statement::make_assignment(chancase.val(), ref->copy(), cloc); + as->determine_types(gogo); bchan->add_statement(as); } else if (chancase.var() != NULL) @@ -6031,6 +6481,7 @@ Select_statement::lower_two_case(Gogo* gogo, Block* b) cloc); Statement* as = Statement::make_assignment(chancase.closed(), okref, cloc); + as->determine_types(gogo); bchan->add_statement(as); } else if (chancase.closedvar() != NULL) @@ -6047,6 +6498,7 @@ Select_statement::lower_two_case(Gogo* gogo, Block* b) Statement* ifs = Statement::make_if_statement(cond, bchan, defcase.statements(), loc); + ifs->determine_types(gogo); b->add_statement(ifs); Statement* label = @@ -6129,16 +6581,47 @@ For_statement::do_traverse(Traverse* traverse) return this->statements_->traverse(traverse); } +void +For_statement::do_determine_types(Gogo* gogo) +{ + if (this->init_ != NULL) + this->init_->determine_types(gogo); + if (this->cond_ != NULL) + this->cond_->determine_type_no_context(gogo); + if (this->post_ != NULL) + this->post_->determine_types(gogo); + this->statements_->determine_types(gogo); +} + +void +For_statement::do_check_types(Gogo*) +{ + if (this->cond_ != NULL) + { + Type* type = this->cond_->type(); + if (type->is_error()) + this->set_is_error(); + else if (!type->is_boolean_type()) + { + go_error_at(this->cond_->location(), "expected boolean expression"); + this->set_is_error(); + } + } +} + // Lower a For_statement into if statements and gotos. Getting rid of // complex statements make it easier to handle garbage collection. Statement* -For_statement::do_lower(Gogo*, Named_object*, Block* enclosing, +For_statement::do_lower(Gogo* gogo, Named_object*, Block* enclosing, Statement_inserter*) { - Statement* s; Location loc = this->location(); + if (this->classification() == STATEMENT_ERROR) + return Statement::make_error_statement(loc); + + Statement* s; Block* b = new Block(enclosing, this->location()); if (this->init_ != NULL) { @@ -6188,6 +6671,7 @@ For_statement::do_lower(Gogo*, Named_object*, Block* enclosing, then_block->add_statement(s); s = Statement::make_if_statement(this->cond_, then_block, NULL, cond_loc); + s->determine_types(gogo); b->add_statement(s); } @@ -6318,22 +6802,30 @@ For_range_statement::do_traverse(Traverse* traverse) return this->statements_->traverse(traverse); } -// Lower a for range statement. For simplicity we lower this into a -// for statement, which will then be lowered in turn to goto -// statements. +void +For_range_statement::do_determine_types(Gogo* gogo) +{ + if (this->index_var_ != NULL) + this->index_var_->determine_type_no_context(gogo); + if (this->value_var_ != NULL) + this->value_var_->determine_type_no_context(gogo); + this->range_->determine_type_no_context(gogo); + this->statements_->determine_types(gogo); +} -Statement* -For_range_statement::do_lower(Gogo* gogo, Named_object*, Block* enclosing, - Statement_inserter*) +void +For_range_statement::do_check_types(Gogo*) { Type* range_type = this->range_->type(); + + Type* index_type; + Type* value_type = NULL; + if (range_type->points_to() != NULL && range_type->points_to()->array_type() != NULL && !range_type->points_to()->is_slice_type()) range_type = range_type->points_to(); - Type* index_type; - Type* value_type = NULL; if (range_type->array_type() != NULL) { index_type = Type::lookup_integer_type("int"); @@ -6351,22 +6843,79 @@ For_range_statement::do_lower(Gogo* gogo, Named_object*, Block* enclosing, } else if (range_type->channel_type() != NULL) { + if (!range_type->channel_type()->may_receive()) + this->report_error(_("invalid receive on send-only channel")); index_type = range_type->channel_type()->element_type(); if (this->value_var_ != NULL) { if (!this->value_var_->type()->is_error()) this->report_error(_("too many variables for range clause " "with channel")); - return Statement::make_error_statement(this->location()); + this->set_is_error(); + return; } } else { this->report_error(_("range clause must have " "array, slice, string, map, or channel type")); - return Statement::make_error_statement(this->location()); + return; } + if (this->index_var_ != NULL + && !Assignment_statement::check_assignment_types(this->index_var_, + index_type, + this->location())) + this->set_is_error(); + if (this->value_var_ != NULL + && !Assignment_statement::check_assignment_types(this->value_var_, + value_type, + this->location())) + this->set_is_error(); +} + +// Lower a for range statement. For simplicity we lower this into a +// for statement, which will then be lowered in turn to goto +// statements. + +Statement* +For_range_statement::do_lower(Gogo* gogo, Named_object*, Block* enclosing, + Statement_inserter*) +{ + if (this->classification() == STATEMENT_ERROR) + return Statement::make_error_statement(this->location()); + + Type* range_type = this->range_->type(); + if (range_type->points_to() != NULL + && range_type->points_to()->array_type() != NULL + && !range_type->points_to()->is_slice_type()) + range_type = range_type->points_to(); + + Type* index_type; + Type* value_type = NULL; + if (range_type->array_type() != NULL) + { + index_type = Type::lookup_integer_type("int"); + value_type = range_type->array_type()->element_type(); + } + else if (range_type->is_string_type()) + { + index_type = Type::lookup_integer_type("int"); + value_type = Type::lookup_integer_type("rune"); + } + else if (range_type->map_type() != NULL) + { + index_type = range_type->map_type()->key_type(); + value_type = range_type->map_type()->val_type(); + } + else if (range_type->channel_type() != NULL) + { + index_type = range_type->channel_type()->element_type(); + go_assert(this->value_var_ == NULL); + } + else + go_unreachable(); + // If there is only one iteration variable, and len(this->range_) is // constant, then we do not evaluate the range variable. len(x) is // a contant if x is a string constant or if x is an array. If x is @@ -6412,6 +6961,7 @@ For_range_statement::do_lower(Gogo* gogo, Named_object*, Block* enclosing, { if (gogo->debug_optimization()) go_debug(loc, "map range clear"); + clear->determine_types(gogo); temp_block->add_statement(clear); return Statement::make_block_statement(temp_block, loc); } @@ -6429,6 +6979,7 @@ For_range_statement::do_lower(Gogo* gogo, Named_object*, Block* enclosing, { if (gogo->debug_optimization()) go_debug(loc, "array range clear"); + clear->determine_types(gogo); temp_block->add_statement(clear); return Statement::make_block_statement(temp_block, loc); } @@ -6505,6 +7056,7 @@ For_range_statement::do_lower(Gogo* gogo, Named_object*, Block* enclosing, assign = Statement::make_tuple_assignment(lhs, rhs, loc); } + assign->determine_types(gogo); body->add_statement(assign); } @@ -6515,6 +7067,7 @@ For_range_statement::do_lower(Gogo* gogo, Named_object*, Block* enclosing, For_statement* loop = Statement::make_for_statement(init, cond, post, this->location()); loop->add_statements(body); + loop->determine_types(gogo); loop->set_break_continue_labels(this->break_label_, this->continue_label_); temp_block->add_statement(loop); @@ -6596,12 +7149,14 @@ For_range_statement::lower_range_array(Gogo* gogo, { Expression* ref = this->make_range_ref(range_object, range_temp, loc); range_temp = Statement::make_temporary(NULL, ref, loc); + range_temp->determine_types(gogo); init->add_statement(range_temp); len_arg = ref; } Expression* len_call = this->call_builtin(gogo, "len", len_arg, loc); Temporary_statement* len_temp = Statement::make_temporary(index_temp->type(), len_call, loc); + len_temp->determine_types(gogo); init->add_statement(len_temp); Expression* zexpr = Expression::make_integer_ul(0, NULL, loc); @@ -6610,6 +7165,7 @@ For_range_statement::lower_range_array(Gogo* gogo, Expression::make_temporary_reference(index_temp, loc); tref->set_is_lvalue(); Statement* s = Statement::make_assignment(tref, zexpr, loc); + s->determine_types(gogo); init->add_statement(s); *pinit = init; @@ -6638,6 +7194,7 @@ For_range_statement::lower_range_array(Gogo* gogo, tref = Expression::make_temporary_reference(value_temp, loc); tref->set_is_lvalue(); s = Statement::make_assignment(tref, index, loc); + s->determine_types(gogo); iter_init->add_statement(s); } @@ -6650,6 +7207,7 @@ For_range_statement::lower_range_array(Gogo* gogo, tref = Expression::make_temporary_reference(index_temp, loc); tref->set_is_lvalue(); s = Statement::make_inc_statement(tref); + s->determine_types(gogo); post->add_statement(s); *ppost = post; } @@ -6694,12 +7252,14 @@ For_range_statement::lower_range_slice(Gogo* gogo, Expression* ref = this->make_range_ref(range_object, range_temp, loc); Temporary_statement* for_temp = Statement::make_temporary(NULL, ref, loc); + for_temp->determine_types(gogo); init->add_statement(for_temp); ref = Expression::make_temporary_reference(for_temp, loc); Expression* len_call = this->call_builtin(gogo, "len", ref, loc); Temporary_statement* len_temp = Statement::make_temporary(index_temp->type(), len_call, loc); + len_temp->determine_types(gogo); init->add_statement(len_temp); Expression* zexpr = Expression::make_integer_ul(0, NULL, loc); @@ -6708,6 +7268,7 @@ For_range_statement::lower_range_slice(Gogo* gogo, Expression::make_temporary_reference(index_temp, loc); tref->set_is_lvalue(); Statement* s = Statement::make_assignment(tref, zexpr, loc); + s->determine_types(gogo); init->add_statement(s); *pinit = init; @@ -6736,6 +7297,7 @@ For_range_statement::lower_range_slice(Gogo* gogo, tref = Expression::make_temporary_reference(value_temp, loc); tref->set_is_lvalue(); s = Statement::make_assignment(tref, index, loc); + s->determine_types(gogo); iter_init->add_statement(s); } @@ -6748,6 +7310,7 @@ For_range_statement::lower_range_slice(Gogo* gogo, tref = Expression::make_temporary_reference(index_temp, loc); tref->set_is_lvalue(); s = Statement::make_inc_statement(tref); + s->determine_types(gogo); post->add_statement(s); *ppost = post; } @@ -6796,6 +7359,7 @@ For_range_statement::lower_range_string(Gogo* gogo, Call_expression* call = this->call_builtin(gogo, "len", ref, loc); Temporary_statement* len_temp = Statement::make_temporary(index_temp->type(), call, loc); + len_temp->determine_types(gogo); init->add_statement(len_temp); Temporary_statement* next_index_temp = @@ -6807,6 +7371,7 @@ For_range_statement::lower_range_string(Gogo* gogo, index_ref->set_is_lvalue(); Expression* zexpr = Expression::make_integer_ul(0, index_temp->type(), loc); Statement* s = Statement::make_assignment(index_ref, zexpr, loc); + s->determine_types(gogo); init->add_statement(s); Type* rune_type; @@ -6847,6 +7412,7 @@ For_range_statement::lower_range_string(Gogo* gogo, Expression::make_temporary_reference(value_temp, loc); value_ref->set_is_lvalue(); s = Statement::make_assignment(value_ref, ref, loc); + s->determine_types(gogo); iter_init->add_statement(s); value_ref = Expression::make_temporary_reference(value_temp, loc); @@ -6864,6 +7430,7 @@ For_range_statement::lower_range_string(Gogo* gogo, Expression* sum = Expression::make_binary(OPERATOR_PLUS, index_ref, one, loc); s = Statement::make_assignment(lhs, sum, loc); + s->determine_types(gogo); then_block->add_statement(s); Block* else_block = new Block(iter_init, loc); @@ -6876,15 +7443,18 @@ For_range_statement::lower_range_string(Gogo* gogo, value_ref->set_is_lvalue(); Expression* res = Expression::make_call_result(call, 0); s = Statement::make_assignment(value_ref, res, loc); + s->determine_types(gogo); else_block->add_statement(s); lhs = Expression::make_temporary_reference(next_index_temp, loc); lhs->set_is_lvalue(); res = Expression::make_call_result(call, 1); s = Statement::make_assignment(lhs, res, loc); + s->determine_types(gogo); else_block->add_statement(s); s = Statement::make_if_statement(cond, then_block, else_block, loc); + s->determine_types(gogo); iter_init->add_statement(s); *piter_init = iter_init; @@ -6898,6 +7468,7 @@ For_range_statement::lower_range_string(Gogo* gogo, index_ref->set_is_lvalue(); ref = Expression::make_temporary_reference(next_index_temp, loc); s = Statement::make_assignment(index_ref, ref, loc); + s->determine_types(gogo); post->add_statement(s); *ppost = post; @@ -6951,7 +7522,9 @@ For_range_statement::lower_range_map(Gogo* gogo, Expression* p3 = Expression::make_unary(OPERATOR_AND, ref, loc); Expression* call = Runtime::make_call(gogo, Runtime::MAPITERINIT, loc, 3, p1, p2, p3); - init->add_statement(Statement::make_statement(call, true)); + Statement* s = Statement::make_statement(call, true); + s->determine_types(gogo); + init->add_statement(s); *pinit = init; @@ -6977,6 +7550,7 @@ For_range_statement::lower_range_map(Gogo* gogo, rhs = Expression::make_dereference(ref, Expression::NIL_CHECK_NOT_NEEDED, loc); Statement* set = Statement::make_assignment(lhs, rhs, loc); + set->determine_types(gogo); iter_init->add_statement(set); if (value_temp != NULL) @@ -6987,6 +7561,7 @@ For_range_statement::lower_range_map(Gogo* gogo, rhs = Expression::make_dereference(rhs, Expression::NIL_CHECK_NOT_NEEDED, loc); set = Statement::make_assignment(lhs, rhs, loc); + set->determine_types(gogo); iter_init->add_statement(set); } @@ -7000,7 +7575,9 @@ For_range_statement::lower_range_map(Gogo* gogo, ref = Expression::make_temporary_reference(hiter, loc); p1 = Expression::make_unary(OPERATOR_AND, ref, loc); call = Runtime::make_call(gogo, Runtime::MAPITERNEXT, loc, 1, p1); - post->add_statement(Statement::make_statement(call, true)); + s = Statement::make_statement(call, true); + s->determine_types(gogo); + post->add_statement(s); *ppost = post; } @@ -7008,7 +7585,7 @@ For_range_statement::lower_range_map(Gogo* gogo, // Lower a for range over a channel. void -For_range_statement::lower_range_channel(Gogo*, +For_range_statement::lower_range_channel(Gogo* gogo, Block*, Block* body_block, Named_object* range_object, @@ -7061,6 +7638,7 @@ For_range_statement::lower_range_channel(Gogo*, oref->set_is_lvalue(); Statement* s = Statement::make_tuple_receive_assignment(iref, oref, cref, loc); + s->determine_types(gogo); iter_init->add_statement(s); Block* then_block = new Block(iter_init, loc); @@ -7070,6 +7648,7 @@ For_range_statement::lower_range_channel(Gogo*, oref = Expression::make_temporary_reference(ok_temp, loc); Expression* cond = Expression::make_unary(OPERATOR_NOT, oref, loc); s = Statement::make_if_statement(cond, then_block, NULL, loc); + s->determine_types(gogo); iter_init->add_statement(s); *piter_init = iter_init; @@ -7125,7 +7704,9 @@ For_range_statement::lower_map_range_clear(Gogo* gogo, Expression* e1 = Expression::make_type_descriptor(map_type, loc); Expression* e2 = this->make_range_ref(range_object, range_temp, loc); call = Runtime::make_call(gogo, Runtime::MAPCLEAR, loc, 2, e1, e2); - return Statement::make_statement(call, true); + Statement* s = Statement::make_statement(call, true); + s->determine_types(gogo); + return s; } // Match @@ -7193,6 +7774,7 @@ For_range_statement::lower_array_range_clear(Gogo* gogo, ref = this->make_range_ref(range_object, range_temp, loc); Expression* len = this->call_builtin(gogo, "len", ref, loc); Temporary_statement* tslen = Statement::make_temporary(NULL, len, loc); + tslen->determine_types(gogo); temp_block->add_statement(tslen); Expression* zero = Expression::make_integer_ul(0, this->index_var_->type(), loc); @@ -7201,12 +7783,14 @@ For_range_statement::lower_array_range_clear(Gogo* gogo, elem->array_index_expression()->set_needs_bounds_check(false); Expression* e1 = Expression::make_unary(OPERATOR_AND, elem, loc); Temporary_statement* ts1 = Statement::make_temporary(NULL, e1, loc); + ts1->determine_types(gogo); b->add_statement(ts1); len = Expression::make_temporary_reference(tslen, loc); Expression* sz = Expression::make_integer_int64(elme_sz, len->type(), loc); Expression* e2 = Expression::make_binary(OPERATOR_MULT, len, sz, loc); Temporary_statement* ts2 = Statement::make_temporary(NULL, e2, loc); + ts2->determine_types(gogo); b->add_statement(ts2); Expression* ptr_arg = Expression::make_temporary_reference(ts1, loc); @@ -7223,6 +7807,7 @@ For_range_statement::lower_array_range_clear(Gogo* gogo, zero32, sz_arg); } Statement* cs3 = Statement::make_statement(call, true); + cs3->determine_types(gogo); b->add_statement(cs3); len = Expression::make_temporary_reference(tslen, loc); @@ -7230,12 +7815,15 @@ For_range_statement::lower_array_range_clear(Gogo* gogo, Expression* rhs = Expression::make_binary(OPERATOR_MINUS, len, one, loc); Expression* lhs = this->index_var_->copy(); Statement* as4 = Statement::make_assignment(lhs, rhs, loc); + as4->determine_types(gogo); b->add_statement(as4); len = Expression::make_temporary_reference(tslen, loc); zero = zero->copy(); Expression* cond = Expression::make_binary(OPERATOR_NOTEQ, len, zero, loc); - return Statement::make_if_statement(cond, b, NULL, loc); + Statement* ret = Statement::make_if_statement(cond, b, NULL, loc); + ret->determine_types(gogo); + return ret; } // Return the break LABEL_EXPR. diff --git a/gcc/go/gofrontend/statements.h b/gcc/go/gofrontend/statements.h index 9a920ba..530011c 100644 --- a/gcc/go/gofrontend/statements.h +++ b/gcc/go/gofrontend/statements.h @@ -171,16 +171,17 @@ class Statement static Statement* make_defer_statement(Call_expression* call, Location); - // Make a return statement. + // Make a return statement. FUNCTION is a backpointer to the + // function that this statement is returning from. static Return_statement* - make_return_statement(Expression_list*, Location); + make_return_statement(Named_object* function, Expression_list*, Location); // Make a statement that returns the result of a call expression. // If the call does not return any results, this just returns the // call expression as a statement, assuming that the function will // end immediately afterward. static Statement* - make_return_from_call(Call_expression*, Location); + make_return_from_call(Named_object* function, Call_expression*, Location); // Make a break statement. static Statement* @@ -580,6 +581,11 @@ class Assignment_statement : public Statement set_omit_write_barrier() { this->omit_write_barrier_ = true; } + // Check if we can assign RHS to LHS. If we can, return true. If + // we can't, report an error and return false. + static bool + check_assignment_types(Expression* lhs, Type* rhs_type, Location); + protected: int do_traverse(Traverse* traverse); @@ -765,6 +771,9 @@ class Variable_declaration_statement : public Statement int do_traverse(Traverse*); + void + do_determine_types(Gogo*); + Statement* do_lower(Gogo*, Named_object*, Block*, Statement_inserter*); @@ -796,9 +805,11 @@ class Variable_declaration_statement : public Statement class Return_statement : public Statement { public: - Return_statement(Expression_list* vals, Location location) + Return_statement(Named_object* function, Expression_list* vals, + Location location) : Statement(STATEMENT_RETURN, location), - vals_(vals), is_lowered_(false) + function_(function), vals_(vals), types_are_determined_(false), + is_lowered_(false) { } // The list of values being returned. This may be NULL. @@ -811,6 +822,12 @@ class Return_statement : public Statement do_traverse(Traverse* traverse) { return this->traverse_expression_list(traverse, this->vals_); } + void + do_determine_types(Gogo*); + + void + do_check_types(Gogo*); + Statement* do_lower(Gogo*, Named_object*, Block*, Statement_inserter*); @@ -832,8 +849,12 @@ class Return_statement : public Statement do_dump_statement(Ast_dump_context*) const; private: + // A backpointer to the function we are returning from. + Named_object* function_; // Return values. This may be NULL. Expression_list* vals_; + // True if types have been determined. + bool types_are_determined_; // True if this statement has been lowered. bool is_lowered_; }; @@ -1185,14 +1206,14 @@ class Select_clauses private: void - lower_send(Block*, Expression*, Expression*); + lower_send(Gogo*, Block*, Expression*, Expression*); void lower_recv(Gogo*, Named_object*, Block*, Expression*, Expression*, Temporary_statement*); void - set_case(Block*, Expression*, Expression*, Expression*); + set_case(Gogo*, Block*, Expression*, Expression*, Expression*); // The channel. Expression* channel_; @@ -1655,6 +1676,12 @@ class For_statement : public Statement int do_traverse(Traverse*); + void + do_determine_types(Gogo*); + + void + do_check_types(Gogo*); + Statement* do_lower(Gogo*, Named_object*, Block*, Statement_inserter*); @@ -1715,6 +1742,12 @@ class For_range_statement : public Statement int do_traverse(Traverse*); + void + do_determine_types(Gogo*); + + void + do_check_types(Gogo*); + Statement* do_lower(Gogo*, Named_object*, Block*, Statement_inserter*); @@ -1817,7 +1850,7 @@ class Case_clauses // Lower for a nonconstant switch. void - lower(Block*, Temporary_statement*, Unnamed_label*) const; + lower(Gogo*, Block*, Temporary_statement*, Unnamed_label*) const; // Determine types of expressions. The Type parameter is the type // of the switch value. @@ -1892,7 +1925,8 @@ class Case_clauses // Lower for a nonconstant switch. void - lower(Block*, Temporary_statement*, Unnamed_label*, Unnamed_label*) const; + lower(Gogo*, Block*, Temporary_statement*, Unnamed_label*, + Unnamed_label*) const; // Determine types. void @@ -1970,6 +2004,12 @@ class Switch_statement : public Statement int do_traverse(Traverse*); + void + do_determine_types(Gogo*); + + void + do_check_types(Gogo*); + Statement* do_lower(Gogo*, Named_object*, Block*, Statement_inserter*); @@ -2028,9 +2068,17 @@ class Type_case_clauses void check_duplicates() const; + // Determine types of expressions. + void + determine_types(Gogo*); + + // Check types. + bool + check_types(Type*); + // Lower to if and goto statements. void - lower(Gogo*, Type*, Block*, Temporary_statement* descriptor_temp, + lower(Gogo*, Block*, Temporary_statement* descriptor_temp, Unnamed_label* break_label) const; // Return true if these clauses may fall through to the statements @@ -2077,9 +2125,17 @@ class Type_case_clauses int traverse(Traverse*); + // Determine types. + void + determine_types(Gogo*); + + // Check types. + bool + check_types(Type*); + // Lower to if and goto statements. void - lower(Gogo*, Type*, Block*, Temporary_statement* descriptor_temp, + lower(Gogo*, Block*, Temporary_statement* descriptor_temp, Unnamed_label* break_label, Unnamed_label** stmts_label) const; // Return true if this clause may fall through to execute the @@ -2140,6 +2196,12 @@ class Type_switch_statement : public Statement int do_traverse(Traverse*); + void + do_determine_types(Gogo*); + + void + do_check_types(Gogo*); + Statement* do_lower(Gogo*, Named_object*, Block*, Statement_inserter*); diff --git a/gcc/go/gofrontend/types.cc b/gcc/go/gofrontend/types.cc index e6b1250..b349ad1 100644 --- a/gcc/go/gofrontend/types.cc +++ b/gcc/go/gofrontend/types.cc @@ -1377,6 +1377,7 @@ Type::make_type_descriptor_var(Gogo* gogo) // Build the contents of the type descriptor. Expression* initializer = this->do_type_descriptor(gogo, NULL); + initializer->determine_type_no_context(gogo); Btype* initializer_btype = initializer->type()->get_backend(gogo); @@ -1492,7 +1493,9 @@ Type::type_descriptor_defined_elsewhere(Named_type* nt, Expression* Type::type_descriptor(Gogo* gogo, Type* type) { - return type->do_type_descriptor(gogo, NULL); + Expression* ret = type->do_type_descriptor(gogo, NULL); + ret->determine_type_no_context(gogo); + return ret; } // Return a composite literal for a type descriptor with a name. @@ -1501,7 +1504,9 @@ Expression* Type::named_type_descriptor(Gogo* gogo, Type* type, Named_type* name) { go_assert(name != NULL && type->named_type() != name); - return type->do_type_descriptor(gogo, name); + Expression* ret = type->do_type_descriptor(gogo, name); + ret->determine_type_no_context(gogo); + return ret; } // Make a builtin struct type from a list of fields. The fields are @@ -1989,16 +1994,17 @@ Type::write_hash_function(Gogo* gogo, int64_t size, const Backend_name* bname, gogo->start_block(bloc); if (size != -1) - this->write_identity_hash(gogo, size); + this->write_identity_hash(gogo, hash_fn, size); else if (this->struct_type() != NULL) - this->struct_type()->write_hash_function(gogo, hash_fntype); + this->struct_type()->write_hash_function(gogo, hash_fn, hash_fntype); else if (this->array_type() != NULL) - this->array_type()->write_hash_function(gogo, hash_fntype); + this->array_type()->write_hash_function(gogo, hash_fn, hash_fntype); else go_unreachable(); Block* b = gogo->finish_block(bloc); gogo->add_block(b, bloc); + b->determine_types(gogo); gogo->lower_block(hash_fn, b); gogo->order_block(b); gogo->remove_shortcuts_in_block(b); @@ -2016,7 +2022,7 @@ Type::write_hash_function(Gogo* gogo, int64_t size, const Backend_name* bname, // is called), and the constant size. void -Type::write_identity_hash(Gogo* gogo, int64_t size) +Type::write_identity_hash(Gogo* gogo, Named_object* function, int64_t size) { Location bloc = Linemap::predeclared_location(); @@ -2057,7 +2063,8 @@ Type::write_identity_hash(Gogo* gogo, int64_t size) Expression_list* vals = new Expression_list(); vals->push_back(call); - Statement* s = Statement::make_return_statement(vals, bloc); + Statement* s = Statement::make_return_statement(function, vals, bloc); + s->determine_types(gogo); gogo->add_statement(s); } @@ -2329,18 +2336,19 @@ Type::write_equal_function(Gogo* gogo, Named_type* name, int64_t size, gogo->start_block(bloc); if (size != -1) - this->write_identity_equal(gogo, size); + this->write_identity_equal(gogo, equal_fn, size); else if (name != NULL && name->real_type()->named_type() != NULL) - this->write_named_equal(gogo, name); + this->write_named_equal(gogo, equal_fn, name); else if (this->struct_type() != NULL) - this->struct_type()->write_equal_function(gogo, name); + this->struct_type()->write_equal_function(gogo, equal_fn, name); else if (this->array_type() != NULL) - this->array_type()->write_equal_function(gogo, name); + this->array_type()->write_equal_function(gogo, equal_fn, name); else go_unreachable(); Block* b = gogo->finish_block(bloc); gogo->add_block(b, bloc); + b->determine_types(gogo); gogo->lower_block(equal_fn, b); gogo->order_block(b); gogo->remove_shortcuts_in_block(b); @@ -2358,7 +2366,7 @@ Type::write_equal_function(Gogo* gogo, Named_type* name, int64_t size, // constructed before this is called), and the constant size. void -Type::write_identity_equal(Gogo* gogo, int64_t size) +Type::write_identity_equal(Gogo* gogo, Named_object* function, int64_t size) { Location bloc = Linemap::predeclared_location(); @@ -2399,7 +2407,8 @@ Type::write_identity_equal(Gogo* gogo, int64_t size) Expression_list* vals = new Expression_list(); vals->push_back(call); - Statement* s = Statement::make_return_statement(vals, bloc); + Statement* s = Statement::make_return_statement(function, vals, bloc); + s->determine_types(gogo); gogo->add_statement(s); } @@ -2410,7 +2419,7 @@ Type::write_identity_equal(Gogo* gogo, int64_t size) // functions defined only in that package. void -Type::write_named_equal(Gogo* gogo, Named_type* name) +Type::write_named_equal(Gogo* gogo, Named_object* function, Named_type* name) { Location bloc = Linemap::predeclared_location(); @@ -2429,11 +2438,13 @@ Type::write_named_equal(Gogo* gogo, Named_type* name) Expression* ref = Expression::make_var_reference(key1_arg, bloc); ref = Expression::make_cast(pt, ref, bloc); Temporary_statement* p1 = Statement::make_temporary(pt, ref, bloc); + p1->determine_types(gogo); gogo->add_statement(p1); ref = Expression::make_var_reference(key2_arg, bloc); ref = Expression::make_cast(pt, ref, bloc); Temporary_statement* p2 = Statement::make_temporary(pt, ref, bloc); + p2->determine_types(gogo); gogo->add_statement(p2); // Compare the values for equality. @@ -2448,7 +2459,8 @@ Type::write_named_equal(Gogo* gogo, Named_type* name) // Return the equality comparison. Expression_list* vals = new Expression_list(); vals->push_back(cond); - Statement* s = Statement::make_return_statement(vals, bloc); + Statement* s = Statement::make_return_statement(function, vals, bloc); + s->determine_types(gogo); gogo->add_statement(s); } @@ -6658,7 +6670,8 @@ Struct_type::do_type_descriptor(Gogo* gogo, Named_type* name) // function. void -Struct_type::write_hash_function(Gogo* gogo, Function_type* hash_fntype) +Struct_type::write_hash_function(Gogo* gogo, Named_object* function, + Function_type* hash_fntype) { Location bloc = Linemap::predeclared_location(); @@ -6678,6 +6691,7 @@ Struct_type::write_hash_function(Gogo* gogo, Function_type* hash_fntype) Expression* ref = Expression::make_var_reference(seed_arg, bloc); Temporary_statement* retval = Statement::make_temporary(uintptr_type, ref, bloc); + retval->determine_types(gogo); gogo->add_statement(retval); // Make a temporary to hold the key as a uintptr. @@ -6685,6 +6699,7 @@ Struct_type::write_hash_function(Gogo* gogo, Function_type* hash_fntype) ref = Expression::make_cast(uintptr_type, ref, bloc); Temporary_statement* key = Statement::make_temporary(uintptr_type, ref, bloc); + key->determine_types(gogo); gogo->add_statement(key); // Loop over the struct fields. @@ -6720,6 +6735,7 @@ Struct_type::write_hash_function(Gogo* gogo, Function_type* hash_fntype) Expression::make_temporary_reference(retval, bloc); tref->set_is_lvalue(); Statement* s = Statement::make_assignment(tref, call, bloc); + s->determine_types(gogo); gogo->add_statement(s); } @@ -6727,7 +6743,8 @@ Struct_type::write_hash_function(Gogo* gogo, Function_type* hash_fntype) Expression_list* vals = new Expression_list(); ref = Expression::make_temporary_reference(retval, bloc); vals->push_back(ref); - Statement* s = Statement::make_return_statement(vals, bloc); + Statement* s = Statement::make_return_statement(function, vals, bloc); + s->determine_types(gogo); gogo->add_statement(s); } @@ -6735,7 +6752,8 @@ Struct_type::write_hash_function(Gogo* gogo, Function_type* hash_fntype) // identity function. void -Struct_type::write_equal_function(Gogo* gogo, Named_type* name) +Struct_type::write_equal_function(Gogo* gogo, Named_object* function, + Named_type* name) { Location bloc = Linemap::predeclared_location(); @@ -6752,11 +6770,13 @@ Struct_type::write_equal_function(Gogo* gogo, Named_type* name) Expression* ref = Expression::make_var_reference(key1_arg, bloc); ref = Expression::make_unsafe_cast(pt, ref, bloc); Temporary_statement* p1 = Statement::make_temporary(pt, ref, bloc); + p1->determine_types(gogo); gogo->add_statement(p1); ref = Expression::make_var_reference(key2_arg, bloc); ref = Expression::make_unsafe_cast(pt, ref, bloc); Temporary_statement* p2 = Statement::make_temporary(pt, ref, bloc); + p2->determine_types(gogo); gogo->add_statement(p2); const Struct_field_list* fields = this->fields_; @@ -6785,18 +6805,21 @@ Struct_type::write_equal_function(Gogo* gogo, Named_type* name) gogo->start_block(bloc); Expression_list* vals = new Expression_list(); vals->push_back(Expression::make_boolean(false, bloc)); - Statement* s = Statement::make_return_statement(vals, bloc); + Statement* s = Statement::make_return_statement(function, vals, bloc); + s->determine_types(gogo); gogo->add_statement(s); Block* then_block = gogo->finish_block(bloc); s = Statement::make_if_statement(cond, then_block, NULL, bloc); + s->determine_types(gogo); gogo->add_statement(s); } // All the fields are equal, so return true. Expression_list* vals = new Expression_list(); vals->push_back(Expression::make_boolean(true, bloc)); - Statement* s = Statement::make_return_statement(vals, bloc); + Statement* s = Statement::make_return_statement(function, vals, bloc); + s->determine_types(gogo); gogo->add_statement(s); } @@ -7342,8 +7365,9 @@ Array_type::verify_length(Gogo* gogo) if (this->length_ == NULL) return true; - Type_context context(Type::lookup_integer_type("int"), false); - this->length_->determine_type(gogo, &context); + Type* int_type = Type::lookup_integer_type("int"); + Type_context int_context(int_type, false); + this->length_->determine_type(gogo, &int_context); if (this->length_->is_error_expression() || this->length_->type()->is_error()) @@ -7379,7 +7403,6 @@ Array_type::verify_length(Gogo* gogo) return false; } - Type* int_type = Type::lookup_integer_type("int"); unsigned int tbits = int_type->integer_type()->bits(); unsigned long val; switch (nc.to_unsigned_long(&val)) @@ -7514,7 +7537,8 @@ Array_type::do_hash_for_method(Gogo* gogo, int flags) const // function. void -Array_type::write_hash_function(Gogo* gogo, Function_type* hash_fntype) +Array_type::write_hash_function(Gogo* gogo, Named_object* function, + Function_type* hash_fntype) { Location bloc = Linemap::predeclared_location(); @@ -7534,6 +7558,7 @@ Array_type::write_hash_function(Gogo* gogo, Function_type* hash_fntype) Expression* ref = Expression::make_var_reference(seed_arg, bloc); Temporary_statement* retval = Statement::make_temporary(uintptr_type, ref, bloc); + retval->determine_types(gogo); gogo->add_statement(retval); // Make a temporary to hold the key as a uintptr. @@ -7541,12 +7566,14 @@ Array_type::write_hash_function(Gogo* gogo, Function_type* hash_fntype) ref = Expression::make_cast(uintptr_type, ref, bloc); Temporary_statement* key = Statement::make_temporary(uintptr_type, ref, bloc); + key->determine_types(gogo); gogo->add_statement(key); // Loop over the array elements. // for i = range a Type* int_type = Type::lookup_integer_type("int"); Temporary_statement* index = Statement::make_temporary(int_type, NULL, bloc); + index->determine_types(gogo); gogo->add_statement(index); Expression* iref = Expression::make_temporary_reference(index, bloc); @@ -7585,6 +7612,7 @@ Array_type::write_hash_function(Gogo* gogo, Function_type* hash_fntype) Expression::make_temporary_reference(retval, bloc); tref->set_is_lvalue(); Statement* s = Statement::make_assignment(tref, call, bloc); + s->determine_types(gogo); gogo->add_statement(s); // Increase the element pointer. @@ -7595,13 +7623,15 @@ Array_type::write_hash_function(Gogo* gogo, Function_type* hash_fntype) Block* statements = gogo->finish_block(bloc); for_range->add_statements(statements); + for_range->determine_types(gogo); gogo->add_statement(for_range); // Return retval to the caller of the hash function. Expression_list* vals = new Expression_list(); ref = Expression::make_temporary_reference(retval, bloc); vals->push_back(ref); - s = Statement::make_return_statement(vals, bloc); + s = Statement::make_return_statement(function, vals, bloc); + s->determine_types(gogo); gogo->add_statement(s); } @@ -7609,7 +7639,8 @@ Array_type::write_hash_function(Gogo* gogo, Function_type* hash_fntype) // identity function. void -Array_type::write_equal_function(Gogo* gogo, Named_type* name) +Array_type::write_equal_function(Gogo* gogo, Named_object* function, + Named_type* name) { Location bloc = Linemap::predeclared_location(); @@ -7626,17 +7657,20 @@ Array_type::write_equal_function(Gogo* gogo, Named_type* name) Expression* ref = Expression::make_var_reference(key1_arg, bloc); ref = Expression::make_unsafe_cast(pt, ref, bloc); Temporary_statement* p1 = Statement::make_temporary(pt, ref, bloc); + p1->determine_types(gogo); gogo->add_statement(p1); ref = Expression::make_var_reference(key2_arg, bloc); ref = Expression::make_unsafe_cast(pt, ref, bloc); Temporary_statement* p2 = Statement::make_temporary(pt, ref, bloc); + p2->determine_types(gogo); gogo->add_statement(p2); // Loop over the array elements. // for i = range a Type* int_type = Type::lookup_integer_type("int"); Temporary_statement* index = Statement::make_temporary(int_type, NULL, bloc); + index->determine_types(gogo); gogo->add_statement(index); Expression* iref = Expression::make_temporary_reference(index, bloc); @@ -7665,22 +7699,26 @@ Array_type::write_equal_function(Gogo* gogo, Named_type* name) gogo->start_block(bloc); Expression_list* vals = new Expression_list(); vals->push_back(Expression::make_boolean(false, bloc)); - Statement* s = Statement::make_return_statement(vals, bloc); + Statement* s = Statement::make_return_statement(function, vals, bloc); + s->determine_types(gogo); gogo->add_statement(s); Block* then_block = gogo->finish_block(bloc); s = Statement::make_if_statement(cond, then_block, NULL, bloc); + s->determine_types(gogo); gogo->add_statement(s); Block* statements = gogo->finish_block(bloc); for_range->add_statements(statements); + for_range->determine_types(gogo); gogo->add_statement(for_range); // All the elements are equal, so return true. vals = new Expression_list(); vals->push_back(Expression::make_boolean(true, bloc)); - s = Statement::make_return_statement(vals, bloc); + s = Statement::make_return_statement(function, vals, bloc); + s->determine_types(gogo); gogo->add_statement(s); } @@ -11805,9 +11843,9 @@ Type::build_stub_methods(Gogo* gogo, const Type* type, const Methods* methods, { stub = gogo->start_function(stub_name, stub_type, false, fntype->location()); - Type::build_one_stub_method(gogo, m, buf, receiver_type, stub_params, - fntype->is_varargs(), stub_results, - location); + Type::build_one_stub_method(gogo, m, stub, buf, receiver_type, + stub_params, fntype->is_varargs(), + stub_results, location); gogo->finish_function(fntype->location()); if (type->named_type() == NULL && stub->is_function()) @@ -11826,6 +11864,7 @@ Type::build_stub_methods(Gogo* gogo, const Type* type, const Methods* methods, void Type::build_one_stub_method(Gogo* gogo, Method* method, + Named_object* stub, const char* receiver_name, const Type* receiver_type, const Typed_identifier_list* params, @@ -11865,7 +11904,7 @@ Type::build_one_stub_method(Gogo* gogo, Method* method, go_assert(func != NULL); Call_expression* call = Expression::make_call(func, arguments, is_varargs, location); - Type::add_return_from_results(gogo, call, results, location); + Type::add_return_from_results(gogo, stub, call, results, location); } // Build direct interface stub methods for TYPE as needed. METHODS @@ -11974,7 +12013,7 @@ Type::build_direct_iface_stub_methods(Gogo* gogo, const Type* type, { stub = gogo->start_function(stub_name, stub_type, false, fntype->location()); - Type::build_one_iface_stub_method(gogo, m, buf, stub_params, + Type::build_one_iface_stub_method(gogo, m, stub, buf, stub_params, fntype->is_varargs(), stub_results, loc); gogo->finish_function(fntype->location()); @@ -12001,6 +12040,7 @@ Type::build_direct_iface_stub_methods(Gogo* gogo, const Type* type, void Type::build_one_iface_stub_method(Gogo* gogo, Method* method, + Named_object* stub, const char* receiver_name, const Typed_identifier_list* params, bool is_varargs, @@ -12037,7 +12077,7 @@ Type::build_one_iface_stub_method(Gogo* gogo, Method* method, go_assert(func != NULL); Call_expression* call = Expression::make_call(func, arguments, is_varargs, loc); - Type::add_return_from_results(gogo, call, results, loc); + Type::add_return_from_results(gogo, stub, call, results, loc); } // Build and add a return statement from a call expression and a list @@ -12045,9 +12085,10 @@ Type::build_one_iface_stub_method(Gogo* gogo, Method* method, // results. void -Type::add_return_from_results(Gogo* gogo, Call_expression* call, - const Typed_identifier_list* results, - Location loc) +Type::add_return_from_results(Gogo* gogo, Named_object* stub, + Call_expression* call, + const Typed_identifier_list* results, + Location loc) { Statement* s; if (results == NULL || results->empty()) @@ -12063,9 +12104,10 @@ Type::add_return_from_results(Gogo* gogo, Call_expression* call, for (size_t i = 0; i < rc; ++i) vals->push_back(Expression::make_call_result(call, i)); } - s = Statement::make_return_statement(vals, loc); + s = Statement::make_return_statement(stub, vals, loc); } + s->determine_types(gogo); gogo->add_statement(s); } diff --git a/gcc/go/gofrontend/types.h b/gcc/go/gofrontend/types.h index 15f29f7..3dd3279 100644 --- a/gcc/go/gofrontend/types.h +++ b/gcc/go/gofrontend/types.h @@ -1300,13 +1300,13 @@ class Type Function_type* equal_fntype); void - write_identity_hash(Gogo*, int64_t size); + write_identity_hash(Gogo*, Named_object* function, int64_t size); void - write_identity_equal(Gogo*, int64_t size); + write_identity_equal(Gogo*, Named_object* function, int64_t size); void - write_named_equal(Gogo*, Named_type*); + write_named_equal(Gogo*, Named_object* function, Named_type*); // Build a composite literal for the uncommon type information. Expression* @@ -1354,8 +1354,8 @@ class Type Location); static void - build_one_stub_method(Gogo*, Method*, const char* receiver_name, - const Type* receiver_type, + build_one_stub_method(Gogo*, Method*, Named_object* stub, + const char* receiver_name, const Type* receiver_type, const Typed_identifier_list*, bool is_varargs, const Typed_identifier_list*, Location); @@ -1364,12 +1364,12 @@ class Type build_direct_iface_stub_methods(Gogo*, const Type*, Methods*, Location); static void - build_one_iface_stub_method(Gogo*, Method*, const char*, + build_one_iface_stub_method(Gogo*, Method*, Named_object* stub, const char*, const Typed_identifier_list*, bool, const Typed_identifier_list*, Location); static void - add_return_from_results(Gogo*, Call_expression*, + add_return_from_results(Gogo*, Named_object* stub, Call_expression*, const Typed_identifier_list*, Location); static Expression* @@ -2654,11 +2654,11 @@ class Struct_type : public Type // Write the hash function for this type. void - write_hash_function(Gogo*, Function_type*); + write_hash_function(Gogo*, Named_object* function, Function_type*); // Write the equality function for this type. void - write_equal_function(Gogo*, Named_type*); + write_equal_function(Gogo*, Named_object* function, Named_type*); // Whether we can write this type to a C header file, to implement // -fgo-c-header. @@ -2844,11 +2844,11 @@ class Array_type : public Type // Write the hash function for this type. void - write_hash_function(Gogo*, Function_type*); + write_hash_function(Gogo*, Named_object* function, Function_type*); // Write the equality function for this type. void - write_equal_function(Gogo*, Named_type*); + write_equal_function(Gogo*, Named_object* function, Named_type*); protected: int diff --git a/gcc/go/gofrontend/wb.cc b/gcc/go/gofrontend/wb.cc index 0621014..d0d6326 100644 --- a/gcc/go/gofrontend/wb.cc +++ b/gcc/go/gofrontend/wb.cc @@ -872,6 +872,7 @@ Gogo::assign_with_write_barrier(Function* function, Block* enclosing, addr->unary_expression()->set_does_not_escape(); } Temporary_statement* lhs_temp = Statement::make_temporary(NULL, addr, loc); + lhs_temp->determine_types(this); inserter->insert(lhs_temp); lhs = Expression::make_temporary_reference(lhs_temp, loc); @@ -883,6 +884,7 @@ Gogo::assign_with_write_barrier(Function* function, Block* enclosing, { // May need a temporary for interface conversion. Temporary_statement* temp = Statement::make_temporary(NULL, rhs, loc); + temp->determine_types(this); inserter->insert(temp); rhs = Expression::make_temporary_reference(temp, loc); } @@ -891,6 +893,7 @@ Gogo::assign_with_write_barrier(Function* function, Block* enclosing, if (!rhs->is_multi_eval_safe()) { rhs_temp = Statement::make_temporary(NULL, rhs, loc); + rhs_temp->determine_types(this); inserter->insert(rhs_temp); rhs = Expression::make_temporary_reference(rhs_temp, loc); } @@ -940,6 +943,7 @@ Gogo::assign_with_write_barrier(Function* function, Block* enclosing, Expression::STRING_INFO_LENGTH, loc); Statement* as = Statement::make_assignment(llen, rlen, loc); + as->determine_types(this); inserter->insert(as); // Assign the data field with a write barrier. @@ -978,6 +982,7 @@ Gogo::assign_with_write_barrier(Function* function, Block* enclosing, Expression::INTERFACE_INFO_METHODS, loc); Statement* as = Statement::make_assignment(ltab, rtab, loc); + as->determine_types(this); inserter->insert(as); // Assign the data field with a write barrier. @@ -1010,6 +1015,7 @@ Gogo::assign_with_write_barrier(Function* function, Block* enclosing, Expression::SLICE_INFO_LENGTH, loc); Statement* as = Statement::make_assignment(llen, rlen, loc); + as->determine_types(this); inserter->insert(as); // Assign the capacity fields directly. @@ -1022,6 +1028,7 @@ Gogo::assign_with_write_barrier(Function* function, Block* enclosing, Expression::SLICE_INFO_CAPACITY, loc); as = Statement::make_assignment(lcap, rcap, loc); + as->determine_types(this); inserter->insert(as); // Assign the data field with a write barrier. @@ -1097,5 +1104,8 @@ Gogo::check_write_barrier(Block* enclosing, Statement* without, Block* else_block = new Block(enclosing, loc); else_block->add_statement(with); - return Statement::make_if_statement(cond, then_block, else_block, loc); + Statement* s = Statement::make_if_statement(cond, then_block, else_block, + loc); + s->determine_types(this); + return s; } |