diff options
author | mrs <mrs@138bc75d-0d04-0410-961f-82ee72b054a4> | 2014-05-06 14:30:33 +0000 |
---|---|---|
committer | mrs <mrs@138bc75d-0d04-0410-961f-82ee72b054a4> | 2014-05-06 14:30:33 +0000 |
commit | 6c86f9ee277f12c56e5e0bd13ca228cf5fb6d88a (patch) | |
tree | e5e1af94eb1502ba893bd6ce4a11f68877ff62a9 /gcc/go | |
parent | badff076649bf7f653a97999208b15fa8062b695 (diff) | |
parent | 5c3f3470f97a047819f593b60db38cf7a34b8187 (diff) | |
download | gcc-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/ChangeLog | 18 | ||||
-rw-r--r-- | gcc/go/go-c.h | 3 | ||||
-rw-r--r-- | gcc/go/go-gcc.cc | 46 | ||||
-rw-r--r-- | gcc/go/go-lang.c | 3 | ||||
-rw-r--r-- | gcc/go/gofrontend/backend.h | 19 | ||||
-rw-r--r-- | gcc/go/gofrontend/expressions.cc | 222 | ||||
-rw-r--r-- | gcc/go/gofrontend/expressions.h | 16 | ||||
-rw-r--r-- | gcc/go/gofrontend/go.cc | 7 | ||||
-rw-r--r-- | gcc/go/gofrontend/gogo.cc | 5 | ||||
-rw-r--r-- | gcc/go/gofrontend/gogo.h | 28 | ||||
-rw-r--r-- | gcc/go/gofrontend/types.cc | 135 | ||||
-rw-r--r-- | gcc/go/gofrontend/types.h | 22 |
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. |