diff options
author | bstarynk <bstarynk@138bc75d-0d04-0410-961f-82ee72b054a4> | 2011-01-03 12:17:59 +0000 |
---|---|---|
committer | bstarynk <bstarynk@138bc75d-0d04-0410-961f-82ee72b054a4> | 2011-01-03 12:17:59 +0000 |
commit | 73556f5f6c5d835df3baa9979de74da7bd85cd05 (patch) | |
tree | ac76e75c45976914468f05d9d01c6dab44ff831c /gcc/go | |
parent | 009b254c18c50184aadbc41673222104cec47838 (diff) | |
download | gcc-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/ChangeLog | 12 | ||||
-rw-r--r-- | gcc/go/Make-lang.in | 6 | ||||
-rw-r--r-- | gcc/go/go-backend.c | 2 | ||||
-rw-r--r-- | gcc/go/gofrontend/expressions.cc | 195 | ||||
-rw-r--r-- | gcc/go/gofrontend/expressions.h | 7 | ||||
-rw-r--r-- | gcc/go/gofrontend/gogo-tree.cc | 26 | ||||
-rw-r--r-- | gcc/go/gofrontend/gogo.cc | 91 | ||||
-rw-r--r-- | gcc/go/gofrontend/gogo.h | 15 | ||||
-rw-r--r-- | gcc/go/gofrontend/lex.cc | 50 | ||||
-rw-r--r-- | gcc/go/gofrontend/lex.h | 3 | ||||
-rw-r--r-- | gcc/go/gofrontend/parse.cc | 59 | ||||
-rw-r--r-- | gcc/go/gofrontend/parse.h | 1 | ||||
-rw-r--r-- | gcc/go/gofrontend/statements.cc | 42 | ||||
-rw-r--r-- | gcc/go/gofrontend/statements.h | 6 | ||||
-rw-r--r-- | gcc/go/gofrontend/types.cc | 232 | ||||
-rw-r--r-- | gcc/go/gofrontend/types.h | 16 |
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 |