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;
first_field_value = fold_convert_loc(location, const_ptr_type_node,
method_table);
}
+ if (first_field_value == error_mark_node)
+ return error_mark_node;
// Start building a constructor for the value we will return.
tree
Expression::complex_constant_tree(mpfr_t real, mpfr_t imag, tree type)
{
- if (TREE_CODE(type) == COMPLEX_TYPE)
+ if (type == error_mark_node)
+ return error_mark_node;
+ else if (TREE_CODE(type) == INTEGER_TYPE || TREE_CODE(type) == REAL_TYPE)
+ return Expression::float_constant_tree(real, type);
+ else if (TREE_CODE(type) == COMPLEX_TYPE)
{
REAL_VALUE_TYPE r1;
real_from_mpfr(&r1, real, TREE_TYPE(type), GMP_RNDN);
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.
+ gcc_assert(saw_errors());
+ return Type::make_error_type();
+}
+
// Class Var_expression.
// Lower a variable expression. Here we just make sure that the
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
{
source_location location = this->location();
Named_object* no = this->named_object_;
- Named_object* real = no->unknown_value()->real_named_object();
- if (real == NULL)
+ Named_object* real;
+ if (!no->is_unknown())
+ real = no;
+ else
{
- if (this->is_composite_literal_key_)
- return this;
- error_at(location, "reference to undefined name %qs",
- this->named_object_->message_name().c_str());
- return Expression::make_error(location);
+ real = no->unknown_value()->real_named_object();
+ if (real == NULL)
+ {
+ if (this->is_composite_literal_key_)
+ return this;
+ error_at(location, "reference to undefined name %qs",
+ this->named_object_->message_name().c_str());
+ return Expression::make_error(location);
+ }
}
switch (real->classification())
{
|| context->type->complex_type() != NULL))
this->type_ = context->type;
else if (!context->may_be_abstract)
- this->type_ = Type::lookup_float_type("float");
+ this->type_ = Type::lookup_float_type("float64");
}
// Return true if the floating point value VAL fits in the range of
&& context->type->complex_type() != NULL)
this->type_ = context->type;
else if (!context->may_be_abstract)
- this->type_ = Type::lookup_complex_type("complex");
+ this->type_ = Type::lookup_complex_type("complex128");
}
// Return true if the complex value REAL/IMAG fits in the range of the
return new Complex_expression(real, imag, type, location);
}
+// Find a named object in an expression.
+
+class Find_named_object : public Traverse
+{
+ public:
+ Find_named_object(Named_object* no)
+ : Traverse(traverse_expressions),
+ no_(no), found_(false)
+ { }
+
+ // Whether we found the object.
+ bool
+ found() const
+ { return this->found_; }
+
+ protected:
+ int
+ expression(Expression**);
+
+ private:
+ // The object we are looking for.
+ Named_object* no_;
+ // Whether we found it.
+ bool found_;
+};
+
// A reference to a const in an expression.
class Const_expression : public Expression
constant_(constant), type_(NULL), seen_(false)
{ }
- const std::string&
- name() const
- { return this->constant_->name(); }
+ Named_object*
+ named_object()
+ { return this->constant_; }
+
+ // Check that the initializer does not refer to the constant itself.
+ void
+ check_for_init_loop();
protected:
+ int
+ do_traverse(Traverse*);
+
Expression*
do_lower(Gogo*, Named_object*, int);
mutable bool seen_;
};
+// Traversal.
+
+int
+Const_expression::do_traverse(Traverse* traverse)
+{
+ if (this->type_ != NULL)
+ return Type::traverse(this->type_, traverse);
+ return TRAVERSE_CONTINUE;
+}
+
// Lower a constant expression. This is where we convert the
// predeclared constant iota into an integer value.
if (this->type_ != NULL)
return this->type_;
- if (this->seen_)
+ Named_constant* nc = this->constant_->const_value();
+
+ if (this->seen_ || nc->lowering())
{
this->report_error(_("constant refers to itself"));
this->type_ = Type::make_error_type();
this->seen_ = true;
- Named_constant* nc = this->constant_->const_value();
Type* ret = nc->type();
if (ret != NULL)
}
}
+// Check for a loop in which the initializer of a constant refers to
+// the constant itself.
+
+void
+Const_expression::check_for_init_loop()
+{
+ if (this->type_ != NULL && this->type_->is_error())
+ return;
+
+ if (this->seen_)
+ {
+ this->report_error(_("constant refers to itself"));
+ this->type_ = Type::make_error_type();
+ return;
+ }
+
+ Expression* init = this->constant_->const_value()->expr();
+ Find_named_object find_named_object(this->constant_);
+
+ this->seen_ = true;
+ Expression::traverse(&init, &find_named_object);
+ this->seen_ = false;
+
+ if (find_named_object.found())
+ {
+ if (this->type_ == NULL || !this->type_->is_error())
+ {
+ this->report_error(_("constant refers to itself"));
+ this->type_ = Type::make_error_type();
+ }
+ return;
+ }
+}
+
// Check types of a const reference.
void
Const_expression::do_check_types(Gogo*)
{
+ if (this->type_ != NULL && this->type_->is_error())
+ return;
+
+ this->check_for_init_loop();
+
if (this->type_ == NULL || this->type_->is_abstract())
return;
// object is an abstract int or float, we try to get the abstract
// value. Otherwise we may lose something in the conversion.
if (this->type_ != NULL
- && this->constant_->const_value()->type()->is_abstract())
+ && (this->constant_->const_value()->type() == NULL
+ || this->constant_->const_value()->type()->is_abstract()))
{
Expression* expr = this->constant_->const_value()->expr();
mpz_t ival;
return new Const_expression(constant, location);
}
+// Find a named object in an expression.
+
+int
+Find_named_object::expression(Expression** pexpr)
+{
+ switch ((*pexpr)->classification())
+ {
+ case Expression::EXPRESSION_CONST_REFERENCE:
+ {
+ 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;
+ }
+
+ case Expression::EXPRESSION_VAR_REFERENCE:
+ if ((*pexpr)->var_expression()->named_object() == this->no_)
+ break;
+ return TRAVERSE_CONTINUE;
+ case Expression::EXPRESSION_FUNC_REFERENCE:
+ if ((*pexpr)->func_expression()->named_object() == this->no_)
+ break;
+ return TRAVERSE_CONTINUE;
+ default:
+ return TRAVERSE_CONTINUE;
+ }
+ this->found_ = true;
+ return TRAVERSE_EXIT;
+}
+
// The nil value.
class Nil_expression : public Expression
Type* expr_type = this->expr_->type();
std::string reason;
+ if (type->is_error() || expr_type->is_error())
+ {
+ this->set_is_error();
+ return;
+ }
+
if (this->may_convert_function_types_
&& type->function_type() != NULL
&& expr_type->function_type() != NULL)
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;
case OPERATOR_LSHIFT:
{
unsigned long shift = mpz_get_ui(right_val);
- if (mpz_cmp_ui(right_val, shift) != 0)
+ if (mpz_cmp_ui(right_val, shift) != 0 || shift > 0x100000)
{
error_at(location, "shift count overflow");
mpz_set_ui(val, 0);
{
// May be a type error--let it be diagnosed later.
}
- else if (is_comparison)
+ else if (op == OPERATOR_EQEQ || op == OPERATOR_NOTEQ)
{
bool b = Binary_expression::compare_complex(op,
(left_type != NULL
Type*
Binary_expression::do_type()
{
+ if (this->classification() == EXPRESSION_ERROR)
+ return Type::make_error_type();
+
switch (this->op_)
{
case OPERATOR_OROR:
{
Type* left_type = this->left_->type();
Type* right_type = this->right_->type();
- if (!left_type->is_abstract() && left_type->named_type() != NULL)
+ if (left_type->is_error())
+ return left_type;
+ else if (right_type->is_error())
+ return right_type;
+ else if (!Type::are_compatible_for_binop(left_type, right_type))
+ {
+ this->report_error(_("incompatible types in binary expression"));
+ return Type::make_error_type();
+ }
+ else if (!left_type->is_abstract() && left_type->named_type() != NULL)
return left_type;
else if (!right_type->is_abstract() && right_type->named_type() != NULL)
return right_type;
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(&subcontext);
void
Binary_expression::do_check_types(Gogo*)
{
+ if (this->classification() == EXPRESSION_ERROR)
+ return;
+
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);
}
tree eval_saved = NULL_TREE;
if (is_shift_op)
{
- if (!DECL_P(left))
- left = save_expr(left);
- if (!DECL_P(right))
- right = save_expr(right);
// Make sure the values are evaluated.
- eval_saved = fold_build2_loc(this->location(), COMPOUND_EXPR,
- void_type_node, left, right);
+ if (!DECL_P(left) && TREE_SIDE_EFFECTS(left))
+ {
+ left = save_expr(left);
+ eval_saved = left;
+ }
+ if (!DECL_P(right) && TREE_SIDE_EFFECTS(right))
+ {
+ right = save_expr(right);
+ if (eval_saved == NULL_TREE)
+ eval_saved = right;
+ else
+ eval_saved = fold_build2_loc(this->location(), COMPOUND_EXPR,
+ void_type_node, eval_saved, right);
+ }
}
tree ret = fold_build2_loc(this->location(),
ret = fold_build3_loc(this->location(), COND_EXPR, TREE_TYPE(left),
compare, ret, overflow_result);
- ret = fold_build2_loc(this->location(), COMPOUND_EXPR,
- TREE_TYPE(ret), eval_saved, ret);
+ if (eval_saved != NULL_TREE)
+ ret = fold_build2_loc(this->location(), COMPOUND_EXPR,
+ TREE_TYPE(ret), eval_saved, ret);
}
return ret;
else if (left_type->interface_type() != NULL
&& right_type->interface_type() != NULL)
{
- if (left_type->interface_type()->is_empty())
+ if (left_type->interface_type()->is_empty()
+ && right_type->interface_type()->is_empty())
{
- gcc_assert(right_type->interface_type()->is_empty());
static tree empty_interface_compare_decl;
left_tree = Gogo::call_builtin(&empty_interface_compare_decl,
location,
// This can panic if the type is uncomparable.
TREE_NOTHROW(empty_interface_compare_decl) = 0;
}
- else
+ else if (!left_type->interface_type()->is_empty()
+ && !right_type->interface_type()->is_empty())
{
- gcc_assert(!right_type->interface_type()->is_empty());
static tree interface_compare_decl;
left_tree = Gogo::call_builtin(&interface_compare_decl,
location,
// This can panic if the type is uncomparable.
TREE_NOTHROW(interface_compare_decl) = 0;
}
+ else
+ {
+ if (left_type->interface_type()->is_empty())
+ {
+ gcc_assert(op == OPERATOR_EQEQ || op == OPERATOR_NOTEQ);
+ std::swap(left_type, right_type);
+ std::swap(left_tree, right_tree);
+ }
+ gcc_assert(!left_type->interface_type()->is_empty());
+ gcc_assert(right_type->interface_type()->is_empty());
+ static tree interface_empty_compare_decl;
+ left_tree = Gogo::call_builtin(&interface_empty_compare_decl,
+ location,
+ "__go_interface_empty_compare",
+ 2,
+ integer_type_node,
+ TREE_TYPE(left_tree),
+ left_tree,
+ TREE_TYPE(right_tree),
+ right_tree);
+ if (left_tree == error_mark_node)
+ return error_mark_node;
+ // This can panic if the type is uncomparable.
+ TREE_NOTHROW(interface_empty_compare_decl) = 0;
+ }
+
right_tree = build_int_cst_type(integer_type_node, 0);
}
tree
Bound_method_expression::do_get_tree(Translate_context*)
{
- gcc_unreachable();
+ error_at(this->location(), "reference to method other than calling it");
+ return error_mark_node;
}
// Make a method expression.
BUILTIN_APPEND,
BUILTIN_CAP,
BUILTIN_CLOSE,
- BUILTIN_CLOSED,
- BUILTIN_CMPLX,
+ BUILTIN_COMPLEX,
BUILTIN_COPY,
BUILTIN_IMAG,
BUILTIN_LEN,
real_imag_type(Type*);
static Type*
- cmplx_type(Type*);
+ complex_type(Type*);
// A pointer back to the general IR structure. This avoids a global
// variable, or passing it around everywhere.
Gogo* gogo_;
// The builtin function being called.
Builtin_function_code code_;
+ // Used to stop endless loops when the length of an array uses len
+ // or cap of the array itself.
+ mutable bool seen_;
};
Builtin_call_expression::Builtin_call_expression(Gogo* gogo,
bool is_varargs,
source_location location)
: Call_expression(fn, args, is_varargs, location),
- gogo_(gogo), code_(BUILTIN_INVALID)
+ gogo_(gogo), code_(BUILTIN_INVALID), seen_(false)
{
Func_expression* fnexp = this->fn()->func_expression();
gcc_assert(fnexp != NULL);
this->code_ = BUILTIN_CAP;
else if (name == "close")
this->code_ = BUILTIN_CLOSE;
- else if (name == "closed")
- this->code_ = BUILTIN_CLOSED;
- else if (name == "cmplx")
- this->code_ = BUILTIN_CMPLX;
+ else if (name == "complex")
+ this->code_ = BUILTIN_COMPLEX;
else if (name == "copy")
this->code_ = BUILTIN_COPY;
else if (name == "imag")
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();
return NULL;
while (nt->real_type()->named_type() != NULL)
nt = nt->real_type()->named_type();
- if (nt->name() == "complex")
- return Type::lookup_float_type("float");
- else if (nt->name() == "complex64")
+ if (nt->name() == "complex64")
return Type::lookup_float_type("float32");
else if (nt->name() == "complex128")
return Type::lookup_float_type("float64");
return NULL;
}
-// Return the type of the cmplx function, given the type of one of the
+// Return the type of the complex function, given the type of one of the
// argments. Like real_imag_type, we have to map by name.
Type*
-Builtin_call_expression::cmplx_type(Type* arg_type)
+Builtin_call_expression::complex_type(Type* arg_type)
{
if (arg_type == NULL || arg_type->is_abstract())
return NULL;
return NULL;
while (nt->real_type()->named_type() != NULL)
nt = nt->real_type()->named_type();
- if (nt->name() == "float")
- return Type::lookup_complex_type("complex");
- else if (nt->name() == "float32")
+ if (nt->name() == "float32")
return Type::lookup_complex_type("complex64");
else if (nt->name() == "float64")
return Type::lookup_complex_type("complex128");
case BUILTIN_LEN:
case BUILTIN_CAP:
{
+ if (this->seen_)
+ return false;
+
Expression* arg = this->one_arg();
if (arg == NULL)
return false;
if (arg_type->array_type() != NULL
&& arg_type->array_type()->length() != NULL)
- return arg_type->array_type()->length()->is_constant();
+ return true;
if (this->code_ == BUILTIN_LEN && arg_type->is_string_type())
- return arg->is_constant();
+ {
+ this->seen_ = true;
+ bool ret = arg->is_constant();
+ this->seen_ = false;
+ return ret;
+ }
}
break;
return arg->field_reference_expression() != NULL;
}
- case BUILTIN_CMPLX:
+ case BUILTIN_COMPLEX:
{
const Expression_list* args = this->args();
if (args != NULL && args->size() == 2)
if (arg_type->array_type() != NULL
&& arg_type->array_type()->length() != NULL)
{
+ if (this->seen_)
+ return false;
Expression* e = arg_type->array_type()->length();
- if (e->integer_constant_value(iota_is_constant, val, ptype))
+ this->seen_ = true;
+ bool r = e->integer_constant_value(iota_is_constant, val, ptype);
+ this->seen_ = false;
+ if (r)
{
*ptype = Type::lookup_integer_type("int");
return true;
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;
+ if (arg_type->named_type() != NULL)
+ arg_type->named_type()->convert(this->gogo_);
tree arg_type_tree = arg_type->get_tree(this->gogo_);
+ if (arg_type_tree == error_mark_node)
+ return false;
unsigned long val_long;
if (this->code_ == BUILTIN_SIZEOF)
{
Type* st = struct_expr->type();
if (st->struct_type() == NULL)
return false;
+ if (st->named_type() != NULL)
+ st->named_type()->convert(this->gogo_);
tree struct_tree = st->get_tree(this->gogo_);
gcc_assert(TREE_CODE(struct_tree) == RECORD_TYPE);
tree field = TYPE_FIELDS(struct_tree);
Builtin_call_expression::do_complex_constant_value(mpfr_t real, mpfr_t imag,
Type** ptype) const
{
- if (this->code_ == BUILTIN_CMPLX)
+ if (this->code_ == BUILTIN_COMPLEX)
{
const Expression_list* args = this->args();
if (args == NULL || args->size() != 2)
{
mpfr_set(real, r, GMP_RNDN);
mpfr_set(imag, i, GMP_RNDN);
- *ptype = Builtin_call_expression::cmplx_type(rtype);
+ *ptype = Builtin_call_expression::complex_type(rtype);
ret = true;
}
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);
return t;
}
- case BUILTIN_CMPLX:
+ case BUILTIN_COMPLEX:
{
const Expression_list* args = this->args();
if (args == NULL || args->size() != 2)
if (t->is_abstract())
t = t->make_non_abstract_type();
}
- t = Builtin_call_expression::cmplx_type(t);
+ t = Builtin_call_expression::complex_type(t);
if (t == NULL)
t = Type::make_error_type();
return t;
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();
case BUILTIN_REAL:
case BUILTIN_IMAG:
- arg_type = Builtin_call_expression::cmplx_type(context->type);
+ arg_type = Builtin_call_expression::complex_type(context->type);
is_print = false;
break;
- case BUILTIN_CMPLX:
+ case BUILTIN_COMPLEX:
{
- // For the cmplx function the type of one operand can
+ // 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 (args != NULL && args->size() == 2)
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;
case BUILTIN_APPEND:
{
const Expression_list* args = this->args();
- if (args == NULL || args->empty())
+ if (args == NULL || args->size() < 2)
{
this->report_error(_("not enough arguments"));
break;
}
- /* Lowering varargs should have left us with 2 arguments. */
- gcc_assert(args->size() == 2);
+ if (args->size() > 2)
+ {
+ this->report_error(_("too many arguments"));
+ break;
+ }
std::string reason;
if (!Type::are_assignable(args->front()->type(), args->back()->type(),
&reason))
}
break;
- case BUILTIN_CMPLX:
+ case BUILTIN_COMPLEX:
{
const Expression_list* args = this->args();
if (args == NULL || args->size() < 2)
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))
- this->report_error(_("cmplx arguments must have identical types"));
+ this->report_error(_("complex arguments must have identical types"));
else if (args->front()->type()->float_type() == NULL)
- this->report_error(_("cmplx arguments must have "
+ this->report_error(_("complex arguments must have "
"floating-point type"));
}
break;
gcc_assert(args != NULL && args->size() == 1);
Expression* arg = *args->begin();
Type* arg_type = arg->type();
+
+ if (this->seen_)
+ {
+ gcc_assert(saw_errors());
+ return error_mark_node;
+ }
+ this->seen_ = true;
+
tree arg_tree = arg->get_tree(context);
+
+ this->seen_ = false;
+
if (arg_tree == error_mark_node)
return error_mark_node;
if (arg_type->is_string_type())
val_tree = String_type::length_tree(gogo, arg_tree);
else if (arg_type->array_type() != NULL)
- val_tree = arg_type->array_type()->length_tree(gogo, arg_tree);
+ {
+ if (this->seen_)
+ {
+ gcc_assert(saw_errors());
+ return error_mark_node;
+ }
+ this->seen_ = true;
+ val_tree = arg_type->array_type()->length_tree(gogo, arg_tree);
+ this->seen_ = false;
+ }
else if (arg_type->map_type() != NULL)
{
static tree map_len_fndecl;
else
{
if (arg_type->array_type() != NULL)
- val_tree = arg_type->array_type()->capacity_tree(gogo, arg_tree);
+ {
+ if (this->seen_)
+ {
+ gcc_assert(saw_errors());
+ return error_mark_node;
+ }
+ this->seen_ = true;
+ val_tree = arg_type->array_type()->capacity_tree(gogo,
+ arg_tree);
+ this->seen_ = false;
+ }
else if (arg_type->channel_type() != NULL)
{
static tree chan_cap_fndecl;
}
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:
mpz_init(val);
Type* dummy;
bool b = this->integer_constant_value(true, val, &dummy);
- gcc_assert(b);
+ if (!b)
+ {
+ gcc_assert(saw_errors());
+ return error_mark_node;
+ }
tree type = Type::lookup_integer_type("int")->get_tree(gogo);
tree ret = Expression::integer_constant_tree(val, type);
mpz_clear(val);
bytecount, element_size);
bytecount = fold_convert_loc(location, size_type_node, bytecount);
- tree call = build_call_expr_loc(location,
- built_in_decls[BUILT_IN_MEMMOVE],
- 3, arg1_val, arg2_val, bytecount);
+ arg1_val = fold_convert_loc(location, ptr_type_node, arg1_val);
+ arg2_val = fold_convert_loc(location, ptr_type_node, arg2_val);
+
+ static tree copy_fndecl;
+ tree call = Gogo::call_builtin(©_fndecl,
+ location,
+ "__go_copy",
+ 3,
+ void_type_node,
+ ptr_type_node,
+ arg1_val,
+ ptr_type_node,
+ arg2_val,
+ size_type_node,
+ bytecount);
+ if (call == error_mark_node)
+ return error_mark_node;
return fold_build2_loc(location, COMPOUND_EXPR, TREE_TYPE(len),
call, len);
if (arg1_tree == error_mark_node || arg2_tree == error_mark_node)
return error_mark_node;
- tree descriptor_tree = arg1->type()->type_descriptor_pointer(gogo);
+ Array_type* at = arg1->type()->array_type();
+ Type* element_type = at->element_type();
+
+ arg2_tree = Expression::convert_for_assignment(context, at,
+ arg2->type(),
+ arg2_tree,
+ location);
+ if (arg2_tree == error_mark_node)
+ return error_mark_node;
+
+ arg2_tree = save_expr(arg2_tree);
+ tree arg2_val = at->value_pointer_tree(gogo, arg2_tree);
+ tree arg2_len = at->length_tree(gogo, arg2_tree);
+ if (arg2_val == error_mark_node || arg2_len == error_mark_node)
+ return error_mark_node;
+ arg2_val = fold_convert_loc(location, ptr_type_node, arg2_val);
+ arg2_len = fold_convert_loc(location, size_type_node, arg2_len);
+
+ tree element_type_tree = element_type->get_tree(gogo);
+ if (element_type_tree == error_mark_node)
+ return error_mark_node;
+ tree element_size = TYPE_SIZE_UNIT(element_type_tree);
+ element_size = fold_convert_loc(location, size_type_node,
+ element_size);
// We rebuild the decl each time since the slice types may
// change.
return Gogo::call_builtin(&append_fndecl,
location,
"__go_append",
- 3,
+ 4,
TREE_TYPE(arg1_tree),
- TREE_TYPE(descriptor_tree),
- descriptor_tree,
TREE_TYPE(arg1_tree),
arg1_tree,
- TREE_TYPE(arg2_tree),
- arg2_tree);
+ ptr_type_node,
+ arg2_val,
+ size_type_node,
+ arg2_len,
+ size_type_node,
+ element_size);
}
case BUILTIN_REAL:
arg_tree);
}
- case BUILTIN_CMPLX:
+ case BUILTIN_COMPLEX:
{
const Expression_list* args = this->args();
gcc_assert(args != NULL && args->size() == 2);
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. FIXME.
- delete this->args_;
+ // 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;
}
}
this->report_error(_("too many arguments"));
return this;
}
- else if (pa + 1 == old_args->end()
- && this->is_compatible_varargs_argument(function, *pa,
- varargs_type,
- &issued_error))
- new_args->push_back(*pa);
else
{
Type* element_type = varargs_type->array_type()->element_type();
return ret;
}
-// Return true if ARG is a varargs argment which should be passed to
-// the varargs parameter of type PARAM_TYPE without wrapping. ARG
-// will be the last argument passed in the call, and PARAM_TYPE will
-// be the type of the last parameter of the varargs function being
-// called.
-
-bool
-Call_expression::is_compatible_varargs_argument(Named_object* function,
- Expression* arg,
- Type* param_type,
- bool* issued_error)
-{
- *issued_error = false;
-
- Type* var_type = NULL;
-
- // The simple case is passing the varargs parameter of the caller.
- Var_expression* ve = arg->var_expression();
- if (ve != NULL && ve->named_object()->is_variable())
- {
- Variable* var = ve->named_object()->var_value();
- if (var->is_varargs_parameter())
- var_type = var->type();
- }
-
- // The complex case is passing the varargs parameter of some
- // enclosing function. This will look like passing down *c.f where
- // c is the closure variable and f is a field in the closure.
- if (function != NULL
- && function->func_value()->needs_closure()
- && arg->classification() == EXPRESSION_UNARY)
- {
- Unary_expression* ue = static_cast<Unary_expression*>(arg);
- if (ue->op() == OPERATOR_MULT)
- {
- Field_reference_expression* fre =
- ue->operand()->deref()->field_reference_expression();
- if (fre != NULL)
- {
- Var_expression* ve = fre->expr()->deref()->var_expression();
- if (ve != NULL)
- {
- Named_object* no = ve->named_object();
- Function* f = function->func_value();
- if (no == f->closure_var())
- {
- // At this point we know that this indeed a
- // reference to some enclosing variable. Now we
- // need to figure out whether that variable is a
- // varargs parameter.
- Named_object* enclosing =
- f->enclosing_var(fre->field_index());
- Variable* var = enclosing->var_value();
- if (var->is_varargs_parameter())
- var_type = var->type();
- }
- }
- }
- }
- }
-
- if (var_type == NULL)
- return false;
-
- // We only match if the parameter is the same, with an identical
- // type.
- Array_type* var_at = var_type->array_type();
- gcc_assert(var_at != NULL);
- Array_type* param_at = param_type->array_type();
- if (param_at != NULL
- && Type::are_identical(var_at->element_type(),
- param_at->element_type(), true, NULL))
- return true;
- error_at(arg->location(), "... mismatch: passing ...T as ...");
- *issued_error = true;
- return false;
-}
-
// Get the function type. Returns NULL if we don't know the type. If
// this returns NULL, and if_ERROR is true, issues an error.
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;
}
pe != this->args_->end();
++pe, ++pp, ++i)
{
+ gcc_assert(pp != params->end());
tree arg_val = (*pe)->get_tree(context);
args[i] = Expression::convert_for_assignment(context,
pp->type(),
arg_val,
location);
if (args[i] == error_mark_node)
- return error_mark_node;
+ {
+ delete[] args;
+ return error_mark_node;
+ }
}
gcc_assert(pp == params->end());
gcc_assert(i == nargs);
tree rettype = TREE_TYPE(TREE_TYPE(fntype->get_tree(gogo)));
if (rettype == error_mark_node)
- return error_mark_node;
+ {
+ delete[] args;
+ return error_mark_node;
+ }
tree fn;
if (has_closure)
gcc_unreachable();
if (fn == error_mark_node || TREE_TYPE(fn) == error_mark_node)
- return error_mark_node;
+ {
+ delete[] args;
+ return error_mark_node;
+ }
- // This is to support builtin math functions when using 80387 math.
tree fndecl = fn;
if (TREE_CODE(fndecl) == ADDR_EXPR)
fndecl = TREE_OPERAND(fndecl, 0);
+
+ // Add a type cast in case the type of the function is a recursive
+ // type which refers to itself.
+ if (!DECL_P(fndecl) || !DECL_IS_BUILTIN(fndecl))
+ {
+ tree fnt = fntype->get_tree(gogo);
+ if (fnt == error_mark_node)
+ return error_mark_node;
+ fn = fold_convert_loc(location, fnt, fn);
+ }
+
+ // This is to support builtin math functions when using 80387 math.
tree excess_type = NULL_TREE;
if (DECL_P(fndecl)
&& DECL_IS_BUILTIN(fndecl)
// to the correct type.
if (TREE_TYPE(ret) == ptr_type_node)
{
- tree t = this->type()->get_tree(gogo);
+ tree t = this->type()->base()->get_tree(gogo);
ret = fold_convert_loc(location, t, ret);
}
// Call_expression::do_must_eval_in_order when there is an error.
Call_expression* ce = this->call_->call_expression();
if (ce == NULL)
- return Type::make_error_type();
+ {
+ this->set_is_error();
+ return Type::make_error_type();
+ }
Function_type* fntype = ce->get_function_type();
if (fntype == NULL)
- return Type::make_error_type();
+ {
+ this->set_is_error();
+ return Type::make_error_type();
+ }
const Typed_identifier_list* results = fntype->results();
+ if (results == NULL)
+ {
+ this->report_error(_("number of results does not match "
+ "number of values"));
+ return Type::make_error_type();
+ }
Typed_identifier_list::const_iterator pr = results->begin();
for (unsigned int i = 0; i < this->index_; ++i)
{
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.
tree call_tree = this->call_->get_tree(context);
if (call_tree == error_mark_node)
return error_mark_node;
- gcc_assert(TREE_CODE(TREE_TYPE(call_tree)) == RECORD_TYPE);
+ if (TREE_CODE(TREE_TYPE(call_tree)) != RECORD_TYPE)
+ {
+ gcc_assert(saw_errors());
+ return error_mark_node;
+ }
tree field = TYPE_FIELDS(TREE_TYPE(call_tree));
for (unsigned int i = 0; i < this->index_; ++i)
{
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())
+ {
+ 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, location);
else if (type->points_to() != NULL
Array_index_expression::do_determine_type(const Type_context*)
{
this->array_->determine_type_no_context();
- Type_context subcontext(NULL, true);
- this->start_->determine_type(&subcontext);
+ this->start_->determine_type_no_context();
if (this->end_ != NULL)
- this->end_->determine_type(&subcontext);
+ this->end_->determine_type_no_context();
}
// Check types of an array index.
this->report_error(_("slice end must be integer"));
Array_type* array_type = this->array_->type()->array_type();
- gcc_assert(array_type != NULL);
+ if (array_type == NULL)
+ {
+ gcc_assert(this->array_->type()->is_error());
+ return;
+ }
unsigned int int_bits =
Type::lookup_integer_type("int")->integer_type()->bits();
source_location loc = this->location();
Array_type* array_type = this->array_->type()->array_type();
- gcc_assert(array_type != NULL);
+ if (array_type == NULL)
+ {
+ gcc_assert(this->array_->type()->is_error());
+ return error_mark_node;
+ }
tree type_tree = array_type->get_tree(gogo);
if (type_tree == error_mark_node)
if (this->end_ == NULL)
return Type::lookup_integer_type("uint8");
else
- return Type::make_string_type();
+ return this->string_->type();
}
// Determine the type of a string index.
String_index_expression::do_determine_type(const Type_context*)
{
this->string_->determine_type_no_context();
- Type_context subcontext(NULL, true);
- this->start_->determine_type(&subcontext);
+ this->start_->determine_type_no_context();
if (this->end_ != NULL)
- this->end_->determine_type(&subcontext);
+ this->end_->determine_type_no_context();
}
// Check types of a string index.
Map_index_expression::get_map_type() const
{
Map_type* mt = this->map_->type()->deref()->map_type();
- gcc_assert(mt != NULL);
+ if (mt == NULL)
+ gcc_assert(saw_errors());
return mt;
}
Type*
Map_index_expression::do_type()
{
- Type* type = this->get_map_type()->val_type();
+ Map_type* mt = this->get_map_type();
+ if (mt == NULL)
+ return Type::make_error_type();
+ Type* type = mt->val_type();
// If this map index is in a tuple assignment, we actually return a
// pointer to the value type. Tuple_map_assignment_statement is
// responsible for handling this correctly. We need to get the type
Map_index_expression::do_determine_type(const Type_context*)
{
this->map_->determine_type_no_context();
- Type_context subcontext(this->get_map_type()->key_type(), false);
+ 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(&subcontext);
}
Map_index_expression::do_check_types(Gogo*)
{
std::string reason;
- if (!Type::are_assignable(this->get_map_type()->key_type(),
- this->index_->type(), &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"));
Map_index_expression::do_get_tree(Translate_context* context)
{
Map_type* type = this->get_map_type();
+ if (type == NULL)
+ return error_mark_node;
tree valptr = this->get_value_pointer(context, this->is_lvalue_);
if (valptr == error_mark_node)
bool insert)
{
Map_type* type = this->get_map_type();
+ if (type == NULL)
+ return error_mark_node;
tree map_tree = this->map_->get_tree(context);
tree index_tree = this->index_->get_tree(context);
// We need to pass in a pointer to the key, so stuff it into a
// variable.
- tree tmp = create_tmp_var(TREE_TYPE(index_tree), get_name(index_tree));
- DECL_IGNORED_P(tmp) = 0;
- DECL_INITIAL(tmp) = index_tree;
- tree make_tmp = build1(DECL_EXPR, void_type_node, tmp);
- tree tmpref = fold_convert(const_ptr_type_node, build_fold_addr_expr(tmp));
- TREE_ADDRESSABLE(tmp) = 1;
+ tree tmp;
+ tree make_tmp;
+ if (current_function_decl != NULL)
+ {
+ tmp = create_tmp_var(TREE_TYPE(index_tree), get_name(index_tree));
+ DECL_IGNORED_P(tmp) = 0;
+ DECL_INITIAL(tmp) = index_tree;
+ make_tmp = build1(DECL_EXPR, void_type_node, tmp);
+ TREE_ADDRESSABLE(tmp) = 1;
+ }
+ else
+ {
+ tmp = build_decl(this->location(), VAR_DECL, create_tmp_var_name("M"),
+ TREE_TYPE(index_tree));
+ DECL_EXTERNAL(tmp) = 0;
+ TREE_PUBLIC(tmp) = 0;
+ TREE_STATIC(tmp) = 1;
+ DECL_ARTIFICIAL(tmp) = 1;
+ if (!TREE_CONSTANT(index_tree))
+ make_tmp = fold_build2_loc(this->location(), INIT_EXPR, void_type_node,
+ tmp, index_tree);
+ else
+ {
+ TREE_READONLY(tmp) = 1;
+ TREE_CONSTANT(tmp) = 1;
+ DECL_INITIAL(tmp) = index_tree;
+ make_tmp = NULL_TREE;
+ }
+ rest_of_decl_compilation(tmp, 1, 0);
+ }
+ tree tmpref = fold_convert_loc(this->location(), const_ptr_type_node,
+ build_fold_addr_expr_loc(this->location(),
+ tmp));
static tree map_index_fndecl;
tree call = Gogo::call_builtin(&map_index_fndecl,
return error_mark_node;
tree ptr_val_type_tree = build_pointer_type(val_type_tree);
- return build2(COMPOUND_EXPR, ptr_val_type_tree,
- make_tmp,
- fold_convert(ptr_val_type_tree, call));
+ tree ret = fold_convert_loc(this->location(), ptr_val_type_tree, call);
+ if (make_tmp != NULL_TREE)
+ ret = build2(COMPOUND_EXPR, ptr_val_type_tree, make_tmp, ret);
+ return ret;
}
// Make a map index expression.
Type*
Field_reference_expression::do_type()
{
- Struct_type* struct_type = this->expr_->type()->struct_type();
+ Type* type = this->expr_->type();
+ if (type->is_error())
+ return type;
+ Struct_type* struct_type = type->struct_type();
gcc_assert(struct_type != NULL);
return struct_type->field(this->field_index_)->type();
}
void
Field_reference_expression::do_check_types(Gogo*)
{
- Struct_type* struct_type = this->expr_->type()->struct_type();
+ Type* type = this->expr_->type();
+ if (type->is_error())
+ return;
+ Struct_type* struct_type = type->struct_type();
gcc_assert(struct_type != NULL);
gcc_assert(struct_type->field(this->field_index_) != NULL);
}
field = DECL_CHAIN(field);
gcc_assert(field != NULL_TREE);
}
+ if (TREE_TYPE(field) == error_mark_node)
+ return error_mark_node;
return build3(COMPONENT_REF, TREE_TYPE(field), struct_tree, field,
NULL_TREE);
}
gcc_assert(vno != NULL);
Expression* ve = Expression::make_var_reference(vno, location);
Expression* bm = Type::bind_field_or_method(gogo, nt, ve, name, location);
- gcc_assert(bm != NULL && !bm->is_error_expression());
+
+ // Even though we found the method above, if it has an error type we
+ // may see an error here.
+ if (bm->is_error_expression())
+ {
+ gogo->finish_function(location);
+ return bm;
+ }
Expression_list* args;
if (method_parameters == NULL)
Allocation_expression::do_get_tree(Translate_context* context)
{
tree type_tree = this->type_->get_tree(context->gogo());
+ if (type_tree == error_mark_node)
+ return error_mark_node;
tree size_tree = TYPE_SIZE_UNIT(type_tree);
tree space = context->gogo()->allocate_memory(this->type_, size_tree,
this->location());
+ if (space == error_mark_node)
+ return error_mark_node;
return fold_convert(build_pointer_type(type_tree), space);
}
(*pv)->determine_type(&subcontext);
}
}
+ // Extra values are an error we will report elsewhere; we still want
+ // to determine the type to avoid knockon errors.
+ for (; pv != this->vals_->end(); ++pv)
+ (*pv)->determine_type_no_context();
}
// Check types.
tree
Open_array_construction_expression::do_get_tree(Translate_context* context)
{
- Type* element_type = this->type()->array_type()->element_type();
+ Array_type* array_type = this->type()->array_type();
+ if (array_type == NULL)
+ {
+ gcc_assert(this->type()->is_error());
+ return error_mark_node;
+ }
+
+ Type* element_type = array_type->element_type();
tree element_type_tree = element_type->get_tree(context->gogo());
if (element_type_tree == error_mark_node)
return error_mark_node;
return error_mark_node;
bool is_constant_initializer = TREE_CONSTANT(values);
- bool is_in_function = context->function() != NULL;
+
+ // We have to copy the initial values into heap memory if we are in
+ // a function or if the values are not constants. We also have to
+ // copy them if they may contain pointers in a non-constant context,
+ // as otherwise the garbage collector won't see them.
+ bool copy_to_heap = (context->function() != NULL
+ || !is_constant_initializer
+ || (element_type->has_pointer()
+ && !context->is_const()));
if (is_constant_initializer)
{
TREE_PUBLIC(tmp) = 0;
TREE_STATIC(tmp) = 1;
DECL_ARTIFICIAL(tmp) = 1;
- if (is_in_function)
+ if (copy_to_heap)
{
- // If this is not a function, we will only initialize the
- // value once, so we can use this directly rather than
- // copying it. In that case we can't make it read-only,
- // because the program is permitted to change it.
+ // If we are not copying the value to the heap, we will only
+ // initialize the value once, so we can use this directly
+ // rather than copying it. In that case we can't make it
+ // read-only, because the program is permitted to change it.
TREE_READONLY(tmp) = 1;
TREE_CONSTANT(tmp) = 1;
}
tree space;
tree set;
- if (!is_in_function && is_constant_initializer)
+ if (!copy_to_heap)
{
- // Outside of a function, we know the initializer will only run
- // once.
+ // the initializer will only run once.
space = build_fold_addr_expr(values);
set = NULL_TREE;
}
tree constructor = build_constructor(type_tree, init);
if (constructor == error_mark_node)
return error_mark_node;
- if (!is_in_function && is_constant_initializer)
+ if (!copy_to_heap)
TREE_CONSTANT(constructor) = 1;
if (set == NULL_TREE)
Type* key_type = mt->key_type();
tree id = get_identifier("__key");
- tree key_field = build_decl(loc, FIELD_DECL, id, key_type->get_tree(gogo));
+ tree key_type_tree = key_type->get_tree(gogo);
+ if (key_type_tree == error_mark_node)
+ return error_mark_node;
+ tree key_field = build_decl(loc, FIELD_DECL, id, key_type_tree);
DECL_CONTEXT(key_field) = struct_type;
TYPE_FIELDS(struct_type) = key_field;
Type* val_type = mt->val_type();
id = get_identifier("__val");
- tree val_field = build_decl(loc, FIELD_DECL, id, val_type->get_tree(gogo));
+ tree val_type_tree = val_type->get_tree(gogo);
+ if (val_type_tree == error_mark_node)
+ return error_mark_node;
+ tree val_field = build_decl(loc, FIELD_DECL, id, val_type_tree);
DECL_CONTEXT(val_field) = struct_type;
DECL_CHAIN(key_field) = val_field;
tree descriptor = gogo->map_descriptor(mt);
tree type_tree = this->type_->get_tree(gogo);
+ if (type_tree == error_mark_node)
+ return error_mark_node;
static tree construct_map_fndecl;
tree call = Gogo::call_builtin(&construct_map_fndecl,
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;
Receive_expression::do_get_tree(Translate_context* context)
{
Channel_type* channel_type = this->channel_->type()->channel_type();
- gcc_assert(channel_type != NULL);
+ if (channel_type == NULL)
+ {
+ gcc_assert(this->channel_->type()->is_error());
+ return error_mark_node;
+ }
Type* element_type = channel_type->element_type();
tree element_type_tree = element_type->get_tree(context->gogo());
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()
-{
- 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.