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