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
|| 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
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();
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.
}
}
-// Check types of a const reference.
+// Check for a loop in which the initializer of a constant refers to
+// the constant itself.
void
-Const_expression::do_check_types(Gogo*)
+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_)
+ {
+ 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())
{
- this->report_error(_("constant refers to itself"));
- this->type_ = Type::make_error_type();
+ 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;
switch ((*pexpr)->classification())
{
case Expression::EXPRESSION_CONST_REFERENCE:
- if (static_cast<Const_expression*>(*pexpr)->named_object() == this->no_)
- break;
- return TRAVERSE_CONTINUE;
+ {
+ 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;
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;
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;
}
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);
Expression* arg1 = args->front();
Expression* arg2 = args->back();
- Array_type* at = arg1->type()->array_type();
- Type* element_type = at->element_type();
-
tree arg1_tree = arg1->get_tree(context);
tree arg2_tree = arg2->get_tree(context);
if (arg1_tree == error_mark_node || arg2_tree == error_mark_node)
return error_mark_node;
- Array_type* at2 = arg2->type()->array_type();
+ 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 = at2->value_pointer_tree(gogo, arg2_tree);
- tree arg2_len = at2->length_tree(gogo, 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);
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;
}
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)
{
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.
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;
}
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.
// 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)
(*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.
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;
}
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)
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.