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