aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@golang.org>2023-10-19 19:34:31 -0700
committerIan Lance Taylor <iant@golang.org>2023-12-18 17:30:56 -0800
commitc20328e7cad2989bcdc9ff5003d6a16405c31ab5 (patch)
tree837db6d6d15e763947916017b122788e30ea1e59 /gcc
parent15cb5204e4c5f79d1b7179ae2590bb65e24b745f (diff)
downloadgcc-c20328e7cad2989bcdc9ff5003d6a16405c31ab5.zip
gcc-c20328e7cad2989bcdc9ff5003d6a16405c31ab5.tar.gz
gcc-c20328e7cad2989bcdc9ff5003d6a16405c31ab5.tar.bz2
compiler: move lowering pass after check types pass
This change moves the lowering pass after the type determination and the type checking passes. This lets us simplify some of the code that determines the type of an expression, which previously had to work correctly both before and after type determination. I'm doing this to help with future generic support. For example, with generics, we can see code like func ident[T any](v T) T { return v } func F() int32 { s := int32(1) return ident(s) } Before this change, we would type check return statements in the lowering pass (see Return_statement::do_lower). With a generic example like the above, that means we have to determine the type of s, and use that to infer the type arguments passed to ident, and use that to determine the result type of ident. That is too much to do at lowering time. Of course we can change the way that return statements work, but similar issues arise with index expressions, the types of closures for function literals, and probably other cases as well. Rather than try to deal with all those cases, we move the lowering pass after type checking. This requires a bunch of changes, notably for determining constant types. We have to add type checking for various constructs that formerly disappeared in the lowering pass. So it's a lot of shuffling. Sorry for the size of the patch. Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/536643
Diffstat (limited to 'gcc')
-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;
}