if (lhs_type_tree == error_mark_node)
return error_mark_node;
- if (lhs_type != rhs_type && lhs_type->interface_type() != NULL)
+ if (lhs_type->forwarded() != rhs_type->forwarded()
+ && lhs_type->interface_type() != NULL)
{
if (rhs_type->interface_type() == NULL)
return Expression::convert_type_to_interface(context, lhs_type,
rhs_type, rhs_tree,
false, location);
}
- else if (lhs_type != rhs_type && rhs_type->interface_type() != NULL)
+ else if (lhs_type->forwarded() != rhs_type->forwarded()
+ && rhs_type->interface_type() != NULL)
return Expression::convert_interface_to_type(context, lhs_type, rhs_type,
rhs_tree, location);
else if (lhs_type->is_slice_type() && rhs_type->is_nil_type())
// object type: a list of function pointers for each interface
// method.
Named_type* rhs_named_type = rhs_type->named_type();
+ Struct_type* rhs_struct_type = rhs_type->struct_type();
bool is_pointer = false;
- if (rhs_named_type == NULL)
+ if (rhs_named_type == NULL && rhs_struct_type == NULL)
{
rhs_named_type = rhs_type->deref()->named_type();
+ rhs_struct_type = rhs_type->deref()->struct_type();
is_pointer = true;
}
tree method_table;
- if (rhs_named_type == NULL)
- method_table = null_pointer_node;
- else
+ if (rhs_named_type != NULL)
method_table =
rhs_named_type->interface_method_table(gogo, lhs_interface_type,
is_pointer);
+ else if (rhs_struct_type != NULL)
+ method_table =
+ rhs_struct_type->interface_method_table(gogo, lhs_interface_type,
+ is_pointer);
+ else
+ method_table = null_pointer_node;
first_field_value = fold_convert_loc(location.gcc_location(),
const_ptr_type_node, method_table);
}
&& TREE_CODE(TREE_OPERAND(fnaddr, 0)) == FUNCTION_DECL);
TREE_ADDRESSABLE(TREE_OPERAND(fnaddr, 0)) = 1;
- // For a normal non-nested function call, that is all we have to do.
- if (!this->function_->is_function()
- || this->function_->func_value()->enclosing() == NULL)
- {
- go_assert(this->closure_ == NULL);
- return fnaddr;
- }
+ // If there is no closure, that is all have to do.
+ if (this->closure_ == NULL)
+ return fnaddr;
- // For a nested function call, we have to always allocate a
- // trampoline. If we don't always allocate, then closures will not
- // be reliably distinct.
- Expression* closure = this->closure_;
- tree closure_tree;
- if (closure == NULL)
- closure_tree = null_pointer_node;
- else
- {
- // Get the value of the closure. This will be a pointer to
- // space allocated on the heap.
- closure_tree = closure->get_tree(context);
- if (closure_tree == error_mark_node)
- return error_mark_node;
- go_assert(POINTER_TYPE_P(TREE_TYPE(closure_tree)));
- }
+ go_assert(this->function_->func_value()->enclosing() != NULL);
+
+ // Get the value of the closure. This will be a pointer to space
+ // allocated on the heap.
+ tree closure_tree = this->closure_->get_tree(context);
+ if (closure_tree == error_mark_node)
+ return error_mark_node;
+ go_assert(POINTER_TYPE_P(TREE_TYPE(closure_tree)));
// Now we need to build some code on the heap. This code will load
// the static chain pointer with the closure and then jump to the
return Expression::make_error(this->location());
}
- if (op == OPERATOR_PLUS || op == OPERATOR_MINUS
- || op == OPERATOR_NOT || op == OPERATOR_XOR)
+ if (op == OPERATOR_PLUS || op == OPERATOR_MINUS || op == OPERATOR_XOR)
{
Numeric_constant nc;
if (expr->numeric_constant_value(&nc))
else
go_unreachable();
- case OPERATOR_NOT:
case OPERATOR_XOR:
break;
+ case OPERATOR_NOT:
case OPERATOR_AND:
case OPERATOR_MULT:
return false;
return false;
mpz_t uval;
- unc->get_int(&uval);
+ if (unc->is_rune())
+ unc->get_rune(&uval);
+ else
+ unc->get_int(&uval);
mpz_t val;
mpz_init(val);
break;
case OPERATOR_NOT:
+ if (!type->is_boolean_type())
+ this->report_error(_("expected boolean type"));
+ break;
+
case OPERATOR_XOR:
if (type->integer_type() == NULL
&& !type->is_boolean_type())
if (this->create_temp_
&& !TREE_ADDRESSABLE(TREE_TYPE(expr))
- && !DECL_P(expr)
+ && (TREE_CODE(expr) == CONST_DECL || !DECL_P(expr))
&& TREE_CODE(expr) != INDIRECT_REF
&& TREE_CODE(expr) != COMPONENT_REF)
{
- tree tmp = create_tmp_var(TREE_TYPE(expr), get_name(expr));
- DECL_IGNORED_P(tmp) = 1;
- DECL_INITIAL(tmp) = expr;
- TREE_ADDRESSABLE(tmp) = 1;
- return build2_loc(loc.gcc_location(), COMPOUND_EXPR,
- build_pointer_type(TREE_TYPE(expr)),
- build1_loc(loc.gcc_location(), DECL_EXPR,
- void_type_node, tmp),
- build_fold_addr_expr_loc(loc.gcc_location(), tmp));
+ if (current_function_decl != NULL)
+ {
+ tree tmp = create_tmp_var(TREE_TYPE(expr), get_name(expr));
+ DECL_IGNORED_P(tmp) = 1;
+ DECL_INITIAL(tmp) = expr;
+ TREE_ADDRESSABLE(tmp) = 1;
+ return build2_loc(loc.gcc_location(), COMPOUND_EXPR,
+ build_pointer_type(TREE_TYPE(expr)),
+ build1_loc(loc.gcc_location(), DECL_EXPR,
+ void_type_node, tmp),
+ build_fold_addr_expr_loc(loc.gcc_location(),
+ tmp));
+ }
+ else
+ {
+ tree tmp = build_decl(loc.gcc_location(), VAR_DECL,
+ create_tmp_var_name("A"), TREE_TYPE(expr));
+ DECL_EXTERNAL(tmp) = 0;
+ TREE_PUBLIC(tmp) = 0;
+ TREE_STATIC(tmp) = 1;
+ DECL_ARTIFICIAL(tmp) = 1;
+ TREE_ADDRESSABLE(tmp) = 1;
+ tree make_tmp;
+ if (!TREE_CONSTANT(expr))
+ make_tmp = fold_build2_loc(loc.gcc_location(), INIT_EXPR,
+ void_type_node, tmp, expr);
+ else
+ {
+ TREE_READONLY(tmp) = 1;
+ TREE_CONSTANT(tmp) = 1;
+ DECL_INITIAL(tmp) = expr;
+ make_tmp = NULL_TREE;
+ }
+ rest_of_decl_compilation(tmp, 1, 0);
+ tree addr = build_fold_addr_expr_loc(loc.gcc_location(), tmp);
+ if (make_tmp == NULL_TREE)
+ return addr;
+ return build2_loc(loc.gcc_location(), COMPOUND_EXPR,
+ TREE_TYPE(addr), make_tmp, addr);
+ }
}
return build_fold_addr_expr_loc(loc.gcc_location(), expr);
case OPERATOR_LE:
case OPERATOR_GT:
case OPERATOR_GE:
- // These return boolean values and as such must be handled
- // elsewhere.
- go_unreachable();
+ // These return boolean values, not numeric.
+ return false;
default:
break;
}
&right_nc, location,
&result))
return this;
- return Expression::make_cast(Type::lookup_bool_type(),
+ return Expression::make_cast(Type::make_boolean_type(),
Expression::make_boolean(result,
location),
location);
{
int cmp = left_string.compare(right_string);
bool r = Binary_expression::cmp_to_bool(op, cmp);
- return Expression::make_cast(Type::lookup_bool_type(),
- Expression::make_boolean(r,
- location),
- location);
+ return Expression::make_boolean(r, location);
}
}
}
pf != fields->end();
++pf, ++field_index)
{
+ if (Gogo::is_sink_name(pf->field_name()))
+ continue;
+
if (field_index > 0)
{
if (left_temp == NULL)
bool
Binary_expression::do_numeric_constant_value(Numeric_constant* nc) const
{
- Operator op = this->op_;
-
- if (op == OPERATOR_EQEQ
- || op == OPERATOR_NOTEQ
- || op == OPERATOR_LT
- || op == OPERATOR_LE
- || op == OPERATOR_GT
- || op == OPERATOR_GE)
- return false;
-
Numeric_constant left_nc;
if (!this->left_->numeric_constant_value(&left_nc))
return false;
Numeric_constant right_nc;
if (!this->right_->numeric_constant_value(&right_nc))
return false;
-
- return Binary_expression::eval_constant(op, &left_nc, &right_nc,
+ return Binary_expression::eval_constant(this->op_, &left_nc, &right_nc,
this->location(), nc);
}
switch (this->op_)
{
- case OPERATOR_OROR:
- case OPERATOR_ANDAND:
case OPERATOR_EQEQ:
case OPERATOR_NOTEQ:
case OPERATOR_LT:
case OPERATOR_LE:
case OPERATOR_GT:
case OPERATOR_GE:
- return Type::lookup_bool_type();
+ if (this->type_ == NULL)
+ this->type_ = Type::make_boolean_type();
+ return this->type_;
case OPERATOR_PLUS:
case OPERATOR_MINUS:
case OPERATOR_MOD:
case OPERATOR_AND:
case OPERATOR_BITCLEAR:
+ case OPERATOR_OROR:
+ case OPERATOR_ANDAND:
{
Type* type;
if (!Binary_expression::operation_type(this->op_,
&& (this->left_->type()->integer_type() == NULL
|| (subcontext.type->integer_type() == NULL
&& subcontext.type->float_type() == NULL
- && subcontext.type->complex_type() == NULL)))
+ && subcontext.type->complex_type() == NULL
+ && subcontext.type->interface_type() == NULL)))
this->report_error(("invalid context-determined non-integer type "
"for shift operand"));
}
this->right_->determine_type(&subcontext);
+
+ if (is_comparison)
+ {
+ if (this->type_ != NULL && !this->type_->is_abstract())
+ ;
+ else if (context->type != NULL && context->type->is_boolean_type())
+ this->type_ = context->type;
+ else if (!context->may_be_abstract)
+ this->type_ = Type::lookup_bool_type();
+ }
}
// Report an error if the binary operator OP does not support TYPE.
case OPERATOR_LE:
case OPERATOR_GT:
case OPERATOR_GE:
- return Expression::comparison_tree(context, this->op_,
+ return Expression::comparison_tree(context, this->type_, this->op_,
this->left_->type(), left,
this->right_->type(), right,
this->location());
// Implement a comparison.
tree
-Expression::comparison_tree(Translate_context* context, Operator op,
- Type* left_type, tree left_tree,
+Expression::comparison_tree(Translate_context* context, Type* result_type,
+ Operator op, Type* left_type, tree left_tree,
Type* right_type, tree right_tree,
Location location)
{
make_tmp = NULL_TREE;
arg = right_tree;
}
- else if (TREE_ADDRESSABLE(TREE_TYPE(right_tree)) || DECL_P(right_tree))
+ else if (TREE_ADDRESSABLE(TREE_TYPE(right_tree))
+ || (TREE_CODE(right_tree) != CONST_DECL
+ && DECL_P(right_tree)))
{
make_tmp = NULL_TREE;
arg = build_fold_addr_expr_loc(location.gcc_location(), right_tree);
if (left_tree == error_mark_node || right_tree == error_mark_node)
return error_mark_node;
- tree ret = fold_build2(code, boolean_type_node, left_tree, right_tree);
+ tree result_type_tree;
+ if (result_type == NULL)
+ result_type_tree = boolean_type_node;
+ else
+ result_type_tree = type_to_tree(result_type->get_backend(context->gogo()));
+
+ tree ret = fold_build2(code, result_type_tree, left_tree, right_tree);
if (CAN_HAVE_LOCATION_P(ret))
SET_EXPR_LOCATION(ret, location.gcc_location());
return ret;
this->set_args(new_args);
}
-// A traversal class which looks for a call expression.
-
-class Find_call_expression : public Traverse
-{
- public:
- Find_call_expression()
- : Traverse(traverse_expressions),
- found_(false)
- { }
-
- int
- expression(Expression**);
-
- bool
- found()
- { return this->found_; }
-
- private:
- bool found_;
-};
-
-int
-Find_call_expression::expression(Expression** pexpr)
-{
- if ((*pexpr)->call_expression() != NULL)
- {
- this->found_ = true;
- return TRAVERSE_EXIT;
- }
- return TRAVERSE_CONTINUE;
-}
-
// Lower a builtin call expression. This turns new and make into
// specific expressions. We also convert to a constant if we can.
if (this->is_constant())
{
- // We can only lower len and cap if there are no function calls
- // in the arguments. Otherwise we have to make the call.
- if (this->code_ == BUILTIN_LEN || this->code_ == BUILTIN_CAP)
- {
- Expression* arg = this->one_arg();
- if (arg != NULL && !arg->is_constant())
- {
- Find_call_expression find_call;
- Expression::traverse(&arg, &find_call);
- if (find_call.found())
- return this;
- }
- }
-
Numeric_constant nc;
if (this->numeric_constant_value(&nc))
return nc.expression(loc);
return args->front();
}
-// Return whether this is constant: len of a string, or len or cap of
-// a fixed array, or unsafe.Sizeof, unsafe.Offsetof, unsafe.Alignof.
+// A traversal class which looks for a call or receive expression.
+
+class Find_call_expression : public Traverse
+{
+ public:
+ Find_call_expression()
+ : Traverse(traverse_expressions),
+ found_(false)
+ { }
+
+ int
+ expression(Expression**);
+
+ bool
+ found()
+ { return this->found_; }
+
+ private:
+ bool found_;
+};
+
+int
+Find_call_expression::expression(Expression** pexpr)
+{
+ if ((*pexpr)->call_expression() != NULL
+ || (*pexpr)->receive_expression() != NULL)
+ {
+ this->found_ = true;
+ return TRAVERSE_EXIT;
+ }
+ return TRAVERSE_CONTINUE;
+}
+
+// Return whether this is constant: len of a string constant, or len
+// or cap of an array, or unsafe.Sizeof, unsafe.Offsetof,
+// unsafe.Alignof.
bool
Builtin_call_expression::do_is_constant() const
&& !arg_type->points_to()->is_slice_type())
arg_type = arg_type->points_to();
+ // The len and cap functions are only constant if there are no
+ // function calls or channel operations in the arguments.
+ // Otherwise we have to make the call.
+ if (!arg->is_constant())
+ {
+ Find_call_expression find_call;
+ Expression::traverse(&arg, &find_call);
+ if (find_call.found())
+ return false;
+ }
+
if (arg_type->array_type() != NULL
&& arg_type->array_type()->length() != NULL)
return true;
if (args != NULL && args->size() == 2)
{
Type* t1 = args->front()->type();
- Type* t2 = args->front()->type();
+ Type* t2 = args->back()->type();
if (!t1->is_abstract())
arg_type = t1;
else if (!t2->is_abstract())
if (this->indexes() == NULL)
max_index = this->vals()->size() - 1;
else
- max_index = *std::max_element(this->indexes()->begin(),
- this->indexes()->end());
+ max_index = this->indexes()->back();
tree max_tree = size_int(max_index);
tree constructor_type = build_array_type(element_type_tree,
build_index_type(max_tree));
return ret;
}
+// Used to sort an index/value array.
+
+class Index_value_compare
+{
+ public:
+ bool
+ operator()(const std::pair<unsigned long, Expression*>& a,
+ const std::pair<unsigned long, Expression*>& b)
+ { return a.first < b.first; }
+};
+
// Lower an array composite literal.
Expression*
std::vector<unsigned long>* indexes = new std::vector<unsigned long>;
indexes->reserve(this->vals_->size());
+ bool indexes_out_of_order = false;
Expression_list* vals = new Expression_list();
vals->reserve(this->vals_->size());
unsigned long index = 0;
return Expression::make_error(location);
}
+ if (!indexes->empty() && index < indexes->back())
+ indexes_out_of_order = true;
+
indexes->push_back(index);
}
indexes = NULL;
}
+ if (indexes_out_of_order)
+ {
+ typedef std::vector<std::pair<unsigned long, Expression*> > V;
+
+ V v;
+ v.reserve(indexes->size());
+ std::vector<unsigned long>::const_iterator pi = indexes->begin();
+ for (Expression_list::const_iterator pe = vals->begin();
+ pe != vals->end();
+ ++pe, ++pi)
+ v.push_back(std::make_pair(*pi, *pe));
+
+ std::sort(v.begin(), v.end(), Index_value_compare());
+
+ delete indexes;
+ delete vals;
+ indexes = new std::vector<unsigned long>();
+ indexes->reserve(v.size());
+ vals = new Expression_list();
+ vals->reserve(v.size());
+
+ for (V::const_iterator p = v.begin(); p != v.end(); ++p)
+ {
+ indexes->push_back(p->first);
+ vals->push_back(p->second);
+ }
+ }
+
return this->make_array(type, indexes, vals);
}
size_t size;
if (vals == NULL)
size = 0;
- else if (indexes == NULL)
+ else if (indexes != NULL)
+ size = indexes->back() + 1;
+ else
{
size = vals->size();
Integer_type* it = Type::lookup_integer_type("int")->integer_type();
return Expression::make_error(location);
}
}
- else
- {
- size = *std::max_element(indexes->begin(), indexes->end());
- ++size;
- }
mpz_t vlen;
mpz_init_set_ui(vlen, size);
}
else
{
- unsigned long max = *std::max_element(indexes->begin(),
- indexes->end());
+ unsigned long max = indexes->back();
if (max >= val)
{
error_at(location,
void
Type_guard_expression::do_check_types(Gogo*)
{
- // 6g permits using a type guard with unsafe.pointer; we are
- // compatible.
Type* expr_type = this->expr_->type();
- if (expr_type->is_unsafe_pointer_type())
- {
- if (this->type_->points_to() == NULL
- && (this->type_->integer_type() == NULL
- || (this->type_->forwarded()
- != Type::lookup_integer_type("uintptr"))))
- this->report_error(_("invalid unsafe.Pointer conversion"));
- }
- else if (this->type_->is_unsafe_pointer_type())
- {
- if (expr_type->points_to() == NULL
- && (expr_type->integer_type() == NULL
- || (expr_type->forwarded()
- != Type::lookup_integer_type("uintptr"))))
- this->report_error(_("invalid unsafe.Pointer conversion"));
- }
- else if (expr_type->interface_type() == NULL)
+ if (expr_type->interface_type() == NULL)
{
if (!expr_type->is_error() && !this->type_->is_error())
this->report_error(_("type assertion only valid for interface types"));
tree
Type_guard_expression::do_get_tree(Translate_context* context)
{
- Gogo* gogo = context->gogo();
tree expr_tree = this->expr_->get_tree(context);
if (expr_tree == error_mark_node)
return error_mark_node;
- Type* expr_type = this->expr_->type();
- if ((this->type_->is_unsafe_pointer_type()
- && (expr_type->points_to() != NULL
- || expr_type->integer_type() != NULL))
- || (expr_type->is_unsafe_pointer_type()
- && this->type_->points_to() != NULL))
- return convert_to_pointer(type_to_tree(this->type_->get_backend(gogo)),
- expr_tree);
- else if (expr_type->is_unsafe_pointer_type()
- && this->type_->integer_type() != NULL)
- return convert_to_integer(type_to_tree(this->type_->get_backend(gogo)),
- expr_tree);
- else if (this->type_->interface_type() != NULL)
+ if (this->type_->interface_type() != NULL)
return Expression::convert_interface_to_interface(context, this->type_,
this->expr_->type(),
expr_tree, true,