summaryrefslogtreecommitdiff
path: root/gcc/go
diff options
context:
space:
mode:
authormrs <mrs@138bc75d-0d04-0410-961f-82ee72b054a4>2014-05-06 14:30:33 +0000
committermrs <mrs@138bc75d-0d04-0410-961f-82ee72b054a4>2014-05-06 14:30:33 +0000
commit6c86f9ee277f12c56e5e0bd13ca228cf5fb6d88a (patch)
treee5e1af94eb1502ba893bd6ce4a11f68877ff62a9 /gcc/go
parentbadff076649bf7f653a97999208b15fa8062b695 (diff)
parent5c3f3470f97a047819f593b60db38cf7a34b8187 (diff)
downloadgcc-6c86f9ee277f12c56e5e0bd13ca228cf5fb6d88a.tar.gz
Merge in trunk.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/wide-int@210111 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/go')
-rw-r--r--gcc/go/ChangeLog18
-rw-r--r--gcc/go/go-c.h3
-rw-r--r--gcc/go/go-gcc.cc46
-rw-r--r--gcc/go/go-lang.c3
-rw-r--r--gcc/go/gofrontend/backend.h19
-rw-r--r--gcc/go/gofrontend/expressions.cc222
-rw-r--r--gcc/go/gofrontend/expressions.h16
-rw-r--r--gcc/go/gofrontend/go.cc7
-rw-r--r--gcc/go/gofrontend/gogo.cc5
-rw-r--r--gcc/go/gofrontend/gogo.h28
-rw-r--r--gcc/go/gofrontend/types.cc135
-rw-r--r--gcc/go/gofrontend/types.h22
12 files changed, 284 insertions, 240 deletions
diff --git a/gcc/go/ChangeLog b/gcc/go/ChangeLog
index a468beed742..b4267ab9873 100644
--- a/gcc/go/ChangeLog
+++ b/gcc/go/ChangeLog
@@ -1,3 +1,21 @@
+2014-05-06 Chris Manghane <cmang@google.com>
+
+ * go-c.h (go_create_gogo): Update declaration to add
+ check_divide_zero and check_divide_overflow parameters.
+ * go-lang.c (go_langhook_init): Pass new arguments to
+ go_create_gogo.
+
+2014-05-05 Chris Manghane <cmang@google.com>
+
+ * go-gcc.cc (Gcc_backend::implicit_variable): Rename from
+ gc_root_variable. Add name and is_constant parameters.
+
+2014-05-05 Chris Manghane <cmang@google.com>
+
+ * go-gcc.cc (Gcc_backend::indirect_expression): Add btype
+ parameter.
+ (Gcc_backend::temporary_variable): Check for erroneous function.
+
2014-04-30 Chris Manghane <cmang@google.com>
* go-backend.c: #include "diagnostics.h".
diff --git a/gcc/go/go-c.h b/gcc/go/go-c.h
index cb10f2b7be7..5f5ac0da9bc 100644
--- a/gcc/go/go-c.h
+++ b/gcc/go/go-c.h
@@ -34,7 +34,8 @@ extern void go_add_search_path (const char*);
extern void go_create_gogo (int int_type_size, int pointer_size,
const char* pkgpath, const char *prefix,
- const char *relative_import_path);
+ const char *relative_import_path,
+ bool check_divide_zero, bool check_divide_overflow);
extern void go_parse_input_files (const char**, unsigned int,
bool only_check_syntax,
diff --git a/gcc/go/go-gcc.cc b/gcc/go/go-gcc.cc
index 45827a08ea2..f4c242f60aa 100644
--- a/gcc/go/go-gcc.cc
+++ b/gcc/go/go-gcc.cc
@@ -229,7 +229,7 @@ class Gcc_backend : public Backend
var_expression(Bvariable* var, Location);
Bexpression*
- indirect_expression(Bexpression* expr, bool known_valid, Location);
+ indirect_expression(Btype*, Bexpression* expr, bool known_valid, Location);
Bexpression*
named_constant_expression(Btype* btype, const std::string& name,
@@ -381,7 +381,7 @@ class Gcc_backend : public Backend
Location, Bstatement**);
Bvariable*
- gc_root_variable(Btype*, Bexpression*);
+ implicit_variable(const std::string&, Btype*, Bexpression*, bool);
Bvariable*
immutable_struct(const std::string&, bool, bool, Btype*, Location);
@@ -1146,14 +1146,26 @@ Gcc_backend::var_expression(Bvariable* var, Location)
// An expression that indirectly references an expression.
Bexpression*
-Gcc_backend::indirect_expression(Bexpression* expr, bool known_valid,
- Location location)
+Gcc_backend::indirect_expression(Btype* btype, Bexpression* expr,
+ bool known_valid, Location location)
{
+ tree expr_tree = expr->get_tree();
+ tree type_tree = btype->get_tree();
+ if (expr_tree == error_mark_node || type_tree == error_mark_node)
+ return this->error_expression();
+
+ // If the type of EXPR is a recursive pointer type, then we
+ // need to insert a cast before indirecting.
+ tree target_type_tree = TREE_TYPE(TREE_TYPE(expr_tree));
+ if (VOID_TYPE_P(target_type_tree))
+ expr_tree = fold_convert_loc(location.gcc_location(),
+ build_pointer_type(type_tree), expr_tree);
+
tree ret = build_fold_indirect_ref_loc(location.gcc_location(),
- expr->get_tree());
+ expr_tree);
if (known_valid)
TREE_THIS_NOTRAP(ret) = 1;
- return tree_to_expr(ret);
+ return this->make_expression(ret);
}
// Return an expression that declares a constant named NAME with the
@@ -2405,17 +2417,18 @@ Gcc_backend::temporary_variable(Bfunction* function, Bblock* bblock,
Location location,
Bstatement** pstatement)
{
+ gcc_assert(function != NULL);
+ tree decl = function->get_tree();
tree type_tree = btype->get_tree();
tree init_tree = binit == NULL ? NULL_TREE : binit->get_tree();
- if (type_tree == error_mark_node || init_tree == error_mark_node)
+ if (type_tree == error_mark_node
+ || init_tree == error_mark_node
+ || decl == error_mark_node)
{
*pstatement = this->error_statement();
return this->error_variable();
}
- gcc_assert(function != NULL);
- tree decl = function->get_tree();
-
tree var;
// We can only use create_tmp_var if the type is not addressable.
if (!TREE_ADDRESSABLE(type_tree))
@@ -2462,10 +2475,12 @@ Gcc_backend::temporary_variable(Bfunction* function, Bblock* bblock,
return new Bvariable(var);
}
-// Make a GC root variable.
+// Create an implicit variable that is compiler-defined. This is used when
+// generating GC root variables and storing the values of a slice initializer.
Bvariable*
-Gcc_backend::gc_root_variable(Btype* type, Bexpression* init)
+Gcc_backend::implicit_variable(const std::string& name, Btype* type,
+ Bexpression* init, bool is_constant)
{
tree type_tree = type->get_tree();
tree init_tree = init->get_tree();
@@ -2473,11 +2488,16 @@ Gcc_backend::gc_root_variable(Btype* type, Bexpression* init)
return this->error_variable();
tree decl = build_decl(BUILTINS_LOCATION, VAR_DECL,
- create_tmp_var_name("gc"), type_tree);
+ get_identifier_from_string(name), type_tree);
DECL_EXTERNAL(decl) = 0;
TREE_PUBLIC(decl) = 0;
TREE_STATIC(decl) = 1;
DECL_ARTIFICIAL(decl) = 1;
+ if (is_constant)
+ {
+ TREE_READONLY(decl) = 1;
+ TREE_CONSTANT(decl) = 1;
+ }
DECL_INITIAL(decl) = init_tree;
rest_of_decl_compilation(decl, 1, 0);
diff --git a/gcc/go/go-lang.c b/gcc/go/go-lang.c
index 3599aa85e54..f6e865e08cf 100644
--- a/gcc/go/go-lang.c
+++ b/gcc/go/go-lang.c
@@ -104,7 +104,8 @@ go_langhook_init (void)
build_common_builtin_nodes (because it calls, indirectly,
go_type_for_size). */
go_create_gogo (INT_TYPE_SIZE, POINTER_SIZE, go_pkgpath, go_prefix,
- go_relative_import_path);
+ go_relative_import_path, go_check_divide_zero,
+ go_check_divide_overflow);
build_common_builtin_nodes ();
diff --git a/gcc/go/gofrontend/backend.h b/gcc/go/gofrontend/backend.h
index 786223fe736..95f494accfc 100644
--- a/gcc/go/gofrontend/backend.h
+++ b/gcc/go/gofrontend/backend.h
@@ -253,9 +253,11 @@ class Backend
// Create an expression that indirects through the pointer expression EXPR
// (i.e., return the expression for *EXPR). KNOWN_VALID is true if the pointer
- // is known to point to a valid memory location.
+ // is known to point to a valid memory location. BTYPE is the expected type
+ // of the indirected EXPR.
virtual Bexpression*
- indirect_expression(Bexpression* expr, bool known_valid, Location) = 0;
+ indirect_expression(Btype* btype, Bexpression* expr, bool known_valid,
+ Location) = 0;
// Return an expression that declares a constant named NAME with the
// constant value VAL in BTYPE.
@@ -534,11 +536,16 @@ class Backend
bool address_is_taken, Location location,
Bstatement** pstatement) = 0;
- // Create a GC root variable. TYPE is the __go_gc_root_list struct described
- // in Gogo::register_gc_vars. INIT is the composite literal consisting of a
- // pointer to the next GC root and the global variables registered.
+ // Create an implicit variable that is compiler-defined. This is used when
+ // generating GC root variables and storing the values of a slice constructor.
+ // NAME is the name of the variable, either gc# for GC roots or C# for slice
+ // initializers. TYPE is the type of the implicit variable with an initial
+ // value INIT. IS_CONSTANT is true if the implicit variable should be treated
+ // like it is immutable. For slice initializers, if the values must be copied
+ // to the heap, the variable IS_CONSTANT.
virtual Bvariable*
- gc_root_variable(Btype* type, Bexpression* init) = 0;
+ implicit_variable(const std::string& name, Btype* type, Bexpression* init,
+ bool is_constant) = 0;
// Create a named immutable initialized data structure. This is
// used for type descriptors, map descriptors, and function
diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc
index a4f959da09d..df3103b0d1d 100644
--- a/gcc/go/gofrontend/expressions.cc
+++ b/gcc/go/gofrontend/expressions.cc
@@ -760,16 +760,24 @@ Var_expression::do_get_tree(Translate_context* context)
context->function());
bool is_in_heap;
Location loc = this->location();
+ Btype* btype;
+ Gogo* gogo = context->gogo();
if (this->variable_->is_variable())
- is_in_heap = this->variable_->var_value()->is_in_heap();
+ {
+ is_in_heap = this->variable_->var_value()->is_in_heap();
+ btype = this->variable_->var_value()->type()->get_backend(gogo);
+ }
else if (this->variable_->is_result_variable())
- is_in_heap = this->variable_->result_var_value()->is_in_heap();
+ {
+ is_in_heap = this->variable_->result_var_value()->is_in_heap();
+ btype = this->variable_->result_var_value()->type()->get_backend(gogo);
+ }
else
go_unreachable();
Bexpression* ret = context->backend()->var_expression(bvar, loc);
if (is_in_heap)
- ret = context->backend()->indirect_expression(ret, true, loc);
+ ret = context->backend()->indirect_expression(btype, ret, true, loc);
return expr_to_tree(ret);
}
@@ -4105,20 +4113,47 @@ Unary_expression::do_get_tree(Translate_context* context)
}
}
- if (this->is_gc_root_)
+ static unsigned int counter;
+ char buf[100];
+ if (this->is_gc_root_ || this->is_slice_init_)
{
- // Build a decl for a GC root variable. GC roots are mutable, so they
- // cannot be represented as an immutable_struct in the backend.
- Bvariable* gc_root = gogo->backend()->gc_root_variable(btype, bexpr);
- bexpr = gogo->backend()->var_expression(gc_root, loc);
+ bool copy_to_heap = false;
+ if (this->is_gc_root_)
+ {
+ // Build a decl for a GC root variable. GC roots are mutable, so
+ // they cannot be represented as an immutable_struct in the
+ // backend.
+ static unsigned int root_counter;
+ snprintf(buf, sizeof buf, "gc%u", root_counter);
+ ++root_counter;
+ }
+ else
+ {
+ // Build a decl for a slice value initializer. An immutable slice
+ // value initializer may have to be copied to the heap if it
+ // contains pointers in a non-constant context.
+ snprintf(buf, sizeof buf, "C%u", counter);
+ ++counter;
+
+ Array_type* at = this->expr_->type()->array_type();
+ go_assert(at != NULL);
+
+ // 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.
+ copy_to_heap = (at->element_type()->has_pointer()
+ && !context->is_const());
+ }
+ Bvariable* implicit =
+ gogo->backend()->implicit_variable(buf, btype, bexpr, copy_to_heap);
+ bexpr = gogo->backend()->var_expression(implicit, loc);
}
else if ((this->expr_->is_composite_literal()
|| this->expr_->string_expression() != NULL)
&& this->expr_->is_immutable())
{
// Build a decl for a constant constructor.
- static unsigned int counter;
- char buf[100];
snprintf(buf, sizeof buf, "C%u", counter);
++counter;
@@ -4168,20 +4203,7 @@ Unary_expression::do_get_tree(Translate_context* context)
}
}
-
- // If the type of EXPR is a recursive pointer type, then we
- // need to insert a cast before indirecting.
- tree expr = expr_to_tree(bexpr);
- tree target_type_tree = TREE_TYPE(TREE_TYPE(expr));
- if (VOID_TYPE_P(target_type_tree))
- {
- tree ind = type_to_tree(pbtype);
- expr = fold_convert_loc(loc.gcc_location(),
- build_pointer_type(ind), expr);
- bexpr = tree_to_expr(expr);
- }
-
- ret = gogo->backend()->indirect_expression(bexpr, false, loc);
+ ret = gogo->backend()->indirect_expression(pbtype, bexpr, false, loc);
}
break;
@@ -5410,7 +5432,7 @@ Binary_expression::lower_compare_to_memcmp(Gogo*, Statement_inserter* inserter)
}
Expression*
-Binary_expression::do_flatten(Gogo*, Named_object*,
+Binary_expression::do_flatten(Gogo* gogo, Named_object*,
Statement_inserter* inserter)
{
Location loc = this->location();
@@ -5440,11 +5462,9 @@ Binary_expression::do_flatten(Gogo*, Named_object*,
left_type->integer_type() != NULL)
|| this->op_ == OPERATOR_MOD);
- // FIXME: go_check_divide_zero and go_check_divide_overflow are globals
- // defined in gcc/go/lang.opt. These should be defined in go_create_gogo
- // and accessed from the Gogo* passed to do_flatten.
if (is_shift_op
- || (is_idiv_op && (go_check_divide_zero || go_check_divide_overflow)))
+ || (is_idiv_op
+ && (gogo->check_divide_by_zero() || gogo->check_divide_overflow())))
{
if (!this->left_->is_variable())
{
@@ -6024,7 +6044,7 @@ Binary_expression::do_get_tree(Translate_context* context)
// Add checks for division by zero and division overflow as needed.
if (is_idiv_op)
{
- if (go_check_divide_zero)
+ if (gogo->check_divide_by_zero())
{
// right == 0
Bexpression* zero_expr =
@@ -6043,7 +6063,7 @@ Binary_expression::do_get_tree(Translate_context* context)
crash_expr, ret, loc);
}
- if (go_check_divide_overflow)
+ if (gogo->check_divide_overflow())
{
// right == -1
// FIXME: It would be nice to say that this test is expected
@@ -10329,7 +10349,10 @@ Array_index_expression::do_get_tree(Translate_context* context)
array_type->get_value_pointer(gogo, this->array_);
Bexpression* ptr = tree_to_expr(valptr->get_tree(context));
ptr = gogo->backend()->pointer_offset_expression(ptr, start, loc);
- ret = gogo->backend()->indirect_expression(ptr, true, loc);
+
+ Type* ele_type = this->array_->type()->array_type()->element_type();
+ Btype* ele_btype = ele_type->get_backend(gogo);
+ ret = gogo->backend()->indirect_expression(ele_btype, ptr, true, loc);
}
return expr_to_tree(ret);
}
@@ -10667,7 +10690,9 @@ String_index_expression::do_get_tree(Translate_context* context)
Bexpression* bstart = tree_to_expr(start->get_tree(context));
Bexpression* ptr = tree_to_expr(bytes->get_tree(context));
ptr = gogo->backend()->pointer_offset_expression(ptr, bstart, loc);
- Bexpression* index = gogo->backend()->indirect_expression(ptr, true, loc);
+ Btype* ubtype = Type::lookup_integer_type("uint8")->get_backend(gogo);
+ Bexpression* index =
+ gogo->backend()->indirect_expression(ubtype, ptr, true, loc);
Btype* byte_btype = bytes->type()->points_to()->get_backend(gogo);
Bexpression* index_error = tree_to_expr(bad_index->get_tree(context));
@@ -12450,6 +12475,7 @@ Slice_construction_expression::do_get_tree(Translate_context* context)
return error_mark_node;
}
+ Location loc = this->location();
Type* element_type = array_type->element_type();
if (this->valtype_ == NULL)
{
@@ -12464,35 +12490,24 @@ Slice_construction_expression::do_get_tree(Translate_context* context)
else
mpz_init_set_ui(lenval, this->indexes()->back() + 1);
}
- Location loc = this->location();
Type* int_type = Type::lookup_integer_type("int");
length = Expression::make_integer(&lenval, int_type, loc);
mpz_clear(lenval);
this->valtype_ = Type::make_array_type(element_type, length);
}
- tree values;
- Gogo* gogo = context->gogo();
- Btype* val_btype = this->valtype_->get_backend(gogo);
+ Expression_list* vals = this->vals();
if (this->vals() == NULL || this->vals()->empty())
{
- // We need to create a unique value.
- Btype* int_btype = Type::lookup_integer_type("int")->get_backend(gogo);
- Bexpression* zero = gogo->backend()->zero_expression(int_btype);
- std::vector<unsigned long> index(1, 0);
- std::vector<Bexpression*> val(1, zero);
- Bexpression* ctor =
- gogo->backend()->array_constructor_expression(val_btype, index, val,
- this->location());
- values = expr_to_tree(ctor);
+ // We need to create a unique value for the empty array literal.
+ vals = new Expression_list;
+ vals->push_back(NULL);
}
- else
- values = expr_to_tree(this->get_constructor(context, val_btype));
-
- if (values == error_mark_node)
- return error_mark_node;
+ Expression* array_val =
+ new Fixed_array_construction_expression(this->valtype_, this->indexes(),
+ vals, loc);
- bool is_constant_initializer = TREE_CONSTANT(values);
+ bool is_constant_initializer = array_val->is_immutable();
// 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
@@ -12503,89 +12518,22 @@ Slice_construction_expression::do_get_tree(Translate_context* context)
|| (element_type->has_pointer()
&& !context->is_const()));
- if (is_constant_initializer)
- {
- tree tmp = build_decl(this->location().gcc_location(), VAR_DECL,
- create_tmp_var_name("C"), TREE_TYPE(values));
- DECL_EXTERNAL(tmp) = 0;
- TREE_PUBLIC(tmp) = 0;
- TREE_STATIC(tmp) = 1;
- DECL_ARTIFICIAL(tmp) = 1;
- if (copy_to_heap)
- {
- // 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;
- }
- DECL_INITIAL(tmp) = values;
- rest_of_decl_compilation(tmp, 1, 0);
- values = tmp;
- }
-
- tree space;
- tree set;
+ Expression* space;
if (!copy_to_heap)
{
- // the initializer will only run once.
- space = build_fold_addr_expr(values);
- set = NULL_TREE;
+ // The initializer will only run once.
+ space = Expression::make_unary(OPERATOR_AND, array_val, loc);
+ space->unary_expression()->set_is_slice_init();
}
else
- {
- Expression* alloc =
- context->gogo()->allocate_memory(this->valtype_, this->location());
- space = save_expr(alloc->get_tree(context));
-
- tree s = fold_convert(build_pointer_type(TREE_TYPE(values)), space);
- tree ref = build_fold_indirect_ref_loc(this->location().gcc_location(),
- s);
- TREE_THIS_NOTRAP(ref) = 1;
- set = build2(MODIFY_EXPR, void_type_node, ref, values);
- }
+ space = Expression::make_heap_expression(array_val, loc);
// Build a constructor for the slice.
- tree type_tree = type_to_tree(this->type()->get_backend(context->gogo()));
- if (type_tree == error_mark_node)
- return error_mark_node;
- go_assert(TREE_CODE(type_tree) == RECORD_TYPE);
-
- vec<constructor_elt, va_gc> *init;
- vec_alloc(init, 3);
-
- constructor_elt empty = {NULL, NULL};
- constructor_elt* elt = init->quick_push(empty);
- tree field = TYPE_FIELDS(type_tree);
- go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__values") == 0);
- elt->index = field;
- elt->value = fold_convert(TREE_TYPE(field), space);
-
- tree length_tree = this->valtype_->array_type()->length()->get_tree(context);
- elt = init->quick_push(empty);
- field = DECL_CHAIN(field);
- go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__count") == 0);
- elt->index = field;
- elt->value = fold_convert(TREE_TYPE(field), length_tree);
-
- elt = init->quick_push(empty);
- field = DECL_CHAIN(field);
- go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)),"__capacity") == 0);
- elt->index = field;
- elt->value = fold_convert(TREE_TYPE(field), length_tree);
-
- tree constructor = build_constructor(type_tree, init);
- if (constructor == error_mark_node)
- return error_mark_node;
- if (!copy_to_heap)
- TREE_CONSTANT(constructor) = 1;
-
- if (set == NULL_TREE)
- return constructor;
- else
- return build2(COMPOUND_EXPR, type_tree, set, constructor);
+ Expression* len = this->valtype_->array_type()->length();
+ Expression* slice_val =
+ Expression::make_slice_value(this->type(), space, len, len, loc);
+ return slice_val->get_tree(context);
}
// Make a slice composite literal. This is used by the type
@@ -13816,7 +13764,9 @@ Heap_expression::do_get_tree(Translate_context* context)
gogo->backend()->temporary_variable(fndecl, context->bblock(), btype,
space, true, loc, &decl);
space = gogo->backend()->var_expression(space_temp, loc);
- Bexpression* ref = gogo->backend()->indirect_expression(space, true, loc);
+ Btype* expr_btype = this->expr_->type()->get_backend(gogo);
+ Bexpression* ref =
+ gogo->backend()->indirect_expression(expr_btype, space, true, loc);
Bexpression* bexpr = tree_to_expr(this->expr_->get_tree(context));
Bstatement* assn = gogo->backend()->assignment_statement(ref, bexpr, loc);
@@ -14095,9 +14045,13 @@ Type_info_expression::do_get_tree(Translate_context* context)
default:
go_unreachable();
}
- tree val_type_tree = type_to_tree(this->type()->get_backend(gogo));
- go_assert(val_type_tree != error_mark_node);
- return build_int_cstu(val_type_tree, val);
+ mpz_t cst;
+ mpz_init_set_ui(cst, val);
+ Btype* int_btype = this->type()->get_backend(gogo);
+ Bexpression* ret =
+ gogo->backend()->integer_constant_expression(int_btype, cst);
+ mpz_clear(cst);
+ return expr_to_tree(ret);
}
// Dump ast representation for a type info expression.
@@ -14796,6 +14750,10 @@ class Struct_field_offset_expression : public Expression
{ }
protected:
+ bool
+ do_is_immutable() const
+ { return true; }
+
Type*
do_type()
{ return Type::lookup_integer_type("uintptr"); }
diff --git a/gcc/go/gofrontend/expressions.h b/gcc/go/gofrontend/expressions.h
index 0936e00bae0..6f03e02a8c6 100644
--- a/gcc/go/gofrontend/expressions.h
+++ b/gcc/go/gofrontend/expressions.h
@@ -1305,7 +1305,7 @@ class Unary_expression : public Expression
Unary_expression(Operator op, Expression* expr, Location location)
: Expression(EXPRESSION_UNARY, location),
op_(op), escapes_(true), create_temp_(false), is_gc_root_(false),
- expr_(expr), issue_nil_check_(false)
+ is_slice_init_(false), expr_(expr), issue_nil_check_(false)
{ }
// Return the operator.
@@ -1344,6 +1344,15 @@ class Unary_expression : public Expression
this->is_gc_root_ = true;
}
+ // Record that this is an address expression of a slice value initializer,
+ // which is mutable if the values are not copied to the heap.
+ void
+ set_is_slice_init()
+ {
+ go_assert(this->op_ == OPERATOR_AND);
+ this->is_slice_init_ = true;
+ }
+
// Apply unary opcode OP to UNC, setting NC. Return true if this
// could be done, false if not. Issue errors for overflow.
static bool
@@ -1427,6 +1436,11 @@ class Unary_expression : public Expression
// special struct composite literal that is mutable when addressed, meaning
// it cannot be represented as an immutable_struct in the backend.
bool is_gc_root_;
+ // True if this is an address expression for a slice value with an immutable
+ // initializer. The initializer for a slice's value pointer has an array
+ // type, meaning it cannot be represented as an immutable_struct in the
+ // backend.
+ bool is_slice_init_;
// The operand.
Expression* expr_;
// Whether or not to issue a nil check for this expression if its address
diff --git a/gcc/go/gofrontend/go.cc b/gcc/go/gofrontend/go.cc
index d2331f3e0ae..222ea90ae01 100644
--- a/gcc/go/gofrontend/go.cc
+++ b/gcc/go/gofrontend/go.cc
@@ -21,7 +21,8 @@ static Gogo* gogo;
GO_EXTERN_C
void
go_create_gogo(int int_type_size, int pointer_size, const char *pkgpath,
- const char *prefix, const char *relative_import_path)
+ const char *prefix, const char *relative_import_path,
+ bool check_divide_by_zero, bool check_divide_overflow)
{
go_assert(::gogo == NULL);
Linemap* linemap = go_get_linemap();
@@ -34,6 +35,10 @@ go_create_gogo(int int_type_size, int pointer_size, const char *pkgpath,
if (relative_import_path != NULL)
::gogo->set_relative_import_path(relative_import_path);
+ if (check_divide_by_zero)
+ ::gogo->set_check_divide_by_zero(check_divide_by_zero);
+ if (check_divide_overflow)
+ ::gogo->set_check_divide_overflow(check_divide_overflow);
}
// Parse the input files.
diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc
index ab54f8491e3..e0ddc2f35ff 100644
--- a/gcc/go/gofrontend/gogo.cc
+++ b/gcc/go/gofrontend/gogo.cc
@@ -5210,7 +5210,10 @@ Function::return_value(Gogo* gogo, Named_object* named_function,
Bvariable* bvar = no->get_backend_variable(gogo, named_function);
Bexpression* val = gogo->backend()->var_expression(bvar, location);
if (no->result_var_value()->is_in_heap())
- val = gogo->backend()->indirect_expression(val, true, location);
+ {
+ Btype* bt = no->result_var_value()->type()->get_backend(gogo);
+ val = gogo->backend()->indirect_expression(bt, val, true, location);
+ }
vals[i] = val;
}
return gogo->backend()->return_statement(this->fndecl_, vals, location);
diff --git a/gcc/go/gofrontend/gogo.h b/gcc/go/gofrontend/gogo.h
index 37cbbdf4411..f125201643f 100644
--- a/gcc/go/gofrontend/gogo.h
+++ b/gcc/go/gofrontend/gogo.h
@@ -215,7 +215,27 @@ class Gogo
// Set the relative import path from a command line option.
void
set_relative_import_path(const std::string& s)
- {this->relative_import_path_ = s; }
+ { this->relative_import_path_ = s; }
+
+ // Return whether to check for division by zero in binary operations.
+ bool
+ check_divide_by_zero() const
+ { return this->check_divide_by_zero_; }
+
+ // Set the option to check division by zero from a command line option.
+ void
+ set_check_divide_by_zero(bool b)
+ { this->check_divide_by_zero_ = b; }
+
+ // Return whether to check for division overflow in binary operations.
+ bool
+ check_divide_overflow() const
+ { return this->check_divide_overflow_; }
+
+ // Set the option to check division overflow from a command line option.
+ void
+ set_check_divide_overflow(bool b)
+ { this->check_divide_overflow_ = b; }
// Return the priority to use for the package we are compiling.
// This is two more than the largest priority of any package we
@@ -716,6 +736,12 @@ class Gogo
// The relative import path, from the -fgo-relative-import-path
// option.
std::string relative_import_path_;
+ // Whether or not to check for division by zero, from the
+ // -fgo-check-divide-zero option.
+ bool check_divide_by_zero_;
+ // Whether or not to check for division overflow, from the
+ // -fgo-check-divide-overflow option.
+ bool check_divide_overflow_;
// A list of types to verify.
std::vector<Type*> verify_types_;
// A list of interface types defined while parsing.
diff --git a/gcc/go/gofrontend/types.cc b/gcc/go/gofrontend/types.cc
index 91a535f01c8..096d87288d4 100644
--- a/gcc/go/gofrontend/types.cc
+++ b/gcc/go/gofrontend/types.cc
@@ -245,7 +245,7 @@ Type::points_to() const
return ptype == NULL ? NULL : ptype->points_to();
}
-// Return whether this is an open array type.
+// Return whether this is a slice type.
bool
Type::is_slice_type() const
@@ -5839,54 +5839,6 @@ Array_type::write_equal_function(Gogo* gogo, Named_type* name)
gogo->add_statement(s);
}
-// Get a tree for the length of a fixed array. The length may be
-// computed using a function call, so we must only evaluate it once.
-
-tree
-Array_type::get_length_tree(Gogo* gogo)
-{
- go_assert(this->length_ != NULL);
- if (this->length_tree_ == NULL_TREE)
- {
- Numeric_constant nc;
- mpz_t val;
- if (this->length_->numeric_constant_value(&nc) && nc.to_int(&val))
- {
- if (mpz_sgn(val) < 0)
- {
- this->length_tree_ = error_mark_node;
- return this->length_tree_;
- }
- Type* t = nc.type();
- if (t == NULL)
- t = Type::lookup_integer_type("int");
- else if (t->is_abstract())
- t = t->make_non_abstract_type();
- Btype* btype = t->get_backend(gogo);
- Bexpression* iexpr =
- gogo->backend()->integer_constant_expression(btype, val);
- this->length_tree_ = expr_to_tree(iexpr);
- mpz_clear(val);
- }
- else
- {
- // Make up a translation context for the array length
- // expression. FIXME: This won't work in general.
- Translate_context context(gogo, NULL, NULL, NULL);
- tree len = this->length_->get_tree(&context);
- if (len != error_mark_node)
- {
- Type* int_type = Type::lookup_integer_type("int");
- tree int_type_tree = type_to_tree(int_type->get_backend(gogo));
- len = convert_to_integer(int_type_tree, len);
- len = save_expr(len);
- }
- this->length_tree_ = len;
- }
- }
- return this->length_tree_;
-}
-
// Get the backend representation of the fields of a slice. This is
// not declared in types.h so that types.h doesn't have to #include
// backend.h.
@@ -5927,7 +5879,7 @@ get_backend_slice_fields(Gogo* gogo, Array_type* type, bool use_placeholder,
// Get a tree for the type of this array. A fixed array is simply
// represented as ARRAY_TYPE with the appropriate index--i.e., it is
-// just like an array in C. An open array is a struct with three
+// just like an array in C. A slice is a struct with three
// fields: a data pointer, the length, and the capacity.
Btype*
@@ -5958,12 +5910,48 @@ Array_type::get_backend_element(Gogo* gogo, bool use_placeholder)
return this->element_type_->get_backend(gogo);
}
-// Return the backend representation of the length.
+// Return the backend representation of the length. The length may be
+// computed using a function call, so we must only evaluate it once.
Bexpression*
Array_type::get_backend_length(Gogo* gogo)
{
- return tree_to_expr(this->get_length_tree(gogo));
+ go_assert(this->length_ != NULL);
+ if (this->blength_ == NULL)
+ {
+ Numeric_constant nc;
+ mpz_t val;
+ if (this->length_->numeric_constant_value(&nc) && nc.to_int(&val))
+ {
+ if (mpz_sgn(val) < 0)
+ {
+ this->blength_ = gogo->backend()->error_expression();
+ return this->blength_;
+ }
+ Type* t = nc.type();
+ if (t == NULL)
+ t = Type::lookup_integer_type("int");
+ else if (t->is_abstract())
+ t = t->make_non_abstract_type();
+ Btype* btype = t->get_backend(gogo);
+ this->blength_ =
+ gogo->backend()->integer_constant_expression(btype, val);
+ mpz_clear(val);
+ }
+ else
+ {
+ // Make up a translation context for the array length
+ // expression. FIXME: This won't work in general.
+ Translate_context context(gogo, NULL, NULL, NULL);
+ this->blength_ = tree_to_expr(this->length_->get_tree(&context));
+
+ Btype* ibtype = Type::lookup_integer_type("int")->get_backend(gogo);
+ this->blength_ =
+ gogo->backend()->convert_expression(ibtype, this->blength_,
+ this->length_->location());
+ }
+ }
+ return this->blength_;
}
// Finish backend representation of the array.
@@ -5997,7 +5985,7 @@ Array_type::get_value_pointer(Gogo*, Expression* array) const
array->location());
}
- // Open array.
+ // Slice.
return Expression::make_slice_info(array,
Expression::SLICE_INFO_VALUE_POINTER,
array->location());
@@ -6012,7 +6000,7 @@ Array_type::get_length(Gogo*, Expression* array) const
if (this->length_ != NULL)
return this->length_;
- // This is an open array. We need to read the length field.
+ // This is a slice. We need to read the length field.
return Expression::make_slice_info(array, Expression::SLICE_INFO_LENGTH,
array->location());
}
@@ -6026,7 +6014,7 @@ Array_type::get_capacity(Gogo*, Expression* array) const
if (this->length_ != NULL)
return this->length_;
- // This is an open array. We need to read the capacity field.
+ // This is a slice. We need to read the capacity field.
return Expression::make_slice_info(array, Expression::SLICE_INFO_CAPACITY,
array->location());
}
@@ -8936,9 +8924,8 @@ Type::finalize_methods(Gogo* gogo, const Type* type, Location location,
Methods** all_methods)
{
*all_methods = NULL;
- Types_seen types_seen;
- Type::add_methods_for_type(type, NULL, 0, false, false, &types_seen,
- all_methods);
+ std::vector<const Named_type*> seen;
+ Type::add_methods_for_type(type, NULL, 0, false, false, &seen, all_methods);
Type::build_stub_methods(gogo, type, *all_methods, location);
}
@@ -8956,7 +8943,7 @@ Type::add_methods_for_type(const Type* type,
unsigned int depth,
bool is_embedded_pointer,
bool needs_stub_method,
- Types_seen* types_seen,
+ std::vector<const Named_type*>* seen,
Methods** methods)
{
// Pointer types may not have methods.
@@ -8966,19 +8953,24 @@ Type::add_methods_for_type(const Type* type,
const Named_type* nt = type->named_type();
if (nt != NULL)
{
- std::pair<Types_seen::iterator, bool> ins = types_seen->insert(nt);
- if (!ins.second)
- return;
- }
+ for (std::vector<const Named_type*>::const_iterator p = seen->begin();
+ p != seen->end();
+ ++p)
+ {
+ if (*p == nt)
+ return;
+ }
- if (nt != NULL)
- Type::add_local_methods_for_type(nt, field_indexes, depth,
- is_embedded_pointer, needs_stub_method,
- methods);
+ seen->push_back(nt);
+
+ Type::add_local_methods_for_type(nt, field_indexes, depth,
+ is_embedded_pointer, needs_stub_method,
+ methods);
+ }
Type::add_embedded_methods_for_type(type, field_indexes, depth,
is_embedded_pointer, needs_stub_method,
- types_seen, methods);
+ seen, methods);
// If we are called with depth > 0, then we are looking at an
// anonymous field of a struct. If such a field has interface type,
@@ -8987,6 +8979,9 @@ Type::add_methods_for_type(const Type* type,
// following the usual rules for an interface type.
if (depth > 0)
Type::add_interface_methods_for_type(type, field_indexes, depth, methods);
+
+ if (nt != NULL)
+ seen->pop_back();
}
// Add the local methods for the named type NT to *METHODS. The
@@ -9032,7 +9027,7 @@ Type::add_embedded_methods_for_type(const Type* type,
unsigned int depth,
bool is_embedded_pointer,
bool needs_stub_method,
- Types_seen* types_seen,
+ std::vector<const Named_type*>* seen,
Methods** methods)
{
// Look for anonymous fields in TYPE. TYPE has fields if it is a
@@ -9076,7 +9071,7 @@ Type::add_embedded_methods_for_type(const Type* type,
(needs_stub_method
|| is_pointer
|| i > 0),
- types_seen,
+ seen,
methods);
}
}
diff --git a/gcc/go/gofrontend/types.h b/gcc/go/gofrontend/types.h
index d2ca1bf27fb..e6ba995429f 100644
--- a/gcc/go/gofrontend/types.h
+++ b/gcc/go/gofrontend/types.h
@@ -1171,14 +1171,11 @@ class Type
static tree
build_receive_return_type(tree type);
- // A hash table we use to avoid infinite recursion.
- typedef Unordered_set_hash(const Named_type*, Type_hash_identical,
- Type_identical) Types_seen;
-
// Add all methods for TYPE to the list of methods for THIS.
static void
add_methods_for_type(const Type* type, const Method::Field_indexes*,
- unsigned int depth, bool, bool, Types_seen*,
+ unsigned int depth, bool, bool,
+ std::vector<const Named_type*>*,
Methods**);
static void
@@ -1189,7 +1186,8 @@ class Type
static void
add_embedded_methods_for_type(const Type* type,
const Method::Field_indexes*,
- unsigned int depth, bool, bool, Types_seen*,
+ unsigned int depth, bool, bool,
+ std::vector<const Named_type*>*,
Methods**);
static void
@@ -2305,7 +2303,7 @@ class Array_type : public Type
public:
Array_type(Type* element_type, Expression* length)
: Type(TYPE_ARRAY),
- element_type_(element_type), length_(length), length_tree_(NULL)
+ element_type_(element_type), length_(length), blength_(NULL)
{ }
// Return the element type.
@@ -2313,7 +2311,7 @@ class Array_type : public Type
element_type() const
{ return this->element_type_; }
- // Return the length. This will return NULL for an open array.
+ // Return the length. This will return NULL for a slice.
Expression*
length() const
{ return this->length_; }
@@ -2407,9 +2405,6 @@ class Array_type : public Type
bool
verify_length();
- tree
- get_length_tree(Gogo*);
-
Expression*
array_type_descriptor(Gogo*, Named_type*);
@@ -2420,8 +2415,9 @@ class Array_type : public Type
Type* element_type_;
// The number of elements. This may be NULL.
Expression* length_;
- // The length as a tree. We only want to compute this once.
- tree length_tree_;
+ // The backend representation of the length.
+ // We only want to compute this once.
+ Bexpression* blength_;
};
// The type of a map.