summaryrefslogtreecommitdiff
path: root/gcc/go
diff options
context:
space:
mode:
authorbstarynk <bstarynk@138bc75d-0d04-0410-961f-82ee72b054a4>2014-01-04 17:57:29 +0000
committerbstarynk <bstarynk@138bc75d-0d04-0410-961f-82ee72b054a4>2014-01-04 17:57:29 +0000
commit48ff1d417d4c49525c09b013395e38dda8bd50fe (patch)
treeffb4ea05f14bc936b5dd3681e19b2aa3cee8c3bf /gcc/go
parent144409bbbdb293946cea105115e0e329f633d333 (diff)
downloadgcc-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/ChangeLog37
-rw-r--r--gcc/go/Make-lang.in5
-rw-r--r--gcc/go/config-lang.in2
-rw-r--r--gcc/go/gccgo.texi2
-rw-r--r--gcc/go/go-backend.c2
-rw-r--r--gcc/go/go-c.h2
-rw-r--r--gcc/go/go-gcc.cc38
-rw-r--r--gcc/go/go-lang.c10
-rw-r--r--gcc/go/go-system.h2
-rw-r--r--gcc/go/gofrontend/backend.h4
-rw-r--r--gcc/go/gofrontend/expressions.cc68
-rw-r--r--gcc/go/gofrontend/gogo-tree.cc24
-rw-r--r--gcc/go/gofrontend/gogo.cc41
-rw-r--r--gcc/go/gofrontend/gogo.h2
-rw-r--r--gcc/go/gofrontend/parse.cc25
-rw-r--r--gcc/go/gofrontend/types.cc154
-rw-r--r--gcc/go/gofrontend/types.h13
-rw-r--r--gcc/go/gospec.c2
-rw-r--r--gcc/go/lang-specs.h2
-rw-r--r--gcc/go/lang.opt2
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.
;