aboutsummaryrefslogtreecommitdiff
path: root/gcc/go
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/go')
-rw-r--r--gcc/go/gofrontend/MERGE2
-rw-r--r--gcc/go/gofrontend/expressions.cc3684
-rw-r--r--gcc/go/gofrontend/expressions.h236
-rw-r--r--gcc/go/gofrontend/go.cc21
-rw-r--r--gcc/go/gofrontend/gogo.cc209
-rw-r--r--gcc/go/gofrontend/gogo.h18
-rw-r--r--gcc/go/gofrontend/parse.cc15
-rw-r--r--gcc/go/gofrontend/runtime.cc10
-rw-r--r--gcc/go/gofrontend/statements.cc1198
-rw-r--r--gcc/go/gofrontend/statements.h84
-rw-r--r--gcc/go/gofrontend/types.cc118
-rw-r--r--gcc/go/gofrontend/types.h22
-rw-r--r--gcc/go/gofrontend/wb.cc12
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;
}