diff options
author | bstarynk <bstarynk@138bc75d-0d04-0410-961f-82ee72b054a4> | 2014-01-04 17:57:29 +0000 |
---|---|---|
committer | bstarynk <bstarynk@138bc75d-0d04-0410-961f-82ee72b054a4> | 2014-01-04 17:57:29 +0000 |
commit | 48ff1d417d4c49525c09b013395e38dda8bd50fe (patch) | |
tree | ffb4ea05f14bc936b5dd3681e19b2aa3cee8c3bf /gcc/go | |
parent | 144409bbbdb293946cea105115e0e329f633d333 (diff) | |
download | gcc-48ff1d417d4c49525c09b013395e38dda8bd50fe.tar.gz |
2014-01-04 Basile Starynkevitch <basile@starynkevitch.net>
{{merge using svnmerge.py with trunk GCC 4.9 svn rev206333 now in
stage 3; very unstable, xtramelt-ana-base don't compile
anymore...}}
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/melt-branch@206336 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/go')
-rw-r--r-- | gcc/go/ChangeLog | 37 | ||||
-rw-r--r-- | gcc/go/Make-lang.in | 5 | ||||
-rw-r--r-- | gcc/go/config-lang.in | 2 | ||||
-rw-r--r-- | gcc/go/gccgo.texi | 2 | ||||
-rw-r--r-- | gcc/go/go-backend.c | 2 | ||||
-rw-r--r-- | gcc/go/go-c.h | 2 | ||||
-rw-r--r-- | gcc/go/go-gcc.cc | 38 | ||||
-rw-r--r-- | gcc/go/go-lang.c | 10 | ||||
-rw-r--r-- | gcc/go/go-system.h | 2 | ||||
-rw-r--r-- | gcc/go/gofrontend/backend.h | 4 | ||||
-rw-r--r-- | gcc/go/gofrontend/expressions.cc | 68 | ||||
-rw-r--r-- | gcc/go/gofrontend/gogo-tree.cc | 24 | ||||
-rw-r--r-- | gcc/go/gofrontend/gogo.cc | 41 | ||||
-rw-r--r-- | gcc/go/gofrontend/gogo.h | 2 | ||||
-rw-r--r-- | gcc/go/gofrontend/parse.cc | 25 | ||||
-rw-r--r-- | gcc/go/gofrontend/types.cc | 154 | ||||
-rw-r--r-- | gcc/go/gofrontend/types.h | 13 | ||||
-rw-r--r-- | gcc/go/gospec.c | 2 | ||||
-rw-r--r-- | gcc/go/lang-specs.h | 2 | ||||
-rw-r--r-- | gcc/go/lang.opt | 2 |
20 files changed, 332 insertions, 105 deletions
diff --git a/gcc/go/ChangeLog b/gcc/go/ChangeLog index a7dafac8e74..5ac09319d5c 100644 --- a/gcc/go/ChangeLog +++ b/gcc/go/ChangeLog @@ -1,3 +1,34 @@ +2014-01-02 Richard Sandiford <rdsandiford@googlemail.com> + + Update copyright years + +2014-01-02 Tobias Burnus <burnus@net-b.de> + + * gccgo.texi: Bump @copying's copyright year. + +2013-12-16 Chris Manghane <cmang@google.com> + + * go-gcc.cc (Gcc_backend::struct_field_expression): New function. + +2013-12-11 Ian Lance Taylor <iant@google.com> + + * go-lang.c (go_langhook_post_options): Disable sibling calls by + default. + +2013-12-10 Ian Lance Taylor <iant@google.com> + + * Make-lang.in (check_go_parallelize): Test go-test.exp r* tests + separately. + +2013-12-05 Ian Lance Taylor <iant@google.com> + + Revert this change; no longer required. + 2013-11-06 Ian Lance Taylor <iant@google.com> + + * go-lang.c (go_langhook_post_options): If + -fisolate-erroneous-paths was turned on by an optimization option, + turn it off. + 2013-11-23 Ian Lance Taylor <iant@google.com> * go-gcc.cc (Gcc_backend::function_type): Add result_struct @@ -720,3 +751,9 @@ 2010-12-02 Ian Lance Taylor <iant@google.com> Go frontend added to gcc repository. + +Copyright (C) 2010-2014 Free Software Foundation, Inc. + +Copying and distribution of this file, with or without modification, +are permitted in any medium without royalty provided the copyright +notice and this notice are preserved. diff --git a/gcc/go/Make-lang.in b/gcc/go/Make-lang.in index e4bceb21c08..abcae66a21f 100644 --- a/gcc/go/Make-lang.in +++ b/gcc/go/Make-lang.in @@ -1,6 +1,6 @@ # Make-lang.in -- Top level -*- makefile -*- fragment for gcc Go frontend. -# Copyright (C) 2009-2013 Free Software Foundation, Inc. +# Copyright (C) 2009-2014 Free Software Foundation, Inc. # This file is part of GCC. @@ -132,9 +132,10 @@ go.srcman: doc/gccgo.1 lang_checks += check-go lang_checks_parallelized += check-go -check_go_parallelize = go-test.exp=*/test/\[0-57-9a-bd-hj-zA-Z\]* \ +check_go_parallelize = go-test.exp=*/test/\[0-57-9a-bd-hj-qs-zA-Z\]* \ go-test.exp=*/test/c* \ go-test.exp=*/test/i* \ + go-test.exp=*/test/r* \ go-test.exp=*/test/6* # Install hooks. diff --git a/gcc/go/config-lang.in b/gcc/go/config-lang.in index fe9bb758f7c..c33e218b45e 100644 --- a/gcc/go/config-lang.in +++ b/gcc/go/config-lang.in @@ -1,6 +1,6 @@ # config-lang.in -- Top level configure fragment for gcc Go frontend. -# Copyright (C) 2009-2013 Free Software Foundation, Inc. +# Copyright (C) 2009-2014 Free Software Foundation, Inc. # This file is part of GCC. diff --git a/gcc/go/gccgo.texi b/gcc/go/gccgo.texi index f6fc3a6b541..d7222d50129 100644 --- a/gcc/go/gccgo.texi +++ b/gcc/go/gccgo.texi @@ -12,7 +12,7 @@ @include gcc-common.texi @c Copyright years for this manual. -@set copyrights-go 2010-2013 +@set copyrights-go 2010-2014 @copying @c man begin COPYRIGHT diff --git a/gcc/go/go-backend.c b/gcc/go/go-backend.c index 31d01221fd1..de33601db52 100644 --- a/gcc/go/go-backend.c +++ b/gcc/go/go-backend.c @@ -1,5 +1,5 @@ /* go-backend.c -- Go frontend interface to gcc backend. - Copyright (C) 2010-2013 Free Software Foundation, Inc. + Copyright (C) 2010-2014 Free Software Foundation, Inc. This file is part of GCC. diff --git a/gcc/go/go-c.h b/gcc/go/go-c.h index 5871d9003e1..cf0fbfb0a3f 100644 --- a/gcc/go/go-c.h +++ b/gcc/go/go-c.h @@ -1,5 +1,5 @@ /* go-c.h -- Header file for go frontend gcc C interface. - Copyright (C) 2009-2013 Free Software Foundation, Inc. + Copyright (C) 2009-2014 Free Software Foundation, Inc. This file is part of GCC. diff --git a/gcc/go/go-gcc.cc b/gcc/go/go-gcc.cc index 939be20c349..ce6e2e1b172 100644 --- a/gcc/go/go-gcc.cc +++ b/gcc/go/go-gcc.cc @@ -1,5 +1,5 @@ // go-gcc.cc -- Go frontend to gcc IR. -// Copyright (C) 2011-2013 Free Software Foundation, Inc. +// Copyright (C) 2011-2014 Free Software Foundation, Inc. // Contributed by Ian Lance Taylor, Google. // This file is part of GCC. @@ -243,6 +243,9 @@ class Gcc_backend : public Backend Bexpression* address_expression(Bexpression*, Location); + Bexpression* + struct_field_expression(Bexpression*, size_t, Location); + // Statements. Bstatement* @@ -998,6 +1001,39 @@ Gcc_backend::address_expression(Bexpression* bexpr, Location location) return this->make_expression(ret); } +// Return an expression for the field at INDEX in BSTRUCT. + +Bexpression* +Gcc_backend::struct_field_expression(Bexpression* bstruct, size_t index, + Location location) +{ + tree struct_tree = bstruct->get_tree(); + if (struct_tree == error_mark_node + || TREE_TYPE(struct_tree) == error_mark_node) + return this->error_expression(); + gcc_assert(TREE_CODE(TREE_TYPE(struct_tree)) == RECORD_TYPE); + tree field = TYPE_FIELDS(TREE_TYPE(struct_tree)); + if (field == NULL_TREE) + { + // This can happen for a type which refers to itself indirectly + // and then turns out to be erroneous. + return this->error_expression(); + } + for (unsigned int i = index; i > 0; --i) + { + field = DECL_CHAIN(field); + gcc_assert(field != NULL_TREE); + } + if (TREE_TYPE(field) == error_mark_node) + return this->error_expression(); + tree ret = fold_build3_loc(location.gcc_location(), COMPONENT_REF, + TREE_TYPE(field), struct_tree, field, + NULL_TREE); + if (TREE_CONSTANT(struct_tree)) + TREE_CONSTANT(ret) = 1; + return tree_to_expr(ret); +} + // An expression as a statement. Bstatement* diff --git a/gcc/go/go-lang.c b/gcc/go/go-lang.c index 580b1b802dc..c0f2f1f3884 100644 --- a/gcc/go/go-lang.c +++ b/gcc/go/go-lang.c @@ -1,5 +1,5 @@ /* go-lang.c -- Go frontend gcc interface. - Copyright (C) 2009-2013 Free Software Foundation, Inc. + Copyright (C) 2009-2014 Free Software Foundation, Inc. This file is part of GCC. @@ -270,11 +270,9 @@ go_langhook_post_options (const char **pfilename ATTRIBUTE_UNUSED) if (flag_excess_precision_cmdline == EXCESS_PRECISION_DEFAULT) flag_excess_precision_cmdline = EXCESS_PRECISION_STANDARD; - /* The isolate_erroneous_paths optimization can change a nil - dereference from a panic to a trap, so we have to disable it for - Go, even though it is normally enabled by -O2. */ - if (!global_options_set.x_flag_isolate_erroneous_paths) - global_options.x_flag_isolate_erroneous_paths = 0; + /* Tail call optimizations can confuse uses of runtime.Callers. */ + if (!global_options_set.x_flag_optimize_sibling_calls) + global_options.x_flag_optimize_sibling_calls = 0; /* Returning false means that the backend should be used. */ return false; diff --git a/gcc/go/go-system.h b/gcc/go/go-system.h index cc924f1b1d6..5a3e81b216d 100644 --- a/gcc/go/go-system.h +++ b/gcc/go/go-system.h @@ -1,5 +1,5 @@ // go-system.h -- Go frontend inclusion of gcc header files -*- C++ -*- -// Copyright (C) 2009-2013 Free Software Foundation, Inc. +// Copyright (C) 2009-2014 Free Software Foundation, Inc. // This file is part of GCC. diff --git a/gcc/go/gofrontend/backend.h b/gcc/go/gofrontend/backend.h index 8344da40120..55805941da6 100644 --- a/gcc/go/gofrontend/backend.h +++ b/gcc/go/gofrontend/backend.h @@ -280,6 +280,10 @@ class Backend virtual Bexpression* address_expression(Bexpression*, Location) = 0; + // Return an expression for the field at INDEX in BSTRUCT. + virtual Bexpression* + struct_field_expression(Bexpression* bstruct, size_t index, Location) = 0; + // Statements. // Create an error statement. This is used for cases which should diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc index 4f9368ed255..2f1c026c983 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -4305,8 +4305,9 @@ Unary_expression::do_get_tree(Translate_context* context) expr, fold_convert(TREE_TYPE(expr), null_pointer_node)); - tree crash = gogo->runtime_error(RUNTIME_ERROR_NIL_DEREFERENCE, - loc); + Expression* crash_expr = + gogo->runtime_error(RUNTIME_ERROR_NIL_DEREFERENCE, loc); + tree crash = crash_expr->get_tree(context); expr = fold_build2_loc(loc.gcc_location(), COMPOUND_EXPR, TREE_TYPE(expr), build3(COND_EXPR, void_type_node, @@ -6183,9 +6184,9 @@ Binary_expression::do_get_tree(Translate_context* context) // __go_runtime_error(RUNTIME_ERROR_DIVISION_BY_ZERO), 0 int errcode = RUNTIME_ERROR_DIVISION_BY_ZERO; + Expression* crash = gogo->runtime_error(errcode, this->location()); tree panic = fold_build2_loc(gccloc, COMPOUND_EXPR, TREE_TYPE(ret), - gogo->runtime_error(errcode, - this->location()), + crash->get_tree(context), fold_convert_loc(gccloc, TREE_TYPE(ret), integer_zero_node)); @@ -6975,8 +6976,9 @@ Bound_method_expression::do_get_tree(Translate_context* context) if (nil_check != NULL) { tree nil_check_tree = nil_check->get_tree(context); - tree crash = + Expression* crash_expr = context->gogo()->runtime_error(RUNTIME_ERROR_NIL_DEREFERENCE, loc); + tree crash = crash_expr->get_tree(context); if (ret_tree == error_mark_node || nil_check_tree == error_mark_node || crash == error_mark_node) @@ -7310,7 +7312,11 @@ Builtin_call_expression::do_lower(Gogo* gogo, Named_object* function, Type* slice_type = args->front()->type(); if (!slice_type->is_slice_type()) { - error_at(args->front()->location(), "argument 1 must be a slice"); + if (slice_type->is_nil_type()) + error_at(args->front()->location(), "use of untyped nil"); + else + error_at(args->front()->location(), + "argument 1 must be a slice"); this->set_is_error(); return this; } @@ -8008,7 +8014,10 @@ Builtin_call_expression::do_type() const Expression_list* args = this->args(); if (args == NULL || args->empty()) return Type::make_error_type(); - return args->front()->type(); + Type *ret = args->front()->type(); + if (!ret->is_slice_type()) + return Type::make_error_type(); + return ret; } case BUILTIN_REAL: @@ -10252,6 +10261,14 @@ Index_expression::do_lower(Gogo*, Named_object*, Statement_inserter*, int) { Expression* deref = Expression::make_unary(OPERATOR_MULT, left, location); + + // For an ordinary index into the array, the pointer will be + // dereferenced. For a slice it will not--the resulting slice + // will simply reuse the pointer, which is incorrect if that + // pointer is nil. + if (end != NULL || cap != NULL) + deref->issue_nil_check(); + return Expression::make_array_index(deref, start, end, cap, location); } else if (type->is_string_type()) @@ -10700,7 +10717,7 @@ Array_index_expression::do_get_tree(Translate_context* context) : (this->end_ == NULL ? RUNTIME_ERROR_SLICE_INDEX_OUT_OF_BOUNDS : RUNTIME_ERROR_SLICE_SLICE_OUT_OF_BOUNDS)); - tree crash = gogo->runtime_error(code, loc); + tree crash = gogo->runtime_error(code, loc)->get_tree(context); if (this->end_ == NULL) { @@ -11074,7 +11091,7 @@ String_index_expression::do_get_tree(Translate_context* context) int code = (this->end_ == NULL ? RUNTIME_ERROR_STRING_INDEX_OUT_OF_BOUNDS : RUNTIME_ERROR_STRING_SLICE_OUT_OF_BOUNDS); - tree crash = context->gogo()->runtime_error(code, loc); + tree crash = context->gogo()->runtime_error(code, loc)->get_tree(context); if (this->end_ == NULL) { @@ -11524,28 +11541,12 @@ Field_reference_expression::do_check_types(Gogo*) tree Field_reference_expression::do_get_tree(Translate_context* context) { - tree struct_tree = this->expr_->get_tree(context); - if (struct_tree == error_mark_node - || TREE_TYPE(struct_tree) == error_mark_node) - return error_mark_node; - go_assert(TREE_CODE(TREE_TYPE(struct_tree)) == RECORD_TYPE); - tree field = TYPE_FIELDS(TREE_TYPE(struct_tree)); - if (field == NULL_TREE) - { - // This can happen for a type which refers to itself indirectly - // and then turns out to be erroneous. - go_assert(saw_errors()); - return error_mark_node; - } - for (unsigned int i = this->field_index_; i > 0; --i) - { - field = DECL_CHAIN(field); - go_assert(field != NULL_TREE); - } - if (TREE_TYPE(field) == error_mark_node) - return error_mark_node; - return build3(COMPONENT_REF, TREE_TYPE(field), struct_tree, field, - NULL_TREE); + Bexpression* bstruct = tree_to_expr(this->expr_->get_tree(context)); + Bexpression* ret = + context->gogo()->backend()->struct_field_expression(bstruct, + this->field_index_, + this->location()); + return expr_to_tree(ret); } // Dump ast representation for a field reference expression. @@ -11880,8 +11881,9 @@ Interface_field_reference_expression::do_get_tree(Translate_context* context) this->expr_, Expression::make_nil(loc), loc); - tree crash = context->gogo()->runtime_error(RUNTIME_ERROR_NIL_DEREFERENCE, - loc); + Expression* crash_expr = + context->gogo()->runtime_error(RUNTIME_ERROR_NIL_DEREFERENCE, loc); + tree crash = crash_expr->get_tree(context); if (closure_tree == error_mark_node || nil_check_tree == error_mark_node || crash == error_mark_node) diff --git a/gcc/go/gofrontend/gogo-tree.cc b/gcc/go/gofrontend/gogo-tree.cc index fcceffb2977..b04e660a92d 100644 --- a/gcc/go/gofrontend/gogo-tree.cc +++ b/gcc/go/gofrontend/gogo-tree.cc @@ -2252,30 +2252,6 @@ Gogo::call_builtin(tree* pdecl, Location location, const char* name, return ret; } -// Build a call to the runtime error function. - -tree -Gogo::runtime_error(int code, Location location) -{ - Type* int32_type = Type::lookup_integer_type("int32"); - tree int32_type_tree = type_to_tree(int32_type->get_backend(this)); - - static tree runtime_error_fndecl; - tree ret = Gogo::call_builtin(&runtime_error_fndecl, - location, - "__go_runtime_error", - 1, - void_type_node, - int32_type_tree, - build_int_cst(int32_type_tree, code)); - if (ret == error_mark_node) - return error_mark_node; - // The runtime error function panics and does not return. - TREE_NOTHROW(runtime_error_fndecl) = 0; - TREE_THIS_VOLATILE(runtime_error_fndecl) = 1; - return ret; -} - // Return a tree for receiving a value of type TYPE_TREE on CHANNEL. // TYPE_DESCRIPTOR_TREE is the channel's type descriptor. This does a // blocking receive and returns the value read from the channel. diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc index eebb75377fa..e46bf9c4193 100644 --- a/gcc/go/gofrontend/gogo.cc +++ b/gcc/go/gofrontend/gogo.cc @@ -440,6 +440,9 @@ Gogo::import_package(const std::string& filename, return; } + if (local_name == "init") + error_at(location, "cannot import package as init"); + if (filename == "unsafe") { this->import_unsafe(local_name, is_local_name_exported, location); @@ -2822,7 +2825,10 @@ Build_recover_thunks::function(Named_object* orig_no) if (orig_fntype->is_varargs()) new_fntype->set_is_varargs(); - std::string name = orig_no->name() + "$recover"; + std::string name = orig_no->name(); + if (orig_fntype->is_method()) + name += "$" + orig_fntype->receiver()->type()->mangled_name(gogo); + name += "$recover"; Named_object *new_no = gogo->start_function(name, new_fntype, false, location); Function *new_func = new_no->func_value(); @@ -2916,7 +2922,25 @@ Build_recover_thunks::function(Named_object* orig_no) && !orig_rec_no->var_value()->is_receiver()); orig_rec_no->var_value()->set_is_receiver(); - const std::string& new_receiver_name(orig_fntype->receiver()->name()); + std::string new_receiver_name(orig_fntype->receiver()->name()); + if (new_receiver_name.empty()) + { + // Find the receiver. It was named "r.NNN" in + // Gogo::start_function. + for (Bindings::const_definitions_iterator p = + new_bindings->begin_definitions(); + p != new_bindings->end_definitions(); + ++p) + { + const std::string& pname((*p)->name()); + if (pname[0] == 'r' && pname[1] == '.') + { + new_receiver_name = pname; + break; + } + } + go_assert(!new_receiver_name.empty()); + } Named_object* new_rec_no = new_bindings->lookup_local(new_receiver_name); if (new_rec_no == NULL) go_assert(saw_errors()); @@ -3036,6 +3060,19 @@ Gogo::build_recover_thunks() this->traverse(&build_recover_thunks); } +// Build a call to the runtime error function. + +Expression* +Gogo::runtime_error(int code, Location location) +{ + Type* int32_type = Type::lookup_integer_type("int32"); + mpz_t val; + mpz_init_set_ui(val, code); + Expression* code_expr = Expression::make_integer(&val, int32_type, location); + mpz_clear(val); + return Runtime::make_call(Runtime::RUNTIME_ERROR, location, 1, code_expr); +} + // Look for named types to see whether we need to create an interface // method table. diff --git a/gcc/go/gofrontend/gogo.h b/gcc/go/gofrontend/gogo.h index 31b258d62d6..a9a56815c17 100644 --- a/gcc/go/gofrontend/gogo.h +++ b/gcc/go/gofrontend/gogo.h @@ -576,7 +576,7 @@ class Gogo tree rettype, ...); // Build a call to the runtime error function. - tree + Expression* runtime_error(int code, Location); // Build a builtin struct with a list of fields. diff --git a/gcc/go/gofrontend/parse.cc b/gcc/go/gofrontend/parse.cc index 6e56f835699..7614e6fc795 100644 --- a/gcc/go/gofrontend/parse.cc +++ b/gcc/go/gofrontend/parse.cc @@ -4287,6 +4287,16 @@ Parse::if_stat() cond = this->expression(PRECEDENCE_NORMAL, false, false, NULL, NULL); } + // Check for the easy error of a newline before starting the block. + if (this->peek_token()->is_op(OPERATOR_SEMICOLON)) + { + Location semi_loc = this->location(); + if (this->advance_token()->is_op(OPERATOR_LCURLY)) + error_at(semi_loc, "missing %<{%> after if clause"); + // Otherwise we will get an error when we call this->block + // below. + } + this->gogo_->start_block(this->location()); Location end_loc = this->block(); Block* then_block = this->gogo_->finish_block(end_loc); @@ -4431,7 +4441,7 @@ Parse::switch_stat(Label* label) Location token_loc = this->location(); if (this->peek_token()->is_op(OPERATOR_SEMICOLON) && this->advance_token()->is_op(OPERATOR_LCURLY)) - error_at(token_loc, "unexpected semicolon or newline before %<{%>"); + error_at(token_loc, "missing %<{%> after switch clause"); else if (this->peek_token()->is_op(OPERATOR_COLONEQ)) { error_at(token_loc, "invalid variable name"); @@ -5158,6 +5168,16 @@ Parse::for_stat(Label* label) } } + // Check for the easy error of a newline before starting the block. + if (this->peek_token()->is_op(OPERATOR_SEMICOLON)) + { + Location semi_loc = this->location(); + if (this->advance_token()->is_op(OPERATOR_LCURLY)) + error_at(semi_loc, "missing %<{%> after for clause"); + // Otherwise we will get an error when we call this->block + // below. + } + // Build the For_statement and note that it is the current target // for break and continue statements. @@ -5224,8 +5244,7 @@ Parse::for_clause(Expression** cond, Block** post) *cond = NULL; else if (this->peek_token()->is_op(OPERATOR_LCURLY)) { - error_at(this->location(), - "unexpected semicolon or newline before %<{%>"); + error_at(this->location(), "missing %<{%> after for clause"); *cond = NULL; *post = NULL; return; diff --git a/gcc/go/gofrontend/types.cc b/gcc/go/gofrontend/types.cc index 28a5b3201a2..d079565d18b 100644 --- a/gcc/go/gofrontend/types.cc +++ b/gcc/go/gofrontend/types.cc @@ -575,9 +575,6 @@ Type::are_compatible_for_comparison(bool is_equality_op, const Type *t1, p != fields->end(); ++p) { - if (Gogo::is_sink_name(p->field_name())) - continue; - if (!p->type()->is_comparable()) { if (reason != NULL) @@ -1833,7 +1830,9 @@ Type::write_specific_type_functions(Gogo* gogo, Named_type* name, bloc); gogo->start_block(bloc); - if (this->struct_type() != NULL) + if (name != NULL && name->real_type()->named_type() != NULL) + this->write_named_hash(gogo, name, hash_fntype, equal_fntype); + else if (this->struct_type() != NULL) this->struct_type()->write_hash_function(gogo, name, hash_fntype, equal_fntype); else if (this->array_type() != NULL) @@ -1851,7 +1850,9 @@ Type::write_specific_type_functions(Gogo* gogo, Named_type* name, false, bloc); gogo->start_block(bloc); - if (this->struct_type() != NULL) + if (name != NULL && name->real_type()->named_type() != NULL) + this->write_named_equal(gogo, name); + else if (this->struct_type() != NULL) this->struct_type()->write_equal_function(gogo, name); else if (this->array_type() != NULL) this->array_type()->write_equal_function(gogo, name); @@ -1864,6 +1865,100 @@ Type::write_specific_type_functions(Gogo* gogo, Named_type* name, gogo->finish_function(bloc); } +// Write a hash function that simply calls the hash function for a +// named type. This is used when one named type is defined as +// another. This ensures that this case works when the other named +// type is defined in another package and relies on calling hash +// functions defined only in that package. + +void +Type::write_named_hash(Gogo* gogo, Named_type* name, + Function_type* hash_fntype, Function_type* equal_fntype) +{ + Location bloc = Linemap::predeclared_location(); + + Named_type* base_type = name->real_type()->named_type(); + go_assert(base_type != NULL); + + // The pointer to the type we are going to hash. This is an + // unsafe.Pointer. + Named_object* key_arg = gogo->lookup("key", NULL); + go_assert(key_arg != NULL); + + // The size of the type we are going to hash. + Named_object* keysz_arg = gogo->lookup("key_size", NULL); + go_assert(keysz_arg != NULL); + + Named_object* hash_fn; + Named_object* equal_fn; + name->real_type()->type_functions(gogo, base_type, hash_fntype, equal_fntype, + &hash_fn, &equal_fn); + + // Call the hash function for the base type. + Expression* key_ref = Expression::make_var_reference(key_arg, bloc); + Expression* keysz_ref = Expression::make_var_reference(keysz_arg, bloc); + Expression_list* args = new Expression_list(); + args->push_back(key_ref); + args->push_back(keysz_ref); + Expression* func = Expression::make_func_reference(hash_fn, NULL, bloc); + Expression* call = Expression::make_call(func, args, false, bloc); + + // Return the hash of the base type. + Expression_list* vals = new Expression_list(); + vals->push_back(call); + Statement* s = Statement::make_return_statement(vals, bloc); + gogo->add_statement(s); +} + +// Write an equality function that simply calls the equality function +// for a named type. This is used when one named type is defined as +// another. This ensures that this case works when the other named +// type is defined in another package and relies on calling equality +// functions defined only in that package. + +void +Type::write_named_equal(Gogo* gogo, Named_type* name) +{ + Location bloc = Linemap::predeclared_location(); + + // The pointers to the types we are going to compare. These have + // type unsafe.Pointer. + Named_object* key1_arg = gogo->lookup("key1", NULL); + Named_object* key2_arg = gogo->lookup("key2", NULL); + go_assert(key1_arg != NULL && key2_arg != NULL); + + Named_type* base_type = name->real_type()->named_type(); + go_assert(base_type != NULL); + + // Build temporaries with the base type. + Type* pt = Type::make_pointer_type(base_type); + + Expression* ref = Expression::make_var_reference(key1_arg, bloc); + ref = Expression::make_cast(pt, ref, bloc); + Temporary_statement* p1 = Statement::make_temporary(pt, ref, bloc); + gogo->add_statement(p1); + + ref = Expression::make_var_reference(key2_arg, bloc); + ref = Expression::make_cast(pt, ref, bloc); + Temporary_statement* p2 = Statement::make_temporary(pt, ref, bloc); + gogo->add_statement(p2); + + // Compare the values for equality. + Expression* t1 = Expression::make_temporary_reference(p1, bloc); + t1 = Expression::make_unary(OPERATOR_MULT, t1, bloc); + + Expression* t2 = Expression::make_temporary_reference(p2, bloc); + t2 = Expression::make_unary(OPERATOR_MULT, t2, bloc); + + Expression* cond = Expression::make_binary(OPERATOR_EQEQ, t1, t2, bloc); + + // Return the equality comparison. + Expression_list* vals = new Expression_list(); + vals->push_back(cond); + Statement* s = Statement::make_return_statement(vals, bloc); + gogo->add_statement(s); +} + // Return a composite literal for the type descriptor for a plain type // of kind RUNTIME_TYPE_KIND named NAME. @@ -2163,26 +2258,9 @@ Type::method_constructor(Gogo*, Type* method_type, ++p; go_assert(p->is_field_name("typ")); - if (!only_value_methods && m->is_value_method()) - { - // This is a value method on a pointer type. Change the type of - // the method to use a pointer receiver. The implementation - // always uses a pointer receiver anyhow. - Type* rtype = mtype->receiver()->type(); - Type* prtype = Type::make_pointer_type(rtype); - Typed_identifier* receiver = - new Typed_identifier(mtype->receiver()->name(), prtype, - mtype->receiver()->location()); - mtype = Type::make_function_type(receiver, - (mtype->parameters() == NULL - ? NULL - : mtype->parameters()->copy()), - (mtype->results() == NULL - ? NULL - : mtype->results()->copy()), - mtype->location()); - } - vals->push_back(Expression::make_type_descriptor(mtype, bloc)); + bool want_pointer_receiver = !only_value_methods && m->is_value_method(); + nonmethod_type = mtype->copy_with_receiver_as_param(want_pointer_receiver); + vals->push_back(Expression::make_type_descriptor(nonmethod_type, bloc)); ++p; go_assert(p->is_field_name("tfn")); @@ -3910,6 +3988,32 @@ Function_type::copy_with_receiver(Type* receiver_type) const return ret; } +// Make a copy of a function type with the receiver as the first +// parameter. + +Function_type* +Function_type::copy_with_receiver_as_param(bool want_pointer_receiver) const +{ + go_assert(this->is_method()); + Typed_identifier_list* new_params = new Typed_identifier_list(); + Type* rtype = this->receiver_->type(); + if (want_pointer_receiver) + rtype = Type::make_pointer_type(rtype); + Typed_identifier receiver(this->receiver_->name(), rtype, + this->receiver_->location()); + new_params->push_back(receiver); + const Typed_identifier_list* orig_params = this->parameters_; + if (orig_params != NULL && !orig_params->empty()) + { + for (Typed_identifier_list::const_iterator p = orig_params->begin(); + p != orig_params->end(); + ++p) + new_params->push_back(*p); + } + return Type::make_function_type(NULL, new_params, this->results_, + this->location_); +} + // Make a copy of a function type ignoring any receiver and adding a // closure parameter. diff --git a/gcc/go/gofrontend/types.h b/gcc/go/gofrontend/types.h index d1a739af354..9f965916131 100644 --- a/gcc/go/gofrontend/types.h +++ b/gcc/go/gofrontend/types.h @@ -1138,6 +1138,13 @@ class Type Function_type* equal_fntype, Named_object** hash_fn, Named_object** equal_fn); + void + write_named_hash(Gogo*, Named_type*, Function_type* hash_fntype, + Function_type* equal_fntype); + + void + write_named_equal(Gogo*, Named_type*); + // Build a composite literal for the uncommon type information. Expression* uncommon_type_constructor(Gogo*, Type* uncommon_type, @@ -1790,6 +1797,12 @@ class Function_type : public Type Function_type* copy_with_receiver(Type*) const; + // Return a copy of this type with the receiver treated as the first + // parameter. If WANT_POINTER_RECEIVER is true, the receiver is + // forced to be a pointer. + Function_type* + copy_with_receiver_as_param(bool want_pointer_receiver) const; + // Return a copy of this type ignoring any receiver and using dummy // names for all parameters. This is used for thunks for method // values. diff --git a/gcc/go/gospec.c b/gcc/go/gospec.c index 0be7716be5c..02d5842352f 100644 --- a/gcc/go/gospec.c +++ b/gcc/go/gospec.c @@ -1,5 +1,5 @@ /* gospec.c -- Specific flags and argument handling of the gcc Go front end. - Copyright (C) 2009-2013 Free Software Foundation, Inc. + Copyright (C) 2009-2014 Free Software Foundation, Inc. This file is part of GCC. diff --git a/gcc/go/lang-specs.h b/gcc/go/lang-specs.h index ce1eb976194..463e05007ae 100644 --- a/gcc/go/lang-specs.h +++ b/gcc/go/lang-specs.h @@ -1,5 +1,5 @@ /* lang-specs.h -- gcc driver specs for Go frontend. - Copyright (C) 2009-2013 Free Software Foundation, Inc. + Copyright (C) 2009-2014 Free Software Foundation, Inc. This file is part of GCC. diff --git a/gcc/go/lang.opt b/gcc/go/lang.opt index f7bd0b96aaf..6f6b4418ac8 100644 --- a/gcc/go/lang.opt +++ b/gcc/go/lang.opt @@ -1,6 +1,6 @@ ; lang.opt -- Options for the gcc Go front end. -; Copyright (C) 2009-2013 Free Software Foundation, Inc. +; Copyright (C) 2009-2014 Free Software Foundation, Inc. ; ; This file is part of GCC. ; |