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.
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.
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);
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);
}
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;
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);
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);
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.
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);
}
Type* type = left->type();
if (type->is_error_type())
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
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.
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_type());
+ return error_mark_node;
+ }
Type* element_type = channel_type->element_type();
tree element_type_tree = element_type->get_tree(context->gogo());