summaryrefslogtreecommitdiff
path: root/gcc/go
diff options
context:
space:
mode:
authorbstarynk <bstarynk@138bc75d-0d04-0410-961f-82ee72b054a4>2011-01-03 12:17:59 +0000
committerbstarynk <bstarynk@138bc75d-0d04-0410-961f-82ee72b054a4>2011-01-03 12:17:59 +0000
commit73556f5f6c5d835df3baa9979de74da7bd85cd05 (patch)
treeac76e75c45976914468f05d9d01c6dab44ff831c /gcc/go
parent009b254c18c50184aadbc41673222104cec47838 (diff)
downloadgcc-73556f5f6c5d835df3baa9979de74da7bd85cd05.tar.gz
2011-01-03 Basile Starynkevitch <basile@starynkevitch.net>
MELT branch merged with trunk rev 168414 git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/melt-branch@168419 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/go')
-rw-r--r--gcc/go/ChangeLog12
-rw-r--r--gcc/go/Make-lang.in6
-rw-r--r--gcc/go/go-backend.c2
-rw-r--r--gcc/go/gofrontend/expressions.cc195
-rw-r--r--gcc/go/gofrontend/expressions.h7
-rw-r--r--gcc/go/gofrontend/gogo-tree.cc26
-rw-r--r--gcc/go/gofrontend/gogo.cc91
-rw-r--r--gcc/go/gofrontend/gogo.h15
-rw-r--r--gcc/go/gofrontend/lex.cc50
-rw-r--r--gcc/go/gofrontend/lex.h3
-rw-r--r--gcc/go/gofrontend/parse.cc59
-rw-r--r--gcc/go/gofrontend/parse.h1
-rw-r--r--gcc/go/gofrontend/statements.cc42
-rw-r--r--gcc/go/gofrontend/statements.h6
-rw-r--r--gcc/go/gofrontend/types.cc232
-rw-r--r--gcc/go/gofrontend/types.h16
16 files changed, 599 insertions, 164 deletions
diff --git a/gcc/go/ChangeLog b/gcc/go/ChangeLog
index c98bb279db5..d25a523df75 100644
--- a/gcc/go/ChangeLog
+++ b/gcc/go/ChangeLog
@@ -1,3 +1,15 @@
+2010-12-31 Joern Rennecke <amylaar@spamcop.net>
+
+ PR go/47113
+ * go-backend.c: (go_field_alignment): Add ATTRIBUTE_UNUSED to
+ variable ‘field’ .
+
+2010-12-21 Ian Lance Taylor <iant@google.com>
+
+ * Make-lang.in (check-go): Remove.
+ (lang_checks_parallelized): Add check-go.
+ (check_go_parallelize): Set.
+
2010-12-13 Ian Lance Taylor <iant@google.com>
* gospec.c (lang_specific_driver): Add a -o option if not linking
diff --git a/gcc/go/Make-lang.in b/gcc/go/Make-lang.in
index 4d008161a1c..48799f4eafa 100644
--- a/gcc/go/Make-lang.in
+++ b/gcc/go/Make-lang.in
@@ -119,8 +119,12 @@ go.man: doc/gccgo.1
go.srcman: doc/gccgo.1
-cp -p $^ $(srcdir)/doc
-check-go:
lang_checks += check-go
+lang_checks_parallelized += check-go
+check_go_parallelize = go-test.exp=*/test/\[0-57-9a-bd-hj-zA-Z\]* \
+ go-test.exp=*/test/c* \
+ go-test.exp=*/test/i* \
+ go-test.exp=*/test/6*
# Install hooks.
diff --git a/gcc/go/go-backend.c b/gcc/go/go-backend.c
index 15986dcbed6..9ffe38a02fb 100644
--- a/gcc/go/go-backend.c
+++ b/gcc/go/go-backend.c
@@ -53,7 +53,7 @@ go_field_alignment (tree t)
#ifdef ADJUST_FIELD_ALIGN
{
- tree field;
+ tree field ATTRIBUTE_UNUSED;
field = build_decl (UNKNOWN_LOCATION, FIELD_DECL, NULL, t);
v = ADJUST_FIELD_ALIGN (field, v);
}
diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc
index 39baf9d1c15..f64e5ee4edf 100644
--- a/gcc/go/gofrontend/expressions.cc
+++ b/gcc/go/gofrontend/expressions.cc
@@ -894,6 +894,19 @@ Expression::make_type(Type* type, source_location location)
return new Type_expression(type, location);
}
+// Class Parser_expression.
+
+Type*
+Parser_expression::do_type()
+{
+ // We should never really ask for the type of a Parser_expression.
+ // However, it can happen, at least when we have an invalid const
+ // whose initializer refers to the const itself. In that case we
+ // may ask for the type when lowering the const itself.
+ gcc_assert(saw_errors());
+ return Type::make_error_type();
+}
+
// Class Var_expression.
// Lower a variable expression. Here we just make sure that the
@@ -1248,14 +1261,20 @@ Unknown_expression::do_lower(Gogo*, Named_object*, int)
{
source_location location = this->location();
Named_object* no = this->named_object_;
- Named_object* real = no->unknown_value()->real_named_object();
- if (real == NULL)
+ Named_object* real;
+ if (!no->is_unknown())
+ real = no;
+ else
{
- if (this->is_composite_literal_key_)
- return this;
- error_at(location, "reference to undefined name %qs",
- this->named_object_->message_name().c_str());
- return Expression::make_error(location);
+ real = no->unknown_value()->real_named_object();
+ if (real == NULL)
+ {
+ if (this->is_composite_literal_key_)
+ return this;
+ error_at(location, "reference to undefined name %qs",
+ this->named_object_->message_name().c_str());
+ return Expression::make_error(location);
+ }
}
switch (real->classification())
{
@@ -2528,7 +2547,9 @@ Const_expression::do_type()
if (this->type_ != NULL)
return this->type_;
- if (this->seen_)
+ Named_constant* nc = this->constant_->const_value();
+
+ if (this->seen_ || nc->lowering())
{
this->report_error(_("constant refers to itself"));
this->type_ = Type::make_error_type();
@@ -2537,7 +2558,6 @@ Const_expression::do_type()
this->seen_ = true;
- Named_constant* nc = this->constant_->const_value();
Type* ret = nc->type();
if (ret != NULL)
@@ -3242,6 +3262,18 @@ Type_conversion_expression::do_check_types(Gogo*)
Type* expr_type = this->expr_->type();
std::string reason;
+ if (type->is_error_type()
+ || type->is_undefined()
+ || expr_type->is_error_type()
+ || expr_type->is_undefined())
+ {
+ // Make sure we emit an error for an undefined type.
+ type->base();
+ expr_type->base();
+ this->set_is_error();
+ return;
+ }
+
if (this->may_convert_function_types_
&& type->function_type() != NULL
&& expr_type->function_type() != NULL)
@@ -6431,6 +6463,9 @@ class Builtin_call_expression : public Call_expression
Gogo* gogo_;
// The builtin function being called.
Builtin_function_code code_;
+ // Used to stop endless loops when the length of an array uses len
+ // or cap of the array itself.
+ mutable bool seen_;
};
Builtin_call_expression::Builtin_call_expression(Gogo* gogo,
@@ -6439,7 +6474,7 @@ Builtin_call_expression::Builtin_call_expression(Gogo* gogo,
bool is_varargs,
source_location location)
: Call_expression(fn, args, is_varargs, location),
- gogo_(gogo), code_(BUILTIN_INVALID)
+ gogo_(gogo), code_(BUILTIN_INVALID), seen_(false)
{
Func_expression* fnexp = this->fn()->func_expression();
gcc_assert(fnexp != NULL);
@@ -6749,6 +6784,9 @@ Builtin_call_expression::do_is_constant() const
case BUILTIN_LEN:
case BUILTIN_CAP:
{
+ if (this->seen_)
+ return false;
+
Expression* arg = this->one_arg();
if (arg == NULL)
return false;
@@ -6761,10 +6799,15 @@ Builtin_call_expression::do_is_constant() const
if (arg_type->array_type() != NULL
&& arg_type->array_type()->length() != NULL)
- return arg_type->array_type()->length()->is_constant();
+ return true;
if (this->code_ == BUILTIN_LEN && arg_type->is_string_type())
- return arg->is_constant();
+ {
+ this->seen_ = true;
+ bool ret = arg->is_constant();
+ this->seen_ = false;
+ return ret;
+ }
}
break;
@@ -6836,8 +6879,13 @@ Builtin_call_expression::do_integer_constant_value(bool iota_is_constant,
if (arg_type->array_type() != NULL
&& arg_type->array_type()->length() != NULL)
{
+ if (this->seen_)
+ return false;
Expression* e = arg_type->array_type()->length();
- if (e->integer_constant_value(iota_is_constant, val, ptype))
+ this->seen_ = true;
+ bool r = e->integer_constant_value(iota_is_constant, val, ptype);
+ this->seen_ = false;
+ if (r)
{
*ptype = Type::lookup_integer_type("int");
return true;
@@ -7369,13 +7417,16 @@ Builtin_call_expression::do_check_types(Gogo*)
case BUILTIN_APPEND:
{
const Expression_list* args = this->args();
- if (args == NULL || args->empty())
+ if (args == NULL || args->size() < 2)
{
this->report_error(_("not enough arguments"));
break;
}
- /* Lowering varargs should have left us with 2 arguments. */
- gcc_assert(args->size() == 2);
+ if (args->size() > 2)
+ {
+ this->report_error(_("too many arguments"));
+ break;
+ }
std::string reason;
if (!Type::are_assignable(args->front()->type(), args->back()->type(),
&reason))
@@ -7449,7 +7500,18 @@ Builtin_call_expression::do_get_tree(Translate_context* context)
gcc_assert(args != NULL && args->size() == 1);
Expression* arg = *args->begin();
Type* arg_type = arg->type();
+
+ if (this->seen_)
+ {
+ gcc_assert(saw_errors());
+ return error_mark_node;
+ }
+ this->seen_ = true;
+
tree arg_tree = arg->get_tree(context);
+
+ this->seen_ = false;
+
if (arg_tree == error_mark_node)
return error_mark_node;
@@ -7468,7 +7530,16 @@ Builtin_call_expression::do_get_tree(Translate_context* context)
if (arg_type->is_string_type())
val_tree = String_type::length_tree(gogo, arg_tree);
else if (arg_type->array_type() != NULL)
- val_tree = arg_type->array_type()->length_tree(gogo, arg_tree);
+ {
+ if (this->seen_)
+ {
+ gcc_assert(saw_errors());
+ return error_mark_node;
+ }
+ this->seen_ = true;
+ val_tree = arg_type->array_type()->length_tree(gogo, arg_tree);
+ this->seen_ = false;
+ }
else if (arg_type->map_type() != NULL)
{
static tree map_len_fndecl;
@@ -7497,7 +7568,17 @@ Builtin_call_expression::do_get_tree(Translate_context* context)
else
{
if (arg_type->array_type() != NULL)
- val_tree = arg_type->array_type()->capacity_tree(gogo, arg_tree);
+ {
+ if (this->seen_)
+ {
+ gcc_assert(saw_errors());
+ return error_mark_node;
+ }
+ this->seen_ = true;
+ val_tree = arg_type->array_type()->capacity_tree(gogo,
+ arg_tree);
+ this->seen_ = false;
+ }
else if (arg_type->channel_type() != NULL)
{
static tree chan_cap_fndecl;
@@ -7891,10 +7972,16 @@ Builtin_call_expression::do_get_tree(Translate_context* context)
if (arg1_tree == error_mark_node || arg2_tree == error_mark_node)
return error_mark_node;
- Array_type* at2 = arg2->type()->array_type();
+ arg2_tree = Expression::convert_for_assignment(context, at,
+ arg2->type(),
+ arg2_tree,
+ location);
+ if (arg2_tree == error_mark_node)
+ return error_mark_node;
+
arg2_tree = save_expr(arg2_tree);
- tree arg2_val = at2->value_pointer_tree(gogo, arg2_tree);
- tree arg2_len = at2->length_tree(gogo, arg2_tree);
+ tree arg2_val = at->value_pointer_tree(gogo, arg2_tree);
+ tree arg2_len = at->length_tree(gogo, arg2_tree);
if (arg2_val == error_mark_node || arg2_len == error_mark_node)
return error_mark_node;
arg2_val = fold_convert_loc(location, ptr_type_node, arg2_val);
@@ -8630,6 +8717,7 @@ Call_expression::do_get_tree(Translate_context* context)
pe != this->args_->end();
++pe, ++pp, ++i)
{
+ gcc_assert(pp != params->end());
tree arg_val = (*pe)->get_tree(context);
args[i] = Expression::convert_for_assignment(context,
pp->type(),
@@ -8815,6 +8903,12 @@ Call_result_expression::do_type()
if (fntype == NULL)
return Type::make_error_type();
const Typed_identifier_list* results = fntype->results();
+ if (results == NULL)
+ {
+ this->report_error(_("number of results does not match "
+ "number of values"));
+ return Type::make_error_type();
+ }
Typed_identifier_list::const_iterator pr = results->begin();
for (unsigned int i = 0; i < this->index_; ++i)
{
@@ -9075,7 +9169,11 @@ Array_index_expression::do_check_types(Gogo*)
this->report_error(_("slice end must be integer"));
Array_type* array_type = this->array_->type()->array_type();
- gcc_assert(array_type != NULL);
+ if (array_type == NULL)
+ {
+ gcc_assert(this->array_->type()->is_error_type());
+ return;
+ }
unsigned int int_bits =
Type::lookup_integer_type("int")->integer_type()->bits();
@@ -9153,7 +9251,11 @@ Array_index_expression::do_get_tree(Translate_context* context)
source_location loc = this->location();
Array_type* array_type = this->array_->type()->array_type();
- gcc_assert(array_type != NULL);
+ if (array_type == NULL)
+ {
+ gcc_assert(this->array_->type()->is_error_type());
+ return error_mark_node;
+ }
tree type_tree = array_type->get_tree(gogo);
if (type_tree == error_mark_node)
@@ -9602,7 +9704,8 @@ Map_type*
Map_index_expression::get_map_type() const
{
Map_type* mt = this->map_->type()->deref()->map_type();
- gcc_assert(mt != NULL);
+ if (mt == NULL)
+ gcc_assert(saw_errors());
return mt;
}
@@ -9621,7 +9724,10 @@ Map_index_expression::do_traverse(Traverse* traverse)
Type*
Map_index_expression::do_type()
{
- Type* type = this->get_map_type()->val_type();
+ Map_type* mt = this->get_map_type();
+ if (mt == NULL)
+ return Type::make_error_type();
+ Type* type = mt->val_type();
// If this map index is in a tuple assignment, we actually return a
// pointer to the value type. Tuple_map_assignment_statement is
// responsible for handling this correctly. We need to get the type
@@ -9637,7 +9743,9 @@ void
Map_index_expression::do_determine_type(const Type_context*)
{
this->map_->determine_type_no_context();
- Type_context subcontext(this->get_map_type()->key_type(), false);
+ Map_type* mt = this->get_map_type();
+ Type* key_type = mt == NULL ? NULL : mt->key_type();
+ Type_context subcontext(key_type, false);
this->index_->determine_type(&subcontext);
}
@@ -9647,8 +9755,10 @@ void
Map_index_expression::do_check_types(Gogo*)
{
std::string reason;
- if (!Type::are_assignable(this->get_map_type()->key_type(),
- this->index_->type(), &reason))
+ Map_type* mt = this->get_map_type();
+ if (mt == NULL)
+ return;
+ if (!Type::are_assignable(mt->key_type(), this->index_->type(), &reason))
{
if (reason.empty())
this->report_error(_("incompatible type for map index"));
@@ -9667,6 +9777,8 @@ tree
Map_index_expression::do_get_tree(Translate_context* context)
{
Map_type* type = this->get_map_type();
+ if (type == NULL)
+ return error_mark_node;
tree valptr = this->get_value_pointer(context, this->is_lvalue_);
if (valptr == error_mark_node)
@@ -9704,6 +9816,8 @@ Map_index_expression::get_value_pointer(Translate_context* context,
bool insert)
{
Map_type* type = this->get_map_type();
+ if (type == NULL)
+ return error_mark_node;
tree map_tree = this->map_->get_tree(context);
tree index_tree = this->index_->get_tree(context);
@@ -10237,9 +10351,13 @@ tree
Allocation_expression::do_get_tree(Translate_context* context)
{
tree type_tree = this->type_->get_tree(context->gogo());
+ if (type_tree == error_mark_node)
+ return error_mark_node;
tree size_tree = TYPE_SIZE_UNIT(type_tree);
tree space = context->gogo()->allocate_memory(this->type_, size_tree,
this->location());
+ if (space == error_mark_node)
+ return error_mark_node;
return fold_convert(build_pointer_type(type_tree), space);
}
@@ -10908,7 +11026,14 @@ class Open_array_construction_expression : public Array_construction_expression
tree
Open_array_construction_expression::do_get_tree(Translate_context* context)
{
- Type* element_type = this->type()->array_type()->element_type();
+ Array_type* array_type = this->type()->array_type();
+ if (array_type == NULL)
+ {
+ gcc_assert(this->type()->is_error_type());
+ return error_mark_node;
+ }
+
+ Type* element_type = array_type->element_type();
tree element_type_tree = element_type->get_tree(context->gogo());
if (element_type_tree == error_mark_node)
return error_mark_node;
@@ -11172,13 +11297,19 @@ Map_construction_expression::do_get_tree(Translate_context* context)
Type* key_type = mt->key_type();
tree id = get_identifier("__key");
- tree key_field = build_decl(loc, FIELD_DECL, id, key_type->get_tree(gogo));
+ tree key_type_tree = key_type->get_tree(gogo);
+ if (key_type_tree == error_mark_node)
+ return error_mark_node;
+ tree key_field = build_decl(loc, FIELD_DECL, id, key_type_tree);
DECL_CONTEXT(key_field) = struct_type;
TYPE_FIELDS(struct_type) = key_field;
Type* val_type = mt->val_type();
id = get_identifier("__val");
- tree val_field = build_decl(loc, FIELD_DECL, id, val_type->get_tree(gogo));
+ tree val_type_tree = val_type->get_tree(gogo);
+ if (val_type_tree == error_mark_node)
+ return error_mark_node;
+ tree val_field = build_decl(loc, FIELD_DECL, id, val_type_tree);
DECL_CONTEXT(val_field) = struct_type;
DECL_CHAIN(key_field) = val_field;
@@ -11279,6 +11410,8 @@ Map_construction_expression::do_get_tree(Translate_context* context)
tree descriptor = gogo->map_descriptor(mt);
tree type_tree = this->type_->get_tree(gogo);
+ if (type_tree == error_mark_node)
+ return error_mark_node;
static tree construct_map_fndecl;
tree call = Gogo::call_builtin(&construct_map_fndecl,
diff --git a/gcc/go/gofrontend/expressions.h b/gcc/go/gofrontend/expressions.h
index 5d7d90bdb01..fe4ade2c99d 100644
--- a/gcc/go/gofrontend/expressions.h
+++ b/gcc/go/gofrontend/expressions.h
@@ -873,8 +873,7 @@ class Parser_expression : public Expression
do_lower(Gogo*, Named_object*, int) = 0;
Type*
- do_type()
- { gcc_unreachable(); }
+ do_type();
void
do_determine_type(const Type_context*)
@@ -1346,7 +1345,9 @@ class Func_expression : public Expression
do_copy()
{
return Expression::make_func_reference(this->function_,
- this->closure_->copy(),
+ (this->closure_ == NULL
+ ? NULL
+ : this->closure_->copy()),
this->location());
}
diff --git a/gcc/go/gofrontend/gogo-tree.cc b/gcc/go/gofrontend/gogo-tree.cc
index e43f64d7e1a..05a701feffc 100644
--- a/gcc/go/gofrontend/gogo-tree.cc
+++ b/gcc/go/gofrontend/gogo-tree.cc
@@ -757,7 +757,7 @@ Gogo::write_globals()
pop_cfun();
}
- if (var_init_tree != NULL_TREE)
+ if (var_init_tree != NULL_TREE && var_init_tree != error_mark_node)
{
if (no->var_value()->init() == NULL
&& !no->var_value()->has_pre_init())
@@ -1209,10 +1209,13 @@ Variable::get_init_block(Gogo* gogo, Named_object* function, tree var_decl)
Translate_context context(gogo, function, NULL, NULL_TREE);
tree block_tree = this->preinit_->get_tree(&context);
+ if (block_tree == error_mark_node)
+ return error_mark_node;
gcc_assert(TREE_CODE(block_tree) == BIND_EXPR);
tree statements = BIND_EXPR_BODY(block_tree);
- while (TREE_CODE(statements) == TRY_FINALLY_EXPR
- || TREE_CODE(statements) == TRY_CATCH_EXPR)
+ while (statements != NULL_TREE
+ && (TREE_CODE(statements) == TRY_FINALLY_EXPR
+ || TREE_CODE(statements) == TRY_CATCH_EXPR))
statements = TREE_OPERAND(statements, 0);
// It's possible to have pre-init statements without an initializer
@@ -1220,6 +1223,8 @@ Variable::get_init_block(Gogo* gogo, Named_object* function, tree var_decl)
if (this->init_ != NULL)
{
tree rhs_tree = this->init_->get_tree(&context);
+ if (rhs_tree == error_mark_node)
+ return error_mark_node;
if (var_decl == NULL_TREE)
append_to_statement_list(rhs_tree, &statements);
else
@@ -1228,6 +1233,8 @@ Variable::get_init_block(Gogo* gogo, Named_object* function, tree var_decl)
this->init_->type(),
rhs_tree,
this->location());
+ if (val == error_mark_node)
+ return error_mark_node;
tree set = fold_build2_loc(this->location(), MODIFY_EXPR,
void_type_node, var_decl, val);
append_to_statement_list(set, &statements);
@@ -2349,6 +2356,8 @@ Gogo::map_descriptor(Map_type* maptype)
Map_descriptors::iterator p = ins.first;
if (!ins.second)
{
+ if (p->second == error_mark_node)
+ return error_mark_node;
gcc_assert(p->second != NULL_TREE && DECL_P(p->second));
return build_fold_addr_expr(p->second);
}
@@ -2378,7 +2387,10 @@ Gogo::map_descriptor(Map_type* maptype)
"__val",
valtype->get_tree(this));
if (map_entry_type == error_mark_node)
- return error_mark_node;
+ {
+ p->second = error_mark_node;
+ return error_mark_node;
+ }
tree map_entry_key_field = DECL_CHAIN(TYPE_FIELDS(map_entry_type));
gcc_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(map_entry_key_field)),
@@ -2888,6 +2900,9 @@ tree
Gogo::send_on_channel(tree channel, tree val, bool blocking, bool for_select,
source_location location)
{
+ if (channel == error_mark_node || val == error_mark_node)
+ return error_mark_node;
+
if (int_size_in_bytes(TREE_TYPE(val)) <= 8
&& !AGGREGATE_TYPE_P(TREE_TYPE(val))
&& !FLOAT_TYPE_P(TREE_TYPE(val)))
@@ -3022,6 +3037,9 @@ tree
Gogo::receive_from_channel(tree type_tree, tree channel, bool for_select,
source_location location)
{
+ if (type_tree == error_mark_node || channel == error_mark_node)
+ return error_mark_node;
+
if (int_size_in_bytes(type_tree) <= 8
&& !AGGREGATE_TYPE_P(type_tree)
&& !FLOAT_TYPE_P(type_tree))
diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc
index d8d704d956e..9e51b63e62f 100644
--- a/gcc/go/gofrontend/gogo.cc
+++ b/gcc/go/gofrontend/gogo.cc
@@ -415,6 +415,9 @@ Gogo::current_block()
Named_object*
Gogo::lookup(const std::string& name, Named_object** pfunction) const
{
+ if (pfunction != NULL)
+ *pfunction = NULL;
+
if (Gogo::is_sink_name(name))
return Named_object::make_sink();
@@ -431,9 +434,6 @@ Gogo::lookup(const std::string& name, Named_object** pfunction) const
}
}
- if (pfunction != NULL)
- *pfunction = NULL;
-
if (this->package_ != NULL)
{
Named_object* ret = this->package_->bindings()->lookup(name);
@@ -659,7 +659,13 @@ Gogo::start_function(const std::string& name, Function_type* type,
Named_object* ret;
if (Gogo::is_sink_name(*pname))
- ret = Named_object::make_sink();
+ {
+ static int sink_count;
+ char buf[30];
+ snprintf(buf, sizeof buf, ".$sink%d", sink_count);
+ ++sink_count;
+ ret = Named_object::make_function(buf, NULL, function);
+ }
else if (!type->is_method())
{
ret = this->package_->bindings()->add_function(*pname, NULL, function);
@@ -881,7 +887,7 @@ Gogo::add_type(const std::string& name, Type* type, source_location location)
{
Named_object* no = this->current_bindings()->add_type(name, NULL, type,
location);
- if (!this->in_global_scope())
+ if (!this->in_global_scope() && no->is_type())
no->type_value()->set_in_function(this->functions_.back().function);
}
@@ -901,7 +907,7 @@ Gogo::declare_type(const std::string& name, source_location location)
{
Bindings* bindings = this->current_bindings();
Named_object* no = bindings->add_type_declaration(name, NULL, location);
- if (!this->in_global_scope())
+ if (!this->in_global_scope() && no->is_type_declaration())
{
Named_object* f = this->functions_.back().function;
no->type_declaration_value()->set_in_function(f);
@@ -1157,8 +1163,8 @@ Lower_parse_tree::constant(Named_object* no, bool)
{
Named_constant* nc = no->const_value();
- // We can recursively a constant if the initializer expression
- // manages to refer to itself.
+ // Don't get into trouble if the constant's initializer expression
+ // refers to the constant itself.
if (nc->lowering())
return TRAVERSE_CONTINUE;
nc->set_lowering();
@@ -1378,7 +1384,11 @@ Gogo::determine_types()
// If this is a global variable which requires runtime
// initialization, we need an initialization function.
- if (!variable->is_global() || variable->init() == NULL)
+ if (!variable->is_global())
+ ;
+ else if (variable->has_pre_init())
+ this->need_init_fn_ = true;
+ else if (variable->init() == NULL)
;
else if (variable->type()->interface_type() != NULL)
this->need_init_fn_ = true;
@@ -2093,14 +2103,6 @@ Build_recover_thunks::function(Named_object* orig_no)
Expression* fn = Expression::make_func_reference(new_no, closure, location);
Expression_list* args = new Expression_list();
- if (orig_fntype->is_method())
- {
- Named_object* rec_no = gogo->lookup(receiver_name, NULL);
- gcc_assert(rec_no != NULL
- && rec_no->is_variable()
- && rec_no->var_value()->is_parameter());
- args->push_back(Expression::make_var_reference(rec_no, location));
- }
if (new_params != NULL)
{
// Note that we skip the last parameter, which is the boolean
@@ -2153,10 +2155,11 @@ Build_recover_thunks::function(Named_object* orig_no)
&& !orig_rec_no->var_value()->is_receiver());
orig_rec_no->var_value()->set_is_receiver();
- Named_object* new_rec_no = new_bindings->lookup_local(receiver_name);
+ const std::string& new_receiver_name(orig_fntype->receiver()->name());
+ Named_object* new_rec_no = new_bindings->lookup_local(new_receiver_name);
gcc_assert(new_rec_no != NULL
&& new_rec_no->is_variable()
- && !new_rec_no->var_value()->is_receiver());
+ && new_rec_no->var_value()->is_receiver());
new_rec_no->var_value()->set_is_not_receiver();
}
@@ -2178,6 +2181,10 @@ Build_recover_thunks::function(Named_object* orig_no)
Convert_recover convert_recover(can_recover_no);
new_func->traverse(&convert_recover);
+ // Update the function pointers in any named results.
+ new_func->update_named_result_variables();
+ orig_func->update_named_result_variables();
+
return TRAVERSE_CONTINUE;
}
@@ -2506,6 +2513,21 @@ Function::create_named_result_variables(Gogo* gogo)
}
}
+// Update the named result variables when cloning a function which
+// calls recover.
+
+void
+Function::update_named_result_variables()
+{
+ if (this->named_results_ == NULL)
+ return;
+
+ for (Named_results::iterator p = this->named_results_->begin();
+ p != this->named_results_->end();
+ ++p)
+ (*p)->result_var_value()->set_function(this);
+}
+
// Return the closure variable, creating it if necessary.
Named_object*
@@ -2629,7 +2651,7 @@ void
Function::swap_for_recover(Function *x)
{
gcc_assert(this->enclosing_ == x->enclosing_);
- gcc_assert(this->named_results_ == x->named_results_);
+ std::swap(this->named_results_, x->named_results_);
std::swap(this->closure_var_, x->closure_var_);
std::swap(this->block_, x->block_);
gcc_assert(this->location_ == x->location_);
@@ -2644,6 +2666,14 @@ Function::traverse(Traverse* traverse)
{
unsigned int traverse_mask = traverse->traverse_mask();
+ if ((traverse_mask
+ & (Traverse::traverse_types | Traverse::traverse_expressions))
+ != 0)
+ {
+ if (Type::traverse(this->type_, traverse) == TRAVERSE_EXIT)
+ return TRAVERSE_EXIT;
+ }
+
// FIXME: We should check traverse_functions here if nested
// functions are stored in block bindings.
if (this->block_ != NULL
@@ -3134,12 +3164,17 @@ Type*
Variable::type_from_tuple(Expression* expr, bool report_error) const
{
if (expr->map_index_expression() != NULL)
- return expr->map_index_expression()->get_map_type()->val_type();
+ {
+ Map_type* mt = expr->map_index_expression()->get_map_type();
+ if (mt == NULL)
+ return Type::make_error_type();
+ return mt->val_type();
+ }
else if (expr->receive_expression() != NULL)
{
Expression* channel = expr->receive_expression()->channel();
Type* channel_type = channel->type();
- if (channel_type->is_error_type())
+ if (channel_type->channel_type() == NULL)
return Type::make_error_type();
return channel_type->channel_type()->element_type();
}
@@ -3702,6 +3737,18 @@ Named_object::set_function_value(Function* function)
this->u_.func_value = function;
}
+// Declare an unknown object as a type declaration.
+
+void
+Named_object::declare_as_type()
+{
+ gcc_assert(this->classification_ == NAMED_OBJECT_UNKNOWN);
+ Unknown_name* unk = this->u_.unknown_value;
+ this->classification_ = NAMED_OBJECT_TYPE_DECLARATION;
+ this->u_.type_declaration = new Type_declaration(unk->location());
+ delete unk;
+}
+
// Return the location of a named object.
source_location
diff --git a/gcc/go/gofrontend/gogo.h b/gcc/go/gofrontend/gogo.h
index 552a6434485..dd7afc86a19 100644
--- a/gcc/go/gofrontend/gogo.h
+++ b/gcc/go/gofrontend/gogo.h
@@ -787,6 +787,11 @@ class Function
void
create_named_result_variables(Gogo*);
+ // Update the named result variables when cloning a function which
+ // calls recover.
+ void
+ update_named_result_variables();
+
// Add a new field to the closure variable.
void
add_closure_field(Named_object* var, source_location loc)
@@ -1318,6 +1323,12 @@ class Result_variable
is_in_heap() const
{ return this->is_address_taken_; }
+ // Set the function. This is used when cloning functions which call
+ // recover.
+ void
+ set_function(Function* function)
+ { this->function_ = function; }
+
private:
// Type of result variable.
Type* type_;
@@ -1815,6 +1826,10 @@ class Named_object
void
set_function_value(Function*);
+ // Declare an unknown name as a type declaration.
+ void
+ declare_as_type();
+
// Export this object.
void
export_named_object(Export*) const;
diff --git a/gcc/go/gofrontend/lex.cc b/gcc/go/gofrontend/lex.cc
index ad1a1fe4fc7..90b41ea2ed0 100644
--- a/gcc/go/gofrontend/lex.cc
+++ b/gcc/go/gofrontend/lex.cc
@@ -434,8 +434,8 @@ Token::print(FILE* file) const
Lex::Lex(const char* input_file_name, FILE* input_file)
: input_file_name_(input_file_name), input_file_(input_file),
- linebuf_(NULL), linebufsize_(120), linesize_(0), lineno_(0),
- add_semi_at_eol_(false)
+ linebuf_(NULL), linebufsize_(120), linesize_(0), lineoff_(0),
+ lineno_(0), add_semi_at_eol_(false)
{
this->linebuf_ = new char[this->linebufsize_];
linemap_add(line_table, LC_ENTER, 0, input_file_name, 1);
@@ -742,12 +742,7 @@ int
Lex::fetch_char(const char* p, unsigned int* value)
{
unsigned char c = *p;
- if (c == 0)
- {
- *value = 0xfffd;
- return 0;
- }
- else if (c <= 0x7f)
+ if (c <= 0x7f)
{
*value = c;
return 1;
@@ -812,13 +807,19 @@ Lex::advance_one_utf8_char(const char* p, unsigned int* value,
bool* issued_error)
{
*issued_error = false;
+
+ if (*p == '\0')
+ {
+ error_at(this->location(), "invalid NUL byte");
+ *issued_error = true;
+ *value = 0;
+ return p + 1;
+ }
+
int adv = Lex::fetch_char(p, value);
if (adv == 0)
{
- if (*p == '\0')
- error_at(this->location(), "invalid NUL byte");
- else
- error_at(this->location(), "invalid UTF-8 encoding");
+ error_at(this->location(), "invalid UTF-8 encoding");
*issued_error = true;
return p + 1;
}
@@ -931,6 +932,25 @@ Lex::is_hex_digit(char c)
|| (c >= 'a' && c <= 'f'));
}
+// Return whether an exponent could start at P.
+
+bool
+Lex::could_be_exponent(const char* p, const char* pend)
+{
+ if (*p != 'e' && *p != 'E')
+ return false;
+ ++p;
+ if (p >= pend)
+ return false;
+ if (*p == '+' || *p == '-')
+ {
+ ++p;
+ if (p >= pend)
+ return false;
+ }
+ return *p >= '0' && *p <= '9';
+}
+
// Pick up a number.
Token
@@ -980,7 +1000,7 @@ Lex::gather_number()
}
}
- if (*p != '.' && *p != 'e' && *p != 'E' && *p != 'i')
+ if (*p != '.' && *p != 'i' && !Lex::could_be_exponent(p, pend))
{
std::string s(pnum, p - pnum);
mpz_t val;
@@ -1004,7 +1024,7 @@ Lex::gather_number()
++p;
}
- if (*p != '.' && *p != 'E' && *p != 'e' && *p != 'i')
+ if (*p != '.' && *p != 'i' && !Lex::could_be_exponent(p, pend))
{
std::string s(pnum, p - pnum);
mpz_t val;
@@ -1039,7 +1059,7 @@ Lex::gather_number()
++p;
}
- if (dot && (*p == 'E' || *p == 'e'))
+ if (dot && Lex::could_be_exponent(p, pend))
{
++p;
if (*p == '+' || *p == '-')
diff --git a/gcc/go/gofrontend/lex.h b/gcc/go/gofrontend/lex.h
index c8def2bf7d5..4202ed3748c 100644
--- a/gcc/go/gofrontend/lex.h
+++ b/gcc/go/gofrontend/lex.h
@@ -379,6 +379,9 @@ class Lex
Token
gather_identifier();
+ static bool
+ could_be_exponent(const char*, const char*);
+
Token
gather_number();
diff --git a/gcc/go/gofrontend/parse.cc b/gcc/go/gofrontend/parse.cc
index a0d87dc8c6a..f4b01be8c93 100644
--- a/gcc/go/gofrontend/parse.cc
+++ b/gcc/go/gofrontend/parse.cc
@@ -1654,8 +1654,18 @@ Parse::init_vars_from_map(const Typed_identifier_list* vars, Type* type,
if (!this->gogo_->in_global_scope())
this->gogo_->add_statement(s);
- else
+ else if (!val_no->is_sink())
val_no->var_value()->add_preinit_statement(s);
+ else if (!no->is_sink())
+ no->var_value()->add_preinit_statement(s);
+ else
+ {
+ // Execute the map index expression just so that we can fail if
+ // the map is nil.
+ Named_object* dummy = this->create_dummy_global(Type::lookup_bool_type(),
+ NULL, location);
+ dummy->var_value()->add_preinit_statement(s);
+ }
return true;
}
@@ -1705,8 +1715,16 @@ Parse::init_vars_from_receive(const Typed_identifier_list* vars, Type* type,
if (!this->gogo_->in_global_scope())
this->gogo_->add_statement(s);
- else
+ else if (!val_no->is_sink())
val_no->var_value()->add_preinit_statement(s);
+ else if (!no->is_sink())
+ no->var_value()->add_preinit_statement(s);
+ else
+ {
+ Named_object* dummy = this->create_dummy_global(Type::lookup_bool_type(),
+ NULL, location);
+ dummy->var_value()->add_preinit_statement(s);
+ }
return true;
}
@@ -1757,8 +1775,15 @@ Parse::init_vars_from_type_guard(const Typed_identifier_list* vars,
if (!this->gogo_->in_global_scope())
this->gogo_->add_statement(s);
- else
+ else if (!val_no->is_sink())
val_no->var_value()->add_preinit_statement(s);
+ else if (!no->is_sink())
+ no->var_value()->add_preinit_statement(s);
+ else
+ {
+ Named_object* dummy = this->create_dummy_global(type, NULL, location);
+ dummy->var_value()->add_preinit_statement(s);
+ }
return true;
}
@@ -1780,17 +1805,7 @@ Parse::init_var(const Typed_identifier& tid, Type* type, Expression* init,
if (!this->gogo_->in_global_scope())
this->gogo_->add_statement(Statement::make_statement(init));
else
- {
- // Create a dummy global variable to force the
- // initializer to be run in the right place.
- Variable* var = new Variable(type, init, true, false, false,
- location);
- static int count;
- char buf[30];
- snprintf(buf, sizeof buf, "_.%d", count);
- ++count;
- return this->gogo_->add_variable(buf, var);
- }
+ return this->create_dummy_global(type, init, location);
}
return this->gogo_->add_sink();
}
@@ -1818,6 +1833,22 @@ Parse::init_var(const Typed_identifier& tid, Type* type, Expression* init,
return this->gogo_->add_variable(tid.name(), var);
}
+// Create a dummy global variable to force an initializer to be run in
+// the right place. This is used when a sink variable is initialized
+// at global scope.
+
+Named_object*
+Parse::create_dummy_global(Type* type, Expression* init,
+ source_location location)
+{
+ Variable* var = new Variable(type, init, true, false, false, location);
+ static int count;
+ char buf[30];
+ snprintf(buf, sizeof buf, "_.%d", count);
+ ++count;
+ return this->gogo_->add_variable(buf, var);
+}
+
// SimpleVarDecl = identifier ":=" Expression .
// We've already seen the identifier.
diff --git a/gcc/go/gofrontend/parse.h b/gcc/go/gofrontend/parse.h
index 5f6e26aedea..1fa93195755 100644
--- a/gcc/go/gofrontend/parse.h
+++ b/gcc/go/gofrontend/parse.h
@@ -197,6 +197,7 @@ class Parse
source_location);
Named_object* init_var(const Typed_identifier&, Type*, Expression*,
bool is_coloneq, bool type_from_init, bool* is_new);
+ Named_object* create_dummy_global(Type*, Expression*, source_location);
void simple_var_decl_or_assignment(const std::string&, source_location,
Range_clause*, Type_switch*);
void function_decl();
diff --git a/gcc/go/gofrontend/statements.cc b/gcc/go/gofrontend/statements.cc
index 2c0dba0a11b..b5ded99e158 100644
--- a/gcc/go/gofrontend/statements.cc
+++ b/gcc/go/gofrontend/statements.cc
@@ -299,6 +299,19 @@ Temporary_statement::type() const
return this->type_ != NULL ? this->type_ : this->init_->type();
}
+// Return the tree for the temporary variable.
+
+tree
+Temporary_statement::get_decl() const
+{
+ if (this->decl_ == NULL)
+ {
+ gcc_assert(saw_errors());
+ return error_mark_node;
+ }
+ return this->decl_;
+}
+
// Traversal.
int
@@ -350,7 +363,18 @@ void
Temporary_statement::do_check_types(Gogo*)
{
if (this->type_ != NULL && this->init_ != NULL)
- gcc_assert(Type::are_assignable(this->type_, this->init_->type(), NULL));
+ {
+ std::string reason;
+ if (!Type::are_assignable(this->type_, this->init_->type(), &reason))
+ {
+ if (reason.empty())
+ error_at(this->location(), "incompatible types in assignment");
+ else
+ error_at(this->location(), "incompatible types in assignment (%s)",
+ reason.c_str());
+ this->set_is_error();
+ }
+ }
}
// Return a tree.
@@ -898,6 +922,8 @@ Tuple_map_assignment_statement::do_lower(Gogo*, Block* enclosing)
return Statement::make_error_statement(loc);
}
Map_type* map_type = map_index->get_map_type();
+ if (map_type == NULL)
+ return Statement::make_error_statement(loc);
Block* b = new Block(enclosing, loc);
@@ -1042,6 +1068,8 @@ Map_assignment_statement::do_lower(Gogo*, Block* enclosing)
return Statement::make_error_statement(loc);
}
Map_type* map_type = map_index->get_map_type();
+ if (map_type == NULL)
+ return Statement::make_error_statement(loc);
Block* b = new Block(enclosing, loc);
@@ -2567,6 +2595,8 @@ Return_statement::do_get_tree(Translate_context* context)
{
Function* function = context->function()->func_value();
tree fndecl = function->get_decl();
+ if (fndecl == error_mark_node || DECL_RESULT(fndecl) == error_mark_node)
+ return error_mark_node;
const Typed_identifier_list* results = this->results_;
@@ -2580,6 +2610,8 @@ Return_statement::do_get_tree(Translate_context* context)
tree set;
if (retval == NULL_TREE)
set = NULL_TREE;
+ else if (retval == error_mark_node)
+ return error_mark_node;
else
set = fold_build2_loc(this->location(), MODIFY_EXPR, void_type_node,
DECL_RESULT(fndecl), retval);
@@ -2591,13 +2623,13 @@ Return_statement::do_get_tree(Translate_context* context)
{
gcc_assert(!VOID_TYPE_P(TREE_TYPE(TREE_TYPE(fndecl))));
tree val = (*this->vals_->begin())->get_tree(context);
- if (val == error_mark_node)
- return error_mark_node;
gcc_assert(results != NULL && results->size() == 1);
val = Expression::convert_for_assignment(context,
results->begin()->type(),
(*this->vals_->begin())->type(),
val, this->location());
+ if (val == error_mark_node)
+ return error_mark_node;
tree set = build2(MODIFY_EXPR, void_type_node,
DECL_RESULT(fndecl), val);
SET_EXPR_LOCATION(set, this->location());
@@ -2618,11 +2650,11 @@ Return_statement::do_get_tree(Translate_context* context)
{
gcc_assert(pv != this->vals_->end());
tree val = (*pv)->get_tree(context);
- if (val == error_mark_node)
- return error_mark_node;
val = Expression::convert_for_assignment(context, pr->type(),
(*pv)->type(), val,
this->location());
+ if (val == error_mark_node)
+ return error_mark_node;
tree set = build2(MODIFY_EXPR, void_type_node,
build3(COMPONENT_REF, TREE_TYPE(field),
retvar, field, NULL_TREE),
diff --git a/gcc/go/gofrontend/statements.h b/gcc/go/gofrontend/statements.h
index 6ca586f10a9..80cdffe801e 100644
--- a/gcc/go/gofrontend/statements.h
+++ b/gcc/go/gofrontend/statements.h
@@ -487,11 +487,7 @@ class Temporary_statement : public Statement
// Return the tree for the temporary variable itself. This should
// not be called until after the statement itself has been expanded.
tree
- get_decl() const
- {
- gcc_assert(this->decl_ != NULL);
- return this->decl_;
- }
+ get_decl() const;
protected:
int
diff --git a/gcc/go/gofrontend/types.cc b/gcc/go/gofrontend/types.cc
index af541e8eb51..02165371503 100644
--- a/gcc/go/gofrontend/types.cc
+++ b/gcc/go/gofrontend/types.cc
@@ -543,15 +543,17 @@ Type::are_assignable(const Type* lhs, const Type* rhs, std::string* reason)
|| lhs->interface_type() != NULL))
return true;
- // An untyped constant may be assigned to a numeric type if it is
- // representable in that type.
- if (rhs->is_abstract()
+ // An untyped numeric constant may be assigned to a numeric type if
+ // it is representable in that type.
+ if ((rhs->is_abstract()
+ && (rhs->integer_type() != NULL
+ || rhs->float_type() != NULL
+ || rhs->complex_type() != NULL))
&& (lhs->integer_type() != NULL
|| lhs->float_type() != NULL
|| lhs->complex_type() != NULL))
return true;
-
// Give some better error messages.
if (reason != NULL && reason->empty())
{
@@ -3251,26 +3253,35 @@ class Call_multiple_result_type : public Type
protected:
bool
do_has_pointer() const
- { gcc_unreachable(); }
+ {
+ gcc_assert(saw_errors());
+ return false;
+ }
tree
do_get_tree(Gogo*);
tree
do_get_init_tree(Gogo*, tree, bool)
- { gcc_unreachable(); }
+ {
+ gcc_assert(saw_errors());
+ return error_mark_node;
+ }
Expression*
do_type_descriptor(Gogo*, Named_type*)
- { gcc_unreachable(); }
+ {
+ gcc_assert(saw_errors());
+ return Expression::make_error(UNKNOWN_LOCATION);
+ }
void
do_reflection(Gogo*, std::string*) const
- { gcc_unreachable(); }
+ { gcc_assert(saw_errors()); }
void
do_mangled_name(Gogo*, std::string*) const
- { gcc_unreachable(); }
+ { gcc_assert(saw_errors()); }
private:
// The expression being called.
@@ -3698,6 +3709,8 @@ Struct_type::is_unexported_local_field(Gogo* gogo,
void
Struct_type::finalize_methods(Gogo* gogo)
{
+ if (this->all_methods_ != NULL)
+ return;
Type::finalize_methods(gogo, this, this->location_, &this->all_methods_);
}
@@ -4355,8 +4368,12 @@ Array_type::get_length_tree(Gogo* gogo)
// expression. FIXME: This won't work in general.
Translate_context context(gogo, NULL, NULL, NULL_TREE);
tree len = this->length_->get_tree(&context);
- len = convert_to_integer(integer_type_node, len);
- this->length_tree_ = save_expr(len);
+ if (len != error_mark_node)
+ {
+ len = convert_to_integer(integer_type_node, len);
+ len = save_expr(len);
+ }
+ this->length_tree_ = len;
}
}
return this->length_tree_;
@@ -5540,7 +5557,7 @@ Interface_type::finalize_methods()
const Typed_identifier* p = &this->methods_->at(from);
if (!p->name().empty())
{
- size_t i = 0;
+ size_t i;
for (i = 0; i < to; ++i)
{
if (this->methods_->at(i).name() == p->name())
@@ -5586,7 +5603,30 @@ Interface_type::finalize_methods()
q != methods->end();
++q)
{
- if (q->name().empty() || this->find_method(q->name()) == NULL)
+ if (q->name().empty())
+ {
+ if (q->type() == p->type())
+ error_at(p->location(), "interface inheritance loop");
+ else
+ {
+ size_t i;
+ for (i = from + 1; i < this->methods_->size(); ++i)
+ {
+ const Typed_identifier* r = &this->methods_->at(i);
+ if (r->name().empty() && r->type() == q->type())
+ {
+ error_at(p->location(),
+ "inherited interface listed twice");
+ break;
+ }
+ }
+ if (i == this->methods_->size())
+ this->methods_->push_back(Typed_identifier(q->name(),
+ q->type(),
+ p->location()));
+ }
+ }
+ else if (this->find_method(q->name()) == NULL)
this->methods_->push_back(Typed_identifier(q->name(), q->type(),
p->location()));
else
@@ -6507,22 +6547,22 @@ Named_type::message_name() const
Type*
Named_type::named_base()
{
- if (this->seen_)
+ if (this->seen_ > 0)
return this;
- this->seen_ = true;
+ ++this->seen_;
Type* ret = this->type_->base();
- this->seen_ = false;
+ --this->seen_;
return ret;
}
const Type*
Named_type::named_base() const
{
- if (this->seen_)
+ if (this->seen_ > 0)
return this;
- this->seen_ = true;
+ ++this->seen_;
const Type* ret = this->type_->base();
- this->seen_ = false;
+ --this->seen_;
return ret;
}
@@ -6532,11 +6572,11 @@ Named_type::named_base() const
bool
Named_type::is_named_error_type() const
{
- if (this->seen_)
+ if (this->seen_ > 0)
return false;
- this->seen_ = true;
+ ++this->seen_;
bool ret = this->type_->is_error_type();
- this->seen_ = false;
+ --this->seen_;
return ret;
}
@@ -6615,6 +6655,9 @@ Named_type::is_unexported_local_method(Gogo* gogo,
void
Named_type::finalize_methods(Gogo* gogo)
{
+ if (this->all_methods_ != NULL)
+ return;
+
if (this->local_methods_ != NULL
&& (this->points_to() != NULL || this->interface_type() != NULL))
{
@@ -6683,11 +6726,11 @@ Named_type::interface_method_table(Gogo* gogo, const Interface_type* interface,
bool
Named_type::named_type_has_hidden_fields(std::string* reason) const
{
- if (this->seen_)
+ if (this->seen_ > 0)
return false;
- this->seen_ = true;
+ ++this->seen_;
bool ret = this->type_->has_hidden_fields(this, reason);
- this->seen_ = false;
+ --this->seen_;
return ret;
}
@@ -6819,6 +6862,19 @@ Named_type::do_verify()
return true;
}
+// Return whether this type is or contains a pointer.
+
+bool
+Named_type::do_has_pointer() const
+{
+ if (this->seen_ > 0)
+ return false;
+ ++this->seen_;
+ bool ret = this->type_->has_pointer();
+ --this->seen_;
+ return ret;
+}
+
// Return a hash code. This is used for method lookup. We simply
// hash on the name itself.
@@ -6889,18 +6945,24 @@ Named_type::do_get_tree(Gogo* gogo)
case TYPE_FUNCTION:
// GENERIC can't handle a pointer to a function type whose
// return type is a pointer to the function type itself. It
- // does into infinite loops when walking the types.
- if (this->seen_)
+ // goes into an infinite loop when walking the types.
+ if (this->seen_ > 0)
{
Function_type* fntype = this->type_->function_type();
if (fntype->results() != NULL
&& fntype->results()->size() == 1
&& fntype->results()->front().type()->forwarded() == this)
return ptr_type_node;
+
+ // We can legitimately see ourselves here twice when a named
+ // type is defined using a struct which refers to the named
+ // type. If we see ourselves too often we are in a loop.
+ if (this->seen_ > 3)
+ return ptr_type_node;
}
- this->seen_ = true;
+ ++this->seen_;
t = Type::get_named_type_tree(gogo, this->type_);
- this->seen_ = false;
+ --this->seen_;
if (t == error_mark_node)
return error_mark_node;
t = build_variant_type_copy(t);
@@ -6910,11 +6972,17 @@ Named_type::do_get_tree(Gogo* gogo)
// Don't recur infinitely if a pointer type refers to itself.
// Ideally we would build a circular data structure here, but
// GENERIC can't handle them.
- if (this->seen_)
- return ptr_type_node;
- this->seen_ = true;
+ if (this->seen_ > 0)
+ {
+ if (this->type_->points_to()->forwarded() == this)
+ return ptr_type_node;
+
+ if (this->seen_ > 3)
+ return ptr_type_node;
+ }
+ ++this->seen_;
t = Type::get_named_type_tree(gogo, this->type_);
- this->seen_ = false;
+ --this->seen_;
if (t == error_mark_node)
return error_mark_node;
t = build_variant_type_copy(t);
@@ -6973,11 +7041,10 @@ Named_type::do_get_tree(Gogo* gogo)
// definition of T2 may refer to T1, then we must simply
// return the type for T2 here. It's not precisely correct,
// but it's as close as we can get with GENERIC.
- bool was_seen = this->seen_;
- this->seen_ = true;
+ ++this->seen_;
t = Type::get_named_type_tree(gogo, this->type_);
- this->seen_ = was_seen;
- if (was_seen)
+ --this->seen_;
+ if (this->seen_ > 0)
return t;
if (t == error_mark_node)
return error_mark_node;
@@ -7600,13 +7667,14 @@ Type::bind_field_or_method(Gogo* gogo, const Type* type, Expression* expr,
bool receiver_can_be_pointer = (expr->type()->points_to() != NULL
|| expr->is_addressable());
+ std::vector<const Named_type*> seen;
bool is_method = false;
bool found_pointer_method = false;
std::string ambig1;
std::string ambig2;
- if (Type::find_field_or_method(type, name, receiver_can_be_pointer, NULL,
- &is_method, &found_pointer_method,
- &ambig1, &ambig2))
+ if (Type::find_field_or_method(type, name, receiver_can_be_pointer,
+ &seen, NULL, &is_method,
+ &found_pointer_method, &ambig1, &ambig2))
{
Expression* ret;
if (!is_method)
@@ -7663,8 +7731,10 @@ Type::bind_field_or_method(Gogo* gogo, const Type* type, Expression* expr,
else
{
std::string unpacked = Gogo::unpack_hidden_name(name);
+ seen.clear();
is_unexported = Type::is_unexported_field_or_method(gogo, type,
- unpacked);
+ unpacked,
+ &seen);
}
if (is_unexported)
error_at(location, "reference to unexported field or method %qs",
@@ -7682,13 +7752,16 @@ Type::bind_field_or_method(Gogo* gogo, const Type* type, Expression* expr,
// ambiguity. If a method is found, sets *IS_METHOD to true;
// otherwise, if a field is found, set it to false. If
// RECEIVER_CAN_BE_POINTER is false, then the receiver is a value
-// whose address can not be taken. When returning false, this sets
-// *FOUND_POINTER_METHOD if we found a method we couldn't use because
-// it requires a pointer. LEVEL is used for recursive calls, and can
-// be NULL for a non-recursive call. When this function returns false
-// because it finds that the name is ambiguous, it will store a path
-// to the ambiguous names in *AMBIG1 and *AMBIG2. If the name is not
-// found at all, *AMBIG1 and *AMBIG2 will be unchanged.
+// whose address can not be taken. SEEN is used to avoid infinite
+// recursion on invalid types.
+
+// When returning false, this sets *FOUND_POINTER_METHOD if we found a
+// method we couldn't use because it requires a pointer. LEVEL is
+// used for recursive calls, and can be NULL for a non-recursive call.
+// When this function returns false because it finds that the name is
+// ambiguous, it will store a path to the ambiguous names in *AMBIG1
+// and *AMBIG2. If the name is not found at all, *AMBIG1 and *AMBIG2
+// will be unchanged.
// This function just returns whether or not there is a field or
// method, and whether it is a field or method. It doesn't build an
@@ -7701,6 +7774,7 @@ bool
Type::find_field_or_method(const Type* type,
const std::string& name,
bool receiver_can_be_pointer,
+ std::vector<const Named_type*>* seen,
int* level,
bool* is_method,
bool* found_pointer_method,
@@ -7727,6 +7801,17 @@ Type::find_field_or_method(const Type* type,
// else.
*found_pointer_method = true;
}
+
+ for (std::vector<const Named_type*>::const_iterator p = seen->begin();
+ p != seen->end();
+ ++p)
+ {
+ if (*p == nt)
+ {
+ // We've already seen this type when searching for methods.
+ return false;
+ }
+ }
}
// Interface types can have methods.
@@ -7746,6 +7831,9 @@ Type::find_field_or_method(const Type* type,
if (fields == NULL)
return false;
+ if (nt != NULL)
+ seen->push_back(nt);
+
int found_level = 0;
bool found_is_method = false;
std::string found_ambig1;
@@ -7758,6 +7846,8 @@ Type::find_field_or_method(const Type* type,
if (pf->field_name() == name)
{
*is_method = false;
+ if (nt != NULL)
+ seen->pop_back();
return true;
}
@@ -7778,6 +7868,7 @@ Type::find_field_or_method(const Type* type,
bool subfound = Type::find_field_or_method(fnt,
name,
receiver_can_be_pointer,
+ seen,
&sublevel,
&sub_is_method,
found_pointer_method,
@@ -7834,6 +7925,9 @@ Type::find_field_or_method(const Type* type,
// FOUND_AMBIG2 are not empty. If we found the field, FOUND_LEVEL
// is not 0 and FOUND_AMBIG1 and FOUND_AMBIG2 are empty.
+ if (nt != NULL)
+ seen->pop_back();
+
if (found_level == 0)
return false;
else if (!found_ambig1.empty())
@@ -7858,13 +7952,28 @@ Type::find_field_or_method(const Type* type,
bool
Type::is_unexported_field_or_method(Gogo* gogo, const Type* type,
- const std::string& name)
+ const std::string& name,
+ std::vector<const Named_type*>* seen)
{
type = type->deref();
const Named_type* nt = type->named_type();
- if (nt != NULL && nt->is_unexported_local_method(gogo, name))
- return true;
+ if (nt != NULL)
+ {
+ if (nt->is_unexported_local_method(gogo, name))
+ return true;
+
+ for (std::vector<const Named_type*>::const_iterator p = seen->begin();
+ p != seen->end();
+ ++p)
+ {
+ if (*p == nt)
+ {
+ // We've already seen this type.
+ return false;
+ }
+ }
+ }
const Interface_type* it = type->interface_type();
if (it != NULL && it->is_unexported_method(gogo, name))
@@ -7881,6 +7990,9 @@ Type::is_unexported_field_or_method(Gogo* gogo, const Type* type,
if (fields == NULL)
return false;
+ if (nt != NULL)
+ seen->push_back(nt);
+
for (Struct_field_list::const_iterator pf = fields->begin();
pf != fields->end();
++pf)
@@ -7891,11 +8003,18 @@ Type::is_unexported_field_or_method(Gogo* gogo, const Type* type,
{
Named_type* subtype = pf->type()->deref()->named_type();
gcc_assert(subtype != NULL);
- if (Type::is_unexported_field_or_method(gogo, subtype, name))
- return true;
+ if (Type::is_unexported_field_or_method(gogo, subtype, name, seen))
+ {
+ if (nt != NULL)
+ seen->pop_back();
+ return true;
+ }
}
}
+ if (nt != NULL)
+ seen->pop_back();
+
return false;
}
@@ -8013,7 +8132,8 @@ Forward_declaration_type::add_method(const std::string& name,
Function* function)
{
Named_object* no = this->named_object();
- gcc_assert(no->is_type_declaration());
+ if (no->is_unknown())
+ no->declare_as_type();
return no->type_declaration_value()->add_method(name, function);
}
@@ -8026,7 +8146,8 @@ Forward_declaration_type::add_method_declaration(const std::string& name,
source_location location)
{
Named_object* no = this->named_object();
- gcc_assert(no->is_type_declaration());
+ if (no->is_unknown())
+ no->declare_as_type();
Type_declaration* td = no->type_declaration_value();
return td->add_method_declaration(name, type, location);
}
@@ -8061,6 +8182,7 @@ Forward_declaration_type::do_get_tree(Gogo* gogo)
tree id = no->get_id(gogo);
tree decl = build_decl(no->location(), TYPE_DECL, id, type_tree);
TYPE_NAME(type_tree) = decl;
+ layout_type(type_tree);
return type_tree;
}
diff --git a/gcc/go/gofrontend/types.h b/gcc/go/gofrontend/types.h
index 2a713b067d4..cecf106e448 100644
--- a/gcc/go/gofrontend/types.h
+++ b/gcc/go/gofrontend/types.h
@@ -791,7 +791,8 @@ class Type
// Return true if NAME is an unexported field or method of TYPE.
static bool
- is_unexported_field_or_method(Gogo*, const Type*, const std::string&);
+ is_unexported_field_or_method(Gogo*, const Type*, const std::string&,
+ std::vector<const Named_type*>*);
// This type was passed to the builtin function make. ARGS are the
// arguments passed to make after the type; this may be NULL if
@@ -1067,8 +1068,8 @@ class Type
static bool
find_field_or_method(const Type* type, const std::string& name,
bool receiver_can_be_pointer,
- int* level, bool* is_method,
- bool* found_pointer_method,
+ std::vector<const Named_type*>*, int* level,
+ bool* is_method, bool* found_pointer_method,
std::string* ambig1, std::string* ambig2);
// Get a tree for a type without looking in the hash table for
@@ -2387,7 +2388,7 @@ class Named_type : public Type
local_methods_(NULL), all_methods_(NULL),
interface_method_tables_(NULL), pointer_interface_method_tables_(NULL),
location_(location), named_tree_(NULL), is_visible_(true),
- is_error_(false), seen_(false)
+ is_error_(false), seen_(0)
{ }
// Return the associated Named_object. This holds the actual name.
@@ -2551,8 +2552,7 @@ class Named_type : public Type
do_verify();
bool
- do_has_pointer() const
- { return this->type_->has_pointer(); }
+ do_has_pointer() const;
unsigned int
do_hash_for_method(Gogo*) const;
@@ -2626,7 +2626,7 @@ class Named_type : public Type
// used to prevent infinite recursion when a type refers to itself.
// This is mutable because it is always reset to false when the
// function exits.
- mutable bool seen_;
+ mutable int seen_;
};
// A forward declaration. This handles a type which has been declared
@@ -2676,7 +2676,7 @@ class Forward_declaration_type : public Type
bool
do_has_pointer() const
- { return this->base()->has_pointer(); }
+ { return this->real_type()->has_pointer(); }
unsigned int
do_hash_for_method(Gogo* gogo) const