if (lhs_type == rhs_type)
return rhs_tree;
- if (lhs_type->is_error_type() || rhs_type->is_error_type())
+ if (lhs_type->is_error() || rhs_type->is_error())
return error_mark_node;
- if (lhs_type->is_undefined() || rhs_type->is_undefined())
- {
- // Make sure we report the error.
- lhs_type->base();
- rhs_type->base();
- return error_mark_node;
- }
-
if (rhs_tree == error_mark_node || TREE_TYPE(rhs_tree) == error_mark_node)
return error_mark_node;
return this;
}
-// Return the name of the variable.
-
-const std::string&
-Var_expression::name() const
-{
- return this->variable_->name();
-}
-
// Return the type of a reference to a variable.
Type*
gcc_unreachable();
}
+// Determine the type of a reference to a variable.
+
+void
+Var_expression::do_determine_type(const Type_context*)
+{
+ if (this->variable_->is_variable())
+ this->variable_->var_value()->determine_type();
+}
+
// Something takes the address of this variable. This means that we
// may want to move the variable onto the heap.
// a function seems like it could work, though there might be little
// point to it.
-// Return the name of the function.
-
-const std::string&
-Func_expression::name() const
-{
- return this->function_->name();
-}
-
// Traversal.
int
named_object()
{ return this->constant_; }
- const std::string&
- name() const
- { return this->constant_->name(); }
-
// Check that the initializer does not refer to the constant itself.
void
check_for_init_loop();
void
Const_expression::check_for_init_loop()
{
- if (this->type_ != NULL && this->type_->is_error_type())
+ if (this->type_ != NULL && this->type_->is_error())
return;
if (this->seen_)
if (find_named_object.found())
{
- if (this->type_ == NULL || !this->type_->is_error_type())
+ if (this->type_ == NULL || !this->type_->is_error())
{
this->report_error(_("constant refers to itself"));
this->type_ = Type::make_error_type();
void
Const_expression::do_check_types(Gogo*)
{
- if (this->type_ != NULL && this->type_->is_error_type())
+ if (this->type_ != NULL && this->type_->is_error())
return;
this->check_for_init_loop();
Type* expr_type = this->expr_->type();
std::string reason;
- if (type->is_error_type()
- || type->is_undefined()
- || expr_type->is_error_type()
- || expr_type->is_undefined())
+ if (type->is_error() || expr_type->is_error())
{
- // Make sure we emit an error for an undefined type.
- type->base();
- expr_type->base();
this->set_is_error();
return;
}
Unary_expression::do_check_types(Gogo*)
{
Type* type = this->expr_->type();
- if (type->is_error_type())
+ if (type->is_error())
{
this->set_is_error();
return;
{
Type* left_type = this->left_->type();
Type* right_type = this->right_->type();
- if (left_type->is_error_type())
+ if (left_type->is_error())
return left_type;
- else if (right_type->is_error_type())
+ else if (right_type->is_error())
return right_type;
else if (!Type::are_compatible_for_binop(left_type, right_type))
{
Type* left_type = this->left_->type();
Type* right_type = this->right_->type();
- if (left_type->is_error_type() || right_type->is_error_type())
+ if (left_type->is_error() || right_type->is_error())
{
this->set_is_error();
return;
if (this->right_->integer_constant_value(true, val, &type))
{
if (mpz_sgn(val) < 0)
- this->report_error(_("negative shift count"));
+ {
+ this->report_error(_("negative shift count"));
+ mpz_set_ui(val, 0);
+ source_location rloc = this->right_->location();
+ this->right_ = Expression::make_integer(&val, right_type,
+ rloc);
+ }
}
mpz_clear(val);
}
BUILTIN_APPEND,
BUILTIN_CAP,
BUILTIN_CLOSE,
- BUILTIN_CLOSED,
BUILTIN_COMPLEX,
BUILTIN_COPY,
BUILTIN_IMAG,
this->code_ = BUILTIN_CAP;
else if (name == "close")
this->code_ = BUILTIN_CLOSE;
- else if (name == "closed")
- this->code_ = BUILTIN_CLOSED;
else if (name == "complex")
this->code_ = BUILTIN_COMPLEX;
else if (name == "copy")
Expression*
Builtin_call_expression::do_lower(Gogo* gogo, Named_object* function, int)
{
+ if (this->is_varargs() && this->code_ != BUILTIN_APPEND)
+ {
+ this->report_error(_("invalid use of %<...%> with builtin function"));
+ return Expression::make_error(this->location());
+ }
+
if (this->code_ == BUILTIN_NEW)
{
const Expression_list* args = this->args();
if (arg == NULL)
return false;
Type* arg_type = arg->type();
- if (arg_type->is_error_type() || arg_type->is_undefined())
+ if (arg_type->is_error())
return false;
if (arg_type->is_abstract())
return false;
case BUILTIN_PRINTLN:
return Type::make_void_type();
- case BUILTIN_CLOSED:
- return Type::lookup_bool_type();
-
case BUILTIN_RECOVER:
return Type::make_interface_type(NULL, BUILTINS_LOCATION);
void
Builtin_call_expression::do_determine_type(const Type_context* context)
{
+ if (!this->determining_types())
+ return;
+
this->fn()->determine_type_no_context();
const Expression_list* args = this->args();
return false;
}
if (args->front()->is_error_expression()
- || args->front()->type()->is_error_type()
- || args->front()->type()->is_undefined())
+ || args->front()->type()->is_error())
{
this->set_is_error();
return false;
arg_type = arg_type->points_to();
if (this->code_ == BUILTIN_CAP)
{
- if (!arg_type->is_error_type()
+ if (!arg_type->is_error()
&& arg_type->array_type() == NULL
&& arg_type->channel_type() == NULL)
this->report_error(_("argument must be array or slice "
}
else
{
- if (!arg_type->is_error_type()
+ if (!arg_type->is_error()
&& !arg_type->is_string_type()
&& arg_type->array_type() == NULL
&& arg_type->map_type() == NULL
++p)
{
Type* type = (*p)->type();
- if (type->is_error_type()
+ if (type->is_error()
|| type->is_string_type()
|| type->integer_type() != NULL
|| type->float_type() != NULL
break;
case BUILTIN_CLOSE:
- case BUILTIN_CLOSED:
if (this->check_one_arg())
{
if (this->one_arg()->type()->channel_type() == NULL)
}
Type* arg1_type = args->front()->type();
Type* arg2_type = args->back()->type();
- if (arg1_type->is_error_type() || arg2_type->is_error_type())
+ if (arg1_type->is_error() || arg2_type->is_error())
break;
Type* e1;
else if (args->size() > 2)
this->report_error(_("too many arguments"));
else if (args->front()->is_error_expression()
- || args->front()->type()->is_error_type()
+ || args->front()->type()->is_error()
|| args->back()->is_error_expression()
- || args->back()->type()->is_error_type())
+ || args->back()->type()->is_error())
this->set_is_error();
else if (!Type::are_identical(args->front()->type(),
args->back()->type(), true, NULL))
}
case BUILTIN_CLOSE:
- case BUILTIN_CLOSED:
{
const Expression_list* args = this->args();
gcc_assert(args != NULL && args->size() == 1);
tree arg_tree = arg->get_tree(context);
if (arg_tree == error_mark_node)
return error_mark_node;
- if (this->code_ == BUILTIN_CLOSE)
- {
- static tree close_fndecl;
- return Gogo::call_builtin(&close_fndecl,
- location,
- "__go_builtin_close",
- 1,
- void_type_node,
- TREE_TYPE(arg_tree),
- arg_tree);
- }
- else
- {
- static tree closed_fndecl;
- return Gogo::call_builtin(&closed_fndecl,
- location,
- "__go_builtin_closed",
- 1,
- boolean_type_node,
- TREE_TYPE(arg_tree),
- arg_tree);
- }
+ static tree close_fndecl;
+ return Gogo::call_builtin(&close_fndecl,
+ location,
+ "__go_builtin_close",
+ 1,
+ void_type_node,
+ TREE_TYPE(arg_tree),
+ arg_tree);
}
case BUILTIN_SIZEOF:
void
Call_expression::do_determine_type(const Type_context*)
{
+ if (!this->determining_types())
+ return;
+
this->fn_->determine_type_no_context();
Function_type* fntype = this->get_function_type();
const Typed_identifier_list* parameters = NULL;
}
}
+// Called when determining types for a Call_expression. Return true
+// if we should go ahead, false if they have already been determined.
+
+bool
+Call_expression::determining_types()
+{
+ if (this->types_are_determined_)
+ return false;
+ else
+ {
+ this->types_are_determined_ = true;
+ return true;
+ }
+}
+
// Check types for parameter I.
bool
Function_type* fntype = this->get_function_type();
if (fntype == NULL)
{
- if (!this->fn_->type()->is_error_type())
+ if (!this->fn_->type()->is_error())
this->report_error(_("expected function"));
return;
}
void
Call_result_expression::do_determine_type(const Type_context*)
{
- if (this->index_ == 0)
- this->call_->determine_type_no_context();
+ this->call_->determine_type_no_context();
}
// Return the tree.
Expression* end = this->end_;
Type* type = left->type();
- if (type->is_error_type())
+ if (type->is_error())
return Expression::make_error(location);
else if (left->is_type_expression())
{
Array_type* array_type = this->array_->type()->array_type();
if (array_type == NULL)
{
- gcc_assert(this->array_->type()->is_error_type());
+ gcc_assert(this->array_->type()->is_error());
return;
}
Array_type* array_type = this->array_->type()->array_type();
if (array_type == NULL)
{
- gcc_assert(this->array_->type()->is_error_type());
+ gcc_assert(this->array_->type()->is_error());
return error_mark_node;
}
Field_reference_expression::do_type()
{
Type* type = this->expr_->type();
- if (type->is_error_type())
+ if (type->is_error())
return type;
Struct_type* struct_type = type->struct_type();
gcc_assert(struct_type != NULL);
Field_reference_expression::do_check_types(Gogo*)
{
Type* type = this->expr_->type();
- if (type->is_error_type())
+ if (type->is_error())
return;
Struct_type* struct_type = type->struct_type();
gcc_assert(struct_type != NULL);
Array_type* array_type = this->type()->array_type();
if (array_type == NULL)
{
- gcc_assert(this->type()->is_error_type());
+ gcc_assert(this->type()->is_error());
return error_mark_node;
}
private:
Expression*
- lower_struct(Type*);
+ lower_struct(Gogo*, Type*);
Expression*
lower_array(Type*);
type = type->map_type()->val_type();
else
{
- if (!type->is_error_type())
+ if (!type->is_error())
error_at(this->location(),
("may only omit types within composite literals "
"of slice, array, or map type"));
}
}
- if (type->is_error_type())
+ if (type->is_error())
return Expression::make_error(this->location());
else if (type->struct_type() != NULL)
- return this->lower_struct(type);
+ return this->lower_struct(gogo, type);
else if (type->array_type() != NULL)
return this->lower_array(type);
else if (type->map_type() != NULL)
// Lower a struct composite literal.
Expression*
-Composite_literal_expression::lower_struct(Type* type)
+Composite_literal_expression::lower_struct(Gogo* gogo, Type* type)
{
source_location location = this->location();
Struct_type* st = type->struct_type();
bool bad_key = false;
std::string name;
+ const Named_object* no = NULL;
switch (name_expr->classification())
{
case EXPRESSION_UNKNOWN_REFERENCE:
break;
case EXPRESSION_CONST_REFERENCE:
- name = static_cast<Const_expression*>(name_expr)->name();
+ no = static_cast<Const_expression*>(name_expr)->named_object();
break;
case EXPRESSION_TYPE:
if (nt == NULL)
bad_key = true;
else
- name = nt->name();
+ no = nt->named_object();
}
break;
case EXPRESSION_VAR_REFERENCE:
- name = name_expr->var_expression()->name();
+ no = name_expr->var_expression()->named_object();
break;
case EXPRESSION_FUNC_REFERENCE:
- name = name_expr->func_expression()->name();
+ no = name_expr->func_expression()->named_object();
break;
case EXPRESSION_UNARY:
return Expression::make_error(location);
}
+ if (no != NULL)
+ {
+ name = no->name();
+
+ // A predefined name won't be packed. If it starts with a
+ // lower case letter we need to check for that case, because
+ // the field name will be packed.
+ if (!Gogo::is_hidden_name(name)
+ && name[0] >= 'a'
+ && name[0] <= 'z')
+ {
+ Named_object* gno = gogo->lookup_global(name.c_str());
+ if (gno == no)
+ name = gogo->pack_hidden_name(name, false);
+ }
+ }
+
unsigned int index;
const Struct_field* sf = st->find_local_field(name, &index);
if (sf == NULL)
{
mpz_t ival;
mpz_init(ival);
+
Type* dummy;
if (!index_expr->integer_constant_value(true, ival, &dummy))
{
"index expression is not integer constant");
return Expression::make_error(location);
}
+
if (mpz_sgn(ival) < 0)
{
mpz_clear(ival);
error_at(index_expr->location(), "index expression is negative");
return Expression::make_error(location);
}
+
index = mpz_get_ui(ival);
if (mpz_cmp_ui(ival, index) != 0)
{
error_at(index_expr->location(), "index value overflow");
return Expression::make_error(location);
}
+
+ Named_type* ntype = Type::lookup_integer_type("int");
+ Integer_type* inttype = ntype->integer_type();
+ mpz_t max;
+ mpz_init_set_ui(max, 1);
+ mpz_mul_2exp(max, max, inttype->bits() - 1);
+ bool ok = mpz_cmp(ival, max) < 0;
+ mpz_clear(max);
+ if (!ok)
+ {
+ mpz_clear(ival);
+ error_at(index_expr->location(), "index value overflow");
+ return Expression::make_error(location);
+ }
+
mpz_clear(ival);
+
+ // FIXME: Our representation isn't very good; this avoids
+ // thrashing.
+ if (index > 0x1000000)
+ {
+ error_at(index_expr->location(), "index too large for compiler");
+ return Expression::make_error(location);
+ }
}
if (index == vals.size())
}
else if (expr_type->interface_type() == NULL)
{
- if (!expr_type->is_error_type() && !this->type_->is_error_type())
+ if (!expr_type->is_error() && !this->type_->is_error())
this->report_error(_("type assertion only valid for interface types"));
this->set_is_error();
}
if (!expr_type->interface_type()->implements_interface(this->type_,
&reason))
{
- if (!this->type_->is_error_type())
+ if (!this->type_->is_error())
{
if (reason.empty())
this->report_error(_("impossible type assertion: "
Receive_expression::do_check_types(Gogo*)
{
Type* type = this->channel_->type();
- if (type->is_error_type())
+ if (type->is_error())
{
this->set_is_error();
return;
Channel_type* channel_type = this->channel_->type()->channel_type();
if (channel_type == NULL)
{
- gcc_assert(this->channel_->type()->is_error_type());
+ gcc_assert(this->channel_->type()->is_error());
return error_mark_node;
}
Type* element_type = channel_type->element_type();
return new Receive_expression(channel, location);
}
-// Class Send_expression.
-
-// Traversal.
-
-int
-Send_expression::do_traverse(Traverse* traverse)
-{
- if (Expression::traverse(&this->channel_, traverse) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- return Expression::traverse(&this->val_, traverse);
-}
-
-// Get the type.
-
-Type*
-Send_expression::do_type()
-{
- if (this->is_value_discarded_)
- return Type::make_void_type();
- else
- return Type::lookup_bool_type();
-}
-
-// Set types.
-
-void
-Send_expression::do_determine_type(const Type_context*)
-{
- this->channel_->determine_type_no_context();
-
- Type* type = this->channel_->type();
- Type_context subcontext;
- if (type->channel_type() != NULL)
- subcontext.type = type->channel_type()->element_type();
- this->val_->determine_type(&subcontext);
-}
-
-// Check types.
-
-void
-Send_expression::do_check_types(Gogo*)
-{
- Type* type = this->channel_->type();
- if (type->is_error_type())
- {
- this->set_is_error();
- return;
- }
- Channel_type* channel_type = type->channel_type();
- if (channel_type == NULL)
- {
- error_at(this->location(), "left operand of %<<-%> must be channel");
- this->set_is_error();
- return;
- }
- Type* element_type = channel_type->element_type();
- if (element_type != NULL
- && !Type::are_assignable(element_type, this->val_->type(), NULL))
- {
- this->report_error(_("incompatible types in send"));
- return;
- }
- if (!channel_type->may_send())
- {
- this->report_error(_("invalid send on receive-only channel"));
- return;
- }
-}
-
-// Get a tree for a send expression.
-
-tree
-Send_expression::do_get_tree(Translate_context* context)
-{
- tree channel = this->channel_->get_tree(context);
- tree val = this->val_->get_tree(context);
- if (channel == error_mark_node || val == error_mark_node)
- return error_mark_node;
- Channel_type* channel_type = this->channel_->type()->channel_type();
- val = Expression::convert_for_assignment(context,
- channel_type->element_type(),
- this->val_->type(),
- val,
- this->location());
- return Gogo::send_on_channel(channel, val, this->is_value_discarded_,
- this->for_select_, this->location());
-}
-
-// Make a send expression
-
-Send_expression*
-Expression::make_send(Expression* channel, Expression* val,
- source_location location)
-{
- return new Send_expression(channel, val, location);
-}
-
// An expression which evaluates to a pointer to the type descriptor
// of a type.