summaryrefslogtreecommitdiff
path: root/gcc/go
diff options
context:
space:
mode:
authorbstarynk <bstarynk@138bc75d-0d04-0410-961f-82ee72b054a4>2010-12-20 21:46:40 +0000
committerbstarynk <bstarynk@138bc75d-0d04-0410-961f-82ee72b054a4>2010-12-20 21:46:40 +0000
commitb08e05713256fbd8a2a414b56c82d1651aadb985 (patch)
tree31bad5c89150cded27efde181d7eee13ce078edb /gcc/go
parent79bd8aab8f7dedd773f23cbf2c109d9f77cd47d7 (diff)
downloadgcc-b08e05713256fbd8a2a414b56c82d1651aadb985.tar.gz
2010-12-20 Basile Starynkevitch <basile@starynkevitch.net>
MELT branch merged with trunk rev 168094 git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/melt-branch@168096 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/go')
-rw-r--r--gcc/go/gofrontend/expressions.cc267
-rw-r--r--gcc/go/gofrontend/expressions.h5
-rw-r--r--gcc/go/gofrontend/gogo-tree.cc25
-rw-r--r--gcc/go/gofrontend/gogo.cc78
-rw-r--r--gcc/go/gofrontend/gogo.h7
-rw-r--r--gcc/go/gofrontend/parse.cc7
-rw-r--r--gcc/go/gofrontend/statements.cc22
-rw-r--r--gcc/go/gofrontend/types.cc158
-rw-r--r--gcc/go/gofrontend/types.h27
9 files changed, 442 insertions, 154 deletions
diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc
index 2bbb11e6c3f..39baf9d1c15 100644
--- a/gcc/go/gofrontend/expressions.cc
+++ b/gcc/go/gofrontend/expressions.cc
@@ -505,6 +505,8 @@ Expression::convert_interface_to_interface(Translate_context* context,
lhs_type_descriptor,
TREE_TYPE(rhs_type_descriptor),
rhs_type_descriptor);
+ if (call == error_mark_node)
+ return error_mark_node;
// This will panic if the interface conversion fails.
TREE_NOTHROW(assert_interface_decl) = 0;
elt->value = fold_convert_loc(location, TREE_TYPE(field), call);
@@ -535,6 +537,8 @@ Expression::convert_interface_to_interface(Translate_context* context,
lhs_type_descriptor,
TREE_TYPE(rhs_type_descriptor),
rhs_type_descriptor);
+ if (call == error_mark_node)
+ return error_mark_node;
// This will panic if the interface conversion fails.
TREE_NOTHROW(convert_interface_decl) = 0;
elt->value = fold_convert_loc(location, TREE_TYPE(field), call);
@@ -599,6 +603,8 @@ Expression::convert_interface_to_type(Translate_context* context,
rhs_type_descriptor,
TREE_TYPE(rhs_inter_descriptor),
rhs_inter_descriptor);
+ if (call == error_mark_node)
+ return error_mark_node;
// This call will panic if the conversion is invalid.
TREE_NOTHROW(check_interface_type_decl) = 0;
@@ -2279,6 +2285,32 @@ Expression::make_complex(const mpfr_t* real, const mpfr_t* imag, Type* type,
return new Complex_expression(real, imag, type, location);
}
+// Find a named object in an expression.
+
+class Find_named_object : public Traverse
+{
+ public:
+ Find_named_object(Named_object* no)
+ : Traverse(traverse_expressions),
+ no_(no), found_(false)
+ { }
+
+ // Whether we found the object.
+ bool
+ found() const
+ { return this->found_; }
+
+ protected:
+ int
+ expression(Expression**);
+
+ private:
+ // The object we are looking for.
+ Named_object* no_;
+ // Whether we found it.
+ bool found_;
+};
+
// A reference to a const in an expression.
class Const_expression : public Expression
@@ -2286,9 +2318,13 @@ class Const_expression : public Expression
public:
Const_expression(Named_object* constant, source_location location)
: Expression(EXPRESSION_CONST_REFERENCE, location),
- constant_(constant), type_(NULL)
+ constant_(constant), type_(NULL), seen_(false)
{ }
+ Named_object*
+ named_object()
+ { return this->constant_; }
+
const std::string&
name() const
{ return this->constant_->name(); }
@@ -2344,6 +2380,9 @@ class Const_expression : public Expression
// The type of this reference. This is used if the constant has an
// abstract type.
Type* type_;
+ // Used to prevent infinite recursion when a constant incorrectly
+ // refers to itself.
+ mutable bool seen_;
};
// Lower a constant expression. This is where we convert the
@@ -2381,6 +2420,9 @@ bool
Const_expression::do_integer_constant_value(bool iota_is_constant, mpz_t val,
Type** ptype) const
{
+ if (this->seen_)
+ return false;
+
Type* ctype;
if (this->type_ != NULL)
ctype = this->type_;
@@ -2390,9 +2432,14 @@ Const_expression::do_integer_constant_value(bool iota_is_constant, mpz_t val,
return false;
Expression* e = this->constant_->const_value()->expr();
+
+ this->seen_ = true;
+
Type* t;
bool r = e->integer_constant_value(iota_is_constant, val, &t);
+ this->seen_ = false;
+
if (r
&& ctype != NULL
&& !Integer_expression::check_constant(val, ctype, this->location()))
@@ -2407,6 +2454,9 @@ Const_expression::do_integer_constant_value(bool iota_is_constant, mpz_t val,
bool
Const_expression::do_float_constant_value(mpfr_t val, Type** ptype) const
{
+ if (this->seen_)
+ return false;
+
Type* ctype;
if (this->type_ != NULL)
ctype = this->type_;
@@ -2415,9 +2465,14 @@ Const_expression::do_float_constant_value(mpfr_t val, Type** ptype) const
if (ctype != NULL && ctype->float_type() == NULL)
return false;
+ this->seen_ = true;
+
Type* t;
bool r = this->constant_->const_value()->expr()->float_constant_value(val,
&t);
+
+ this->seen_ = false;
+
if (r && ctype != NULL)
{
if (!Float_expression::check_constant(val, ctype, this->location()))
@@ -2434,6 +2489,9 @@ bool
Const_expression::do_complex_constant_value(mpfr_t real, mpfr_t imag,
Type **ptype) const
{
+ if (this->seen_)
+ return false;
+
Type* ctype;
if (this->type_ != NULL)
ctype = this->type_;
@@ -2442,10 +2500,15 @@ Const_expression::do_complex_constant_value(mpfr_t real, mpfr_t imag,
if (ctype != NULL && ctype->complex_type() == NULL)
return false;
+ this->seen_ = true;
+
Type *t;
bool r = this->constant_->const_value()->expr()->complex_constant_value(real,
imag,
&t);
+
+ this->seen_ = false;
+
if (r && ctype != NULL)
{
if (!Complex_expression::check_constant(real, imag, ctype,
@@ -2464,13 +2527,32 @@ Const_expression::do_type()
{
if (this->type_ != NULL)
return this->type_;
+
+ if (this->seen_)
+ {
+ this->report_error(_("constant refers to itself"));
+ this->type_ = Type::make_error_type();
+ return this->type_;
+ }
+
+ this->seen_ = true;
+
Named_constant* nc = this->constant_->const_value();
Type* ret = nc->type();
+
if (ret != NULL)
- return ret;
+ {
+ this->seen_ = false;
+ return ret;
+ }
+
// During parsing, a named constant may have a NULL type, but we
// must not return a NULL type here.
- return nc->expr()->type();
+ ret = nc->expr()->type();
+
+ this->seen_ = false;
+
+ return ret;
}
// Set the type of the const reference.
@@ -2513,6 +2595,19 @@ Const_expression::do_determine_type(const Type_context* context)
void
Const_expression::do_check_types(Gogo*)
{
+ if (this->type_ != NULL && this->type_->is_error_type())
+ return;
+
+ Expression* init = this->constant_->const_value()->expr();
+ Find_named_object find_named_object(this->constant_);
+ Expression::traverse(&init, &find_named_object);
+ if (find_named_object.found())
+ {
+ this->report_error(_("constant refers to itself"));
+ this->type_ = Type::make_error_type();
+ return;
+ }
+
if (this->type_ == NULL || this->type_->is_abstract())
return;
@@ -2630,6 +2725,32 @@ Expression::make_const_reference(Named_object* constant,
return new Const_expression(constant, location);
}
+// Find a named object in an expression.
+
+int
+Find_named_object::expression(Expression** pexpr)
+{
+ switch ((*pexpr)->classification())
+ {
+ case Expression::EXPRESSION_CONST_REFERENCE:
+ if (static_cast<Const_expression*>(*pexpr)->named_object() == this->no_)
+ break;
+ return TRAVERSE_CONTINUE;
+ case Expression::EXPRESSION_VAR_REFERENCE:
+ if ((*pexpr)->var_expression()->named_object() == this->no_)
+ break;
+ return TRAVERSE_CONTINUE;
+ case Expression::EXPRESSION_FUNC_REFERENCE:
+ if ((*pexpr)->func_expression()->named_object() == this->no_)
+ break;
+ return TRAVERSE_CONTINUE;
+ default:
+ return TRAVERSE_CONTINUE;
+ }
+ this->found_ = true;
+ return TRAVERSE_EXIT;
+}
+
// The nil value.
class Nil_expression : public Expression
@@ -6012,6 +6133,8 @@ Expression::comparison_tree(Translate_context* context, Operator op,
descriptor,
ptr_type_node,
arg);
+ if (left_tree == error_mark_node)
+ return error_mark_node;
// This can panic if the type is not comparable.
TREE_NOTHROW(empty_interface_value_compare_decl) = 0;
}
@@ -6029,6 +6152,8 @@ Expression::comparison_tree(Translate_context* context, Operator op,
descriptor,
ptr_type_node,
arg);
+ if (left_tree == error_mark_node)
+ return error_mark_node;
// This can panic if the type is not comparable.
TREE_NOTHROW(interface_value_compare_decl) = 0;
}
@@ -6054,6 +6179,8 @@ Expression::comparison_tree(Translate_context* context, Operator op,
left_tree,
TREE_TYPE(right_tree),
right_tree);
+ if (left_tree == error_mark_node)
+ return error_mark_node;
// This can panic if the type is uncomparable.
TREE_NOTHROW(empty_interface_compare_decl) = 0;
}
@@ -6070,6 +6197,8 @@ Expression::comparison_tree(Translate_context* context, Operator op,
left_tree,
TREE_TYPE(right_tree),
right_tree);
+ if (left_tree == error_mark_node)
+ return error_mark_node;
// This can panic if the type is uncomparable.
TREE_NOTHROW(interface_compare_decl) = 0;
}
@@ -6109,6 +6238,9 @@ Expression::comparison_tree(Translate_context* context, Operator op,
}
}
+ if (left_tree == error_mark_node || right_tree == error_mark_node)
+ return error_mark_node;
+
tree ret = fold_build2(code, boolean_type_node, left_tree, right_tree);
if (CAN_HAVE_LOCATION_P(ret))
SET_EXPR_LOCATION(ret, location);
@@ -6172,7 +6304,7 @@ Bound_method_expression::do_check_types(Gogo*)
? this->expr_type_
: this->expr_->type());
etype = etype->deref();
- if (!Type::are_identical(rtype, etype, NULL))
+ if (!Type::are_identical(rtype, etype, true, NULL))
this->report_error(_("method type does not match object type"));
}
}
@@ -6719,7 +6851,7 @@ Builtin_call_expression::do_integer_constant_value(bool iota_is_constant,
if (arg == NULL)
return false;
Type* arg_type = arg->type();
- if (arg_type->is_error_type())
+ if (arg_type->is_error_type() || arg_type->is_undefined())
return false;
if (arg_type->is_abstract())
return false;
@@ -6849,7 +6981,7 @@ Builtin_call_expression::do_complex_constant_value(mpfr_t real, mpfr_t imag,
bool ret = false;
Type* itype;
if (args->back()->float_constant_value(i, &itype)
- && Type::are_identical(rtype, itype, NULL))
+ && Type::are_identical(rtype, itype, false, NULL))
{
mpfr_set(real, r, GMP_RNDN);
mpfr_set(imag, i, GMP_RNDN);
@@ -7066,7 +7198,8 @@ Builtin_call_expression::check_one_arg()
return false;
}
if (args->front()->is_error_expression()
- || args->front()->type()->is_error_type())
+ || args->front()->type()->is_error_type()
+ || args->front()->type()->is_undefined())
{
this->set_is_error();
return false;
@@ -7228,7 +7361,7 @@ Builtin_call_expression::do_check_types(Gogo*)
break;
}
- if (!Type::are_identical(e1, e2, NULL))
+ if (!Type::are_identical(e1, e2, true, NULL))
this->report_error(_("element types must be the same"));
}
break;
@@ -7282,7 +7415,7 @@ Builtin_call_expression::do_check_types(Gogo*)
|| args->back()->type()->is_error_type())
this->set_is_error();
else if (!Type::are_identical(args->front()->type(),
- args->back()->type(), NULL))
+ args->back()->type(), true, NULL))
this->report_error(_("cmplx arguments must have identical types"));
else if (args->front()->type()->float_type() == NULL)
this->report_error(_("cmplx arguments must have "
@@ -7380,6 +7513,9 @@ Builtin_call_expression::do_get_tree(Translate_context* context)
gcc_unreachable();
}
+ if (val_tree == error_mark_node)
+ return error_mark_node;
+
tree type_tree = Type::lookup_integer_type("int")->get_tree(gogo);
if (type_tree == TREE_TYPE(val_tree))
return val_tree;
@@ -7408,6 +7544,8 @@ Builtin_call_expression::do_get_tree(Translate_context* context)
"__go_print_space",
0,
void_type_node);
+ if (call == error_mark_node)
+ return error_mark_node;
append_to_statement_list(call, &stmt_list);
}
@@ -7506,6 +7644,8 @@ Builtin_call_expression::do_get_tree(Translate_context* context)
void_type_node,
TREE_TYPE(arg),
arg);
+ if (call == error_mark_node)
+ return error_mark_node;
append_to_statement_list(call, &stmt_list);
}
}
@@ -7518,6 +7658,8 @@ Builtin_call_expression::do_get_tree(Translate_context* context)
"__go_print_nl",
0,
void_type_node);
+ if (call == error_mark_node)
+ return error_mark_node;
append_to_statement_list(call, &stmt_list);
}
@@ -7544,6 +7686,8 @@ Builtin_call_expression::do_get_tree(Translate_context* context)
void_type_node,
TREE_TYPE(arg_tree),
arg_tree);
+ if (call == error_mark_node)
+ return error_mark_node;
// This function will throw an exception.
TREE_NOTHROW(panic_fndecl) = 0;
// This function will not return.
@@ -7596,6 +7740,8 @@ Builtin_call_expression::do_get_tree(Translate_context* context)
0,
empty_tree);
}
+ if (call == error_mark_node)
+ return error_mark_node;
return fold_build3_loc(location, COND_EXPR, empty_tree, arg_tree,
call, empty_nil_tree);
}
@@ -7665,6 +7811,8 @@ Builtin_call_expression::do_get_tree(Translate_context* context)
arg1_tree = save_expr(arg1_tree);
tree arg1_val = at->value_pointer_tree(gogo, arg1_tree);
tree arg1_len = at->length_tree(gogo, arg1_tree);
+ if (arg1_val == error_mark_node || arg1_len == error_mark_node)
+ return error_mark_node;
Type* arg2_type = arg2->type();
tree arg2_val;
@@ -7682,6 +7830,8 @@ Builtin_call_expression::do_get_tree(Translate_context* context)
arg2_val = String_type::bytes_tree(gogo, arg2_tree);
arg2_len = String_type::length_tree(gogo, arg2_tree);
}
+ if (arg2_val == error_mark_node || arg2_len == error_mark_node)
+ return error_mark_node;
arg1_len = save_expr(arg1_len);
arg2_len = save_expr(arg2_len);
@@ -7694,6 +7844,8 @@ Builtin_call_expression::do_get_tree(Translate_context* context)
Type* element_type = at->element_type();
tree element_type_tree = element_type->get_tree(gogo);
+ if (element_type_tree == error_mark_node)
+ return error_mark_node;
tree element_size = TYPE_SIZE_UNIT(element_type_tree);
tree bytecount = fold_convert_loc(location, TREE_TYPE(element_size),
len);
@@ -7702,9 +7854,23 @@ Builtin_call_expression::do_get_tree(Translate_context* context)
bytecount, element_size);
bytecount = fold_convert_loc(location, size_type_node, bytecount);
- tree call = build_call_expr_loc(location,
- built_in_decls[BUILT_IN_MEMMOVE],
- 3, arg1_val, arg2_val, bytecount);
+ arg1_val = fold_convert_loc(location, ptr_type_node, arg1_val);
+ arg2_val = fold_convert_loc(location, ptr_type_node, arg2_val);
+
+ static tree copy_fndecl;
+ tree call = Gogo::call_builtin(&copy_fndecl,
+ location,
+ "__go_copy",
+ 3,
+ void_type_node,
+ ptr_type_node,
+ arg1_val,
+ ptr_type_node,
+ arg2_val,
+ size_type_node,
+ bytecount);
+ if (call == error_mark_node)
+ return error_mark_node;
return fold_build2_loc(location, COMPOUND_EXPR, TREE_TYPE(len),
call, len);
@@ -7717,12 +7883,29 @@ Builtin_call_expression::do_get_tree(Translate_context* context)
Expression* arg1 = args->front();
Expression* arg2 = args->back();
+ Array_type* at = arg1->type()->array_type();
+ Type* element_type = at->element_type();
+
tree arg1_tree = arg1->get_tree(context);
tree arg2_tree = arg2->get_tree(context);
if (arg1_tree == error_mark_node || arg2_tree == error_mark_node)
return error_mark_node;
- tree descriptor_tree = arg1->type()->type_descriptor_pointer(gogo);
+ Array_type* at2 = arg2->type()->array_type();
+ 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);
+ 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);
+ arg2_len = fold_convert_loc(location, size_type_node, arg2_len);
+
+ tree element_type_tree = element_type->get_tree(gogo);
+ if (element_type_tree == error_mark_node)
+ return error_mark_node;
+ tree element_size = TYPE_SIZE_UNIT(element_type_tree);
+ element_size = fold_convert_loc(location, size_type_node,
+ element_size);
// We rebuild the decl each time since the slice types may
// change.
@@ -7730,14 +7913,16 @@ Builtin_call_expression::do_get_tree(Translate_context* context)
return Gogo::call_builtin(&append_fndecl,
location,
"__go_append",
- 3,
+ 4,
TREE_TYPE(arg1_tree),
- TREE_TYPE(descriptor_tree),
- descriptor_tree,
TREE_TYPE(arg1_tree),
arg1_tree,
- TREE_TYPE(arg2_tree),
- arg2_tree);
+ ptr_type_node,
+ arg2_val,
+ size_type_node,
+ arg2_len,
+ size_type_node,
+ element_size);
}
case BUILTIN_REAL:
@@ -8085,7 +8270,7 @@ Call_expression::is_compatible_varargs_argument(Named_object* function,
Array_type* param_at = param_type->array_type();
if (param_at != NULL
&& Type::are_identical(var_at->element_type(),
- param_at->element_type(), NULL))
+ param_at->element_type(), true, NULL))
return true;
error_at(arg->location(), "... mismatch: passing ...T as ...");
*issued_error = true;
@@ -8618,6 +8803,9 @@ Call_result_expression::do_traverse(Traverse* traverse)
Type*
Call_result_expression::do_type()
{
+ if (this->classification() == EXPRESSION_ERROR)
+ return Type::make_error_type();
+
// THIS->CALL_ can be replaced with a temporary reference due to
// Call_expression::do_must_eval_in_order when there is an error.
Call_expression* ce = this->call_->call_expression();
@@ -8631,34 +8819,25 @@ Call_result_expression::do_type()
for (unsigned int i = 0; i < this->index_; ++i)
{
if (pr == results->end())
- return Type::make_error_type();
+ break;
++pr;
}
if (pr == results->end())
- return Type::make_error_type();
+ {
+ this->report_error(_("number of results does not match "
+ "number of values"));
+ return Type::make_error_type();
+ }
return pr->type();
}
-// Check the type. This is where we give an error if we're trying to
-// extract too many values from a call.
+// Check the type. Just make sure that we trigger the warning in
+// do_type.
void
Call_result_expression::do_check_types(Gogo*)
{
- bool ok = true;
- Call_expression* ce = this->call_->call_expression();
- if (ce != NULL)
- ok = this->index_ < ce->result_count();
- else
- {
- // This can happen when the call returns a single value but we
- // are asking for the second result.
- if (this->call_->is_error_expression())
- return;
- ok = false;
- }
- if (!ok)
- this->report_error(_("number of results does not match number of values"));
+ this->type();
}
// Determine the type. We have nothing to do here, but the 0 result
@@ -9390,6 +9569,8 @@ String_index_expression::do_get_tree(Translate_context* context)
start_tree,
length_type,
end_tree);
+ if (ret == error_mark_node)
+ return error_mark_node;
// This will panic if the bounds are out of range for the
// string.
TREE_NOTHROW(strslice_fndecl) = 0;
@@ -9559,6 +9740,8 @@ Map_index_expression::get_value_pointer(Translate_context* context,
(insert
? boolean_true_node
: boolean_false_node));
+ if (call == error_mark_node)
+ return error_mark_node;
// This can panic on a map of interface type if the interface holds
// an uncomparable or unhashable type.
TREE_NOTHROW(map_index_fndecl) = 0;
@@ -9615,7 +9798,13 @@ Field_reference_expression::do_get_tree(Translate_context* context)
return error_mark_node;
gcc_assert(TREE_CODE(TREE_TYPE(struct_tree)) == RECORD_TYPE);
tree field = TYPE_FIELDS(TREE_TYPE(struct_tree));
- gcc_assert(field != NULL_TREE);
+ if (field == NULL_TREE)
+ {
+ // This can happen for a type which refers to itself indirectly
+ // and then turns out to be erroneous.
+ gcc_assert(saw_errors());
+ return error_mark_node;
+ }
for (unsigned int i = this->field_index_; i > 0; --i)
{
field = DECL_CHAIN(field);
@@ -11109,6 +11298,8 @@ Map_construction_expression::do_get_tree(Translate_context* context)
TYPE_SIZE_UNIT(TREE_TYPE(val_field)),
const_ptr_type_node,
fold_convert(const_ptr_type_node, valaddr));
+ if (call == error_mark_node)
+ return error_mark_node;
tree ret;
if (make_tmp == NULL)
diff --git a/gcc/go/gofrontend/expressions.h b/gcc/go/gofrontend/expressions.h
index 53cca06d42e..5d7d90bdb01 100644
--- a/gcc/go/gofrontend/expressions.h
+++ b/gcc/go/gofrontend/expressions.h
@@ -1235,7 +1235,10 @@ class Call_expression : public Expression
Expression*
do_copy()
{
- return Expression::make_call(this->fn_->copy(), this->args_->copy(),
+ return Expression::make_call(this->fn_->copy(),
+ (this->args_ == NULL
+ ? NULL
+ : this->args_->copy()),
this->is_varargs_, this->location());
}
diff --git a/gcc/go/gofrontend/gogo-tree.cc b/gcc/go/gofrontend/gogo-tree.cc
index 67f9949f695..e43f64d7e1a 100644
--- a/gcc/go/gofrontend/gogo-tree.cc
+++ b/gcc/go/gofrontend/gogo-tree.cc
@@ -341,7 +341,8 @@ Gogo::register_gc_vars(const std::vector<Named_object*>& var_gc,
void_type_node,
build_pointer_type(root_list_type),
build_fold_addr_expr(decl));
- append_to_statement_list(call, init_stmt_list);
+ if (call != error_mark_node)
+ append_to_statement_list(call, init_stmt_list);
}
// Build the decl for the initialization function.
@@ -1684,7 +1685,8 @@ Function::build_defer_wrapper(Gogo* gogo, Named_object* named_function,
void_type_node,
ptr_type_node,
this->defer_stack(end_loc));
- append_to_statement_list(call, &stmt_list);
+ if (call != error_mark_node)
+ append_to_statement_list(call, &stmt_list);
tree retval = this->return_value(gogo, named_function, end_loc, &stmt_list);
tree set;
@@ -1723,7 +1725,8 @@ Function::build_defer_wrapper(Gogo* gogo, Named_object* named_function,
void_type_node,
ptr_type_node,
this->defer_stack(end_loc));
- TREE_NOTHROW(undefer_fndecl) = 0;
+ if (undefer_fndecl != NULL_TREE)
+ TREE_NOTHROW(undefer_fndecl) = 0;
tree defer = Gogo::call_builtin(&check_fndecl,
end_loc,
@@ -2867,6 +2870,8 @@ Gogo::runtime_error(int code, source_location location)
void_type_node,
integer_type_node,
build_int_cst(integer_type_node, code));
+ if (ret == error_mark_node)
+ return error_mark_node;
// The runtime error function panics and does not return.
TREE_NOTHROW(runtime_error_fndecl) = 0;
TREE_THIS_VOLATILE(runtime_error_fndecl) = 1;
@@ -2904,6 +2909,8 @@ Gogo::send_on_channel(tree channel, tree val, bool blocking, bool for_select,
(for_select
? boolean_true_node
: boolean_false_node));
+ if (ret == error_mark_node)
+ return error_mark_node;
// This can panic if there are too many operations on a
// closed channel.
TREE_NOTHROW(send_small_fndecl) = 0;
@@ -2922,6 +2929,8 @@ Gogo::send_on_channel(tree channel, tree val, bool blocking, bool for_select,
channel,
uint64_type_node,
val);
+ if (ret == error_mark_node)
+ return error_mark_node;
// This can panic if there are too many operations on a
// closed channel.
TREE_NOTHROW(send_nonblocking_small_fndecl) = 0;
@@ -2967,6 +2976,8 @@ Gogo::send_on_channel(tree channel, tree val, bool blocking, bool for_select,
(for_select
? boolean_true_node
: boolean_false_node));
+ if (call == error_mark_node)
+ return error_mark_node;
// This can panic if there are too many operations on a
// closed channel.
TREE_NOTHROW(send_big_fndecl) = 0;
@@ -2984,6 +2995,8 @@ Gogo::send_on_channel(tree channel, tree val, bool blocking, bool for_select,
channel,
ptr_type_node,
val);
+ if (call == error_mark_node)
+ return error_mark_node;
// This can panic if there are too many operations on a
// closed channel.
TREE_NOTHROW(send_nonblocking_big_fndecl) = 0;
@@ -3025,6 +3038,8 @@ Gogo::receive_from_channel(tree type_tree, tree channel, bool for_select,
(for_select
? boolean_true_node
: boolean_false_node));
+ if (call == error_mark_node)
+ return error_mark_node;
// This can panic if there are too many operations on a closed
// channel.
TREE_NOTHROW(receive_small_fndecl) = 0;
@@ -3057,6 +3072,8 @@ Gogo::receive_from_channel(tree type_tree, tree channel, bool for_select,
(for_select
? boolean_true_node
: boolean_false_node));
+ if (call == error_mark_node)
+ return error_mark_node;
// This can panic if there are too many operations on a closed
// channel.
TREE_NOTHROW(receive_big_fndecl) = 0;
@@ -3114,6 +3131,8 @@ Gogo::make_trampoline(tree fnaddr, tree closure, source_location location)
ptr_type_node,
fold_convert_loc(location, ptr_type_node,
closure));
+ if (x == error_mark_node)
+ return error_mark_node;
x = save_expr(x);
diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc
index 3a76adb7792..d8d704d956e 100644
--- a/gcc/go/gofrontend/gogo.cc
+++ b/gcc/go/gofrontend/gogo.cc
@@ -640,7 +640,7 @@ Gogo::start_function(const std::string& name, Function_type* type,
}
}
- function->create_named_result_variables();
+ function->create_named_result_variables(this);
const std::string* pname;
std::string nested_name;
@@ -1472,7 +1472,8 @@ Check_types_traverse::constant(Named_object* named_object, bool)
&& !ctype->is_boolean_type()
&& !ctype->is_string_type())
{
- error_at(constant->location(), "invalid constant type");
+ if (!ctype->is_error_type())
+ error_at(constant->location(), "invalid constant type");
constant->set_error();
}
else if (!constant->expr()->is_constant())
@@ -2473,7 +2474,7 @@ Function::Function(Function_type* type, Function* enclosing, Block* block,
// Create the named result variables.
void
-Function::create_named_result_variables()
+Function::create_named_result_variables(Gogo* gogo)
{
const Typed_identifier_list* results = this->type_->results();
if (results == NULL
@@ -2490,10 +2491,17 @@ Function::create_named_result_variables()
p != results->end();
++p, ++index)
{
- Result_variable* result = new Result_variable(p->type(), this,
- index);
- Named_object* no = block->bindings()->add_result_variable(p->name(),
- result);
+ std::string name = p->name();
+ if (Gogo::is_sink_name(name))
+ {
+ static int unnamed_result_counter;
+ char buf[100];
+ snprintf(buf, sizeof buf, "_$%d", unnamed_result_counter);
+ ++unnamed_result_counter;
+ name = gogo->pack_hidden_name(buf, false);
+ }
+ Result_variable* result = new Result_variable(p->type(), this, index);
+ Named_object* no = block->bindings()->add_result_variable(name, result);
this->named_results_->push_back(no);
}
}
@@ -3048,7 +3056,7 @@ Variable::Variable(Type* type, Expression* init, bool is_global,
: type_(type), init_(init), preinit_(NULL), location_(location),
is_global_(is_global), is_parameter_(is_parameter),
is_receiver_(is_receiver), is_varargs_parameter_(false),
- is_address_taken_(false), init_is_lowered_(false),
+ is_address_taken_(false), seen_(false), init_is_lowered_(false),
type_from_init_tuple_(false), type_from_range_index_(false),
type_from_range_value_(false), type_from_chan_element_(false),
is_type_switch_var_(false)
@@ -3082,7 +3090,18 @@ Variable::lower_init_expression(Gogo* gogo, Named_object* function)
{
if (this->init_ != NULL && !this->init_is_lowered_)
{
+ if (this->seen_)
+ {
+ // We will give an error elsewhere, this is just to prevent
+ // an infinite loop.
+ return;
+ }
+ this->seen_ = true;
+
gogo->lower_expression(function, &this->init_);
+
+ this->seen_ = false;
+
this->init_is_lowered_ = true;
}
}
@@ -3119,7 +3138,10 @@ Variable::type_from_tuple(Expression* expr, bool report_error) const
else if (expr->receive_expression() != NULL)
{
Expression* channel = expr->receive_expression()->channel();
- return channel->type()->channel_type()->element_type();
+ Type* channel_type = channel->type();
+ if (channel_type->is_error_type())
+ return Type::make_error_type();
+ return channel_type->channel_type()->element_type();
}
else
{
@@ -3198,7 +3220,7 @@ Variable::type_from_chan_element(Expression* expr, bool report_error) const
// with type determination, then this should be unnecessary.
Type*
-Variable::type() const
+Variable::type()
{
// A variable in a type switch with a nil case will have the wrong
// type here. This gets fixed up in determine_type, below.
@@ -3213,14 +3235,26 @@ Variable::type() const
type = NULL;
}
+ if (this->seen_)
+ {
+ if (this->type_ == NULL || !this->type_->is_error_type())
+ {
+ error_at(this->location_, "variable initializer refers to itself");
+ this->type_ = Type::make_error_type();
+ }
+ return this->type_;
+ }
+
+ this->seen_ = true;
+
if (type != NULL)
- return type;
+ ;
else if (this->type_from_init_tuple_)
- return this->type_from_tuple(init, false);
+ type = this->type_from_tuple(init, false);
else if (this->type_from_range_index_ || this->type_from_range_value_)
- return this->type_from_range(init, this->type_from_range_index_, false);
+ type = this->type_from_range(init, this->type_from_range_index_, false);
else if (this->type_from_chan_element_)
- return this->type_from_chan_element(init, false);
+ type = this->type_from_chan_element(init, false);
else
{
gcc_assert(init != NULL);
@@ -3233,9 +3267,21 @@ Variable::type() const
if (type->is_void_type())
type = Type::make_error_type();
-
- return type;
}
+
+ this->seen_ = false;
+
+ return type;
+}
+
+// Fetch the type from a const pointer, in which case it should have
+// been set already.
+
+Type*
+Variable::type() const
+{
+ gcc_assert(this->type_ != NULL);
+ return this->type_;
}
// Set the type if necessary.
diff --git a/gcc/go/gofrontend/gogo.h b/gcc/go/gofrontend/gogo.h
index d0cfa1e90e0..552a6434485 100644
--- a/gcc/go/gofrontend/gogo.h
+++ b/gcc/go/gofrontend/gogo.h
@@ -785,7 +785,7 @@ class Function
// Create the named result variables in the outer block.
void
- create_named_result_variables();
+ create_named_result_variables(Gogo*);
// Add a new field to the closure variable.
void
@@ -1039,6 +1039,9 @@ class Variable
// Get the type of the variable.
Type*
+ type();
+
+ Type*
type() const;
// Return whether the type is defined yet.
@@ -1258,6 +1261,8 @@ class Variable
bool is_varargs_parameter_ : 1;
// Whether something takes the address of this variable.
bool is_address_taken_ : 1;
+ // True if we have seen this variable in a traversal.
+ bool seen_ : 1;
// True if we have lowered the initialization expression.
bool init_is_lowered_ : 1;
// True if init is a tuple used to set the type.
diff --git a/gcc/go/gofrontend/parse.cc b/gcc/go/gofrontend/parse.cc
index ef63754dc8e..a0d87dc8c6a 100644
--- a/gcc/go/gofrontend/parse.cc
+++ b/gcc/go/gofrontend/parse.cc
@@ -2513,10 +2513,7 @@ Parse::function_lit()
Function_type* type = this->signature(NULL, location);
if (type == NULL)
- {
- this->block();
- return Expression::make_error(location);
- }
+ type = Type::make_function_type(NULL, NULL, NULL, location);
// For a function literal, the next token must be a '{'. If we
// don't see that, then we may have a type expression.
@@ -3982,6 +3979,8 @@ Parse::type_case_clause(Named_object* switch_no, Type_case_clauses* clauses)
clauses->add(*p, true, false, NULL, location);
clauses->add(types.back(), false, false, statements, location);
}
+ else
+ clauses->add(Type::make_error_type(), false, false, statements, location);
}
// TypeSwitchCase = "case" type | "default"
diff --git a/gcc/go/gofrontend/statements.cc b/gcc/go/gofrontend/statements.cc
index 2d17797c9dd..2c0dba0a11b 100644
--- a/gcc/go/gofrontend/statements.cc
+++ b/gcc/go/gofrontend/statements.cc
@@ -782,6 +782,12 @@ Tuple_assignment_statement::do_lower(Gogo*, Block* enclosing)
{
gcc_assert(prhs != this->rhs_->end());
+ if ((*plhs)->is_error_expression()
+ || (*plhs)->type()->is_error_type()
+ || (*prhs)->is_error_expression()
+ || (*prhs)->type()->is_error_type())
+ continue;
+
if ((*plhs)->is_sink_expression())
{
b->add_statement(Statement::make_statement(*prhs));
@@ -802,6 +808,12 @@ Tuple_assignment_statement::do_lower(Gogo*, Block* enclosing)
plhs != this->lhs_->end();
++plhs, ++prhs)
{
+ if ((*plhs)->is_error_expression()
+ || (*plhs)->type()->is_error_type()
+ || (*prhs)->is_error_expression()
+ || (*prhs)->type()->is_error_type())
+ continue;
+
if ((*plhs)->is_sink_expression())
continue;
@@ -1812,7 +1824,13 @@ Thunk_statement::simplify_statement(Gogo* gogo, Block* block)
Call_expression* ce = this->call_->call_expression();
Function_type* fntype = ce->get_function_type();
- if (fntype == NULL || this->is_simple(fntype))
+ if (fntype == NULL)
+ {
+ gcc_assert(saw_errors());
+ this->set_is_error();
+ return false;
+ }
+ if (this->is_simple(fntype))
return false;
Expression* fn = ce->fn();
@@ -4210,6 +4228,8 @@ Select_clauses::get_tree(Translate_context* context,
chans_arg,
pointer_boolean_type_tree,
is_sends_arg);
+ if (call == error_mark_node)
+ return error_mark_node;
tree stmt_list = NULL_TREE;
diff --git a/gcc/go/gofrontend/types.cc b/gcc/go/gofrontend/types.cc
index 1579f179aa7..af541e8eb51 100644
--- a/gcc/go/gofrontend/types.cc
+++ b/gcc/go/gofrontend/types.cc
@@ -301,16 +301,19 @@ Type::do_traverse(Traverse*)
return TRAVERSE_CONTINUE;
}
-// Return whether two types are identical. If REASON is not NULL,
-// optionally set *REASON to the reason the types are not identical.
+// Return whether two types are identical. If ERRORS_ARE_IDENTICAL,
+// then return true for all erroneous types; this is used to avoid
+// cascading errors. If REASON is not NULL, optionally set *REASON to
+// the reason the types are not identical.
bool
-Type::are_identical(const Type* t1, const Type* t2, std::string* reason)
+Type::are_identical(const Type* t1, const Type* t2, bool errors_are_identical,
+ std::string* reason)
{
if (t1 == NULL || t2 == NULL)
{
- // Something is wrong. Return true to avoid cascading errors.
- return true;
+ // Something is wrong.
+ return errors_are_identical ? true : t1 == t2;
}
// Skip defined forward declarations.
@@ -320,15 +323,18 @@ Type::are_identical(const Type* t1, const Type* t2, std::string* reason)
if (t1 == t2)
return true;
- // An undefined forward declaration is an error, so we return true
- // to avoid cascading errors.
+ // An undefined forward declaration is an error.
if (t1->forward_declaration_type() != NULL
|| t2->forward_declaration_type() != NULL)
- return true;
+ return errors_are_identical;
// Avoid cascading errors with error types.
if (t1->is_error_type() || t2->is_error_type())
- return true;
+ {
+ if (errors_are_identical)
+ return true;
+ return t1->is_error_type() && t2->is_error_type();
+ }
// Get a good reason for the sink type. Note that the sink type on
// the left hand side of an assignment is handled in are_assignable.
@@ -368,70 +374,45 @@ Type::are_identical(const Type* t1, const Type* t2, std::string* reason)
case TYPE_FUNCTION:
return t1->function_type()->is_identical(t2->function_type(),
false,
+ errors_are_identical,
reason);
case TYPE_POINTER:
- return Type::are_identical(t1->points_to(), t2->points_to(), reason);
+ return Type::are_identical(t1->points_to(), t2->points_to(),
+ errors_are_identical, reason);
case TYPE_STRUCT:
- return t1->struct_type()->is_identical(t2->struct_type());
+ return t1->struct_type()->is_identical(t2->struct_type(),
+ errors_are_identical);
case TYPE_ARRAY:
- return t1->array_type()->is_identical(t2->array_type());
+ return t1->array_type()->is_identical(t2->array_type(),
+ errors_are_identical);
case TYPE_MAP:
- return t1->map_type()->is_identical(t2->map_type());
+ return t1->map_type()->is_identical(t2->map_type(),
+ errors_are_identical);
case TYPE_CHANNEL:
- return t1->channel_type()->is_identical(t2->channel_type());
+ return t1->channel_type()->is_identical(t2->channel_type(),
+ errors_are_identical);
case TYPE_INTERFACE:
- return t1->interface_type()->is_identical(t2->interface_type());
+ return t1->interface_type()->is_identical(t2->interface_type(),
+ errors_are_identical);
default:
gcc_unreachable();
}
}
-// Return true if two types are identical when it comes to storing
-// them in a hash table. This differs from Type::are_identical with
-// regard to how we handle error types. We want to treat error types
-// as identical to other types when it comes to reporting
-// compatibility errors, but we want to treat them as different when
-// it comes to storing them in a hash table.
-
-bool
-Type::are_identical_for_hash_table(const Type* t1, const Type *t2)
-{
- if (t1 == NULL || t2 == NULL)
- return t1 == t2;
-
- t1 = t1->forwarded();
- t2 = t2->forwarded();
-
- if (t1 == t2)
- return true;
-
- // Undefined forward declarations are only equal to themselves.
- if (t1->forward_declaration_type() != NULL
- || t2->forward_declaration_type() != NULL)
- return false;
-
- // The error type is only equal to the error type.
- if (t1->is_error_type() || t2->is_error_type())
- return t1->is_error_type() && t2->is_error_type();
-
- // Otherwise we can use the usual identity check.
- return Type::are_identical(t1, t2, NULL);
-}
-
// Return true if it's OK to have a binary operation with types LHS
// and RHS. This is not used for shifts or comparisons.
bool
Type::are_compatible_for_binop(const Type* lhs, const Type* rhs)
{
- if (Type::are_identical(lhs, rhs, NULL))
+ if (Type::are_identical(lhs, rhs, true, NULL))
return true;
// A constant of abstract bool type may be mixed with any bool type.
@@ -513,14 +494,14 @@ Type::are_assignable(const Type* lhs, const Type* rhs, std::string* reason)
}
// Identical types are assignable.
- if (Type::are_identical(lhs, rhs, reason))
+ if (Type::are_identical(lhs, rhs, true, reason))
return true;
// The types are assignable if they have identical underlying types
// and either LHS or RHS is not a named type.
if (((lhs->named_type() != NULL && rhs->named_type() == NULL)
|| (rhs->named_type() != NULL && lhs->named_type() == NULL))
- && Type::are_identical(lhs->base(), rhs->base(), reason))
+ && Type::are_identical(lhs->base(), rhs->base(), true, reason))
return true;
// The types are assignable if LHS is an interface type and RHS
@@ -547,6 +528,7 @@ Type::are_assignable(const Type* lhs, const Type* rhs, std::string* reason)
&& (lhs->named_type() == NULL || rhs->named_type() == NULL)
&& Type::are_identical(lhs->channel_type()->element_type(),
rhs->channel_type()->element_type(),
+ true,
reason))
return true;
@@ -609,7 +591,7 @@ Type::are_convertible(const Type* lhs, const Type* rhs, std::string* reason)
// The types are convertible if they have identical underlying
// types.
if ((lhs->named_type() != NULL || rhs->named_type() != NULL)
- && Type::are_identical(lhs->base(), rhs->base(), reason))
+ && Type::are_identical(lhs->base(), rhs->base(), true, reason))
return true;
// The types are convertible if they are both unnamed pointer types
@@ -622,6 +604,7 @@ Type::are_convertible(const Type* lhs, const Type* rhs, std::string* reason)
|| rhs->points_to()->named_type() != NULL)
&& Type::are_identical(lhs->points_to()->base(),
rhs->points_to()->base(),
+ true,
reason))
return true;
@@ -2352,7 +2335,7 @@ bool
Function_type::is_valid_redeclaration(const Function_type* t,
std::string* reason) const
{
- if (!this->is_identical(t, false, reason))
+ if (!this->is_identical(t, false, true, reason))
return false;
// A redeclaration of a function is required to use the same names
@@ -2436,6 +2419,7 @@ Function_type::is_valid_redeclaration(const Function_type* t,
bool
Function_type::is_identical(const Function_type* t, bool ignore_receiver,
+ bool errors_are_identical,
std::string* reason) const
{
if (!ignore_receiver)
@@ -2450,7 +2434,8 @@ Function_type::is_identical(const Function_type* t, bool ignore_receiver,
}
if (r1 != NULL)
{
- if (!Type::are_identical(r1->type(), r2->type(), reason))
+ if (!Type::are_identical(r1->type(), r2->type(), errors_are_identical,
+ reason))
{
if (reason != NULL && !reason->empty())
*reason = "receiver: " + *reason;
@@ -2481,7 +2466,8 @@ Function_type::is_identical(const Function_type* t, bool ignore_receiver,
return false;
}
- if (!Type::are_identical(p1->type(), p2->type(), NULL))
+ if (!Type::are_identical(p1->type(), p2->type(),
+ errors_are_identical, NULL))
{
if (reason != NULL)
*reason = _("different parameter types");
@@ -2525,7 +2511,8 @@ Function_type::is_identical(const Function_type* t, bool ignore_receiver,
return false;
}
- if (!Type::are_identical(res1->type(), res2->type(), NULL))
+ if (!Type::are_identical(res1->type(), res2->type(),
+ errors_are_identical, NULL))
{
if (reason != NULL)
*reason = _("different result types");
@@ -3445,7 +3432,8 @@ Struct_type::do_has_pointer() const
// Whether this type is identical to T.
bool
-Struct_type::is_identical(const Struct_type* t) const
+Struct_type::is_identical(const Struct_type* t,
+ bool errors_are_identical) const
{
const Struct_field_list* fields1 = this->fields();
const Struct_field_list* fields2 = t->fields();
@@ -3461,7 +3449,8 @@ Struct_type::is_identical(const Struct_type* t) const
if (pf1->field_name() != pf2->field_name())
return false;
if (pf1->is_anonymous() != pf2->is_anonymous()
- || !Type::are_identical(pf1->type(), pf2->type(), NULL))
+ || !Type::are_identical(pf1->type(), pf2->type(),
+ errors_are_identical, NULL))
return false;
if (!pf1->has_tag())
{
@@ -4142,9 +4131,10 @@ Type::make_struct_type(Struct_field_list* fields,
// Whether two array types are identical.
bool
-Array_type::is_identical(const Array_type* t) const
+Array_type::is_identical(const Array_type* t, bool errors_are_identical) const
{
- if (!Type::are_identical(this->element_type(), t->element_type(), NULL))
+ if (!Type::are_identical(this->element_type(), t->element_type(),
+ errors_are_identical, NULL))
return false;
Expression* l1 = this->length();
@@ -4960,10 +4950,12 @@ Map_type::do_verify()
// Whether two map types are identical.
bool
-Map_type::is_identical(const Map_type* t) const
+Map_type::is_identical(const Map_type* t, bool errors_are_identical) const
{
- return (Type::are_identical(this->key_type(), t->key_type(), NULL)
- && Type::are_identical(this->val_type(), t->val_type(), NULL));
+ return (Type::are_identical(this->key_type(), t->key_type(),
+ errors_are_identical, NULL)
+ && Type::are_identical(this->val_type(), t->val_type(),
+ errors_are_identical, NULL));
}
// Hash code.
@@ -5102,6 +5094,8 @@ Map_type::do_make_expression_tree(Translate_context* context,
context->gogo()->map_descriptor(this),
sizetype,
expr_tree);
+ if (ret == error_mark_node)
+ return error_mark_node;
// This can panic if the capacity is out of range.
TREE_NOTHROW(new_map_fndecl) = 0;
@@ -5248,9 +5242,11 @@ Channel_type::do_hash_for_method(Gogo* gogo) const
// Whether this type is the same as T.
bool
-Channel_type::is_identical(const Channel_type* t) const
+Channel_type::is_identical(const Channel_type* t,
+ bool errors_are_identical) const
{
- if (!Type::are_identical(this->element_type(), t->element_type(), NULL))
+ if (!Type::are_identical(this->element_type(), t->element_type(),
+ errors_are_identical, NULL))
return false;
return (this->may_send_ == t->may_send_
&& this->may_receive_ == t->may_receive_);
@@ -5350,6 +5346,8 @@ Channel_type::do_make_expression_tree(Translate_context* context,
element_size_tree,
sizetype,
expr_tree);
+ if (ret == error_mark_node)
+ return error_mark_node;
// This can panic if the capacity is out of range.
TREE_NOTHROW(new_channel_fndecl) = 0;
@@ -5666,7 +5664,8 @@ Interface_type::is_unexported_method(Gogo* gogo, const std::string& name) const
// Whether this type is identical with T.
bool
-Interface_type::is_identical(const Interface_type* t) const
+Interface_type::is_identical(const Interface_type* t,
+ bool errors_are_identical) const
{
// We require the same methods with the same types. The methods
// have already been sorted.
@@ -5681,7 +5680,8 @@ Interface_type::is_identical(const Interface_type* t) const
if (p1 == this->methods()->end())
return false;
if (p1->name() != p2->name()
- || !Type::are_identical(p1->type(), p2->type(), NULL))
+ || !Type::are_identical(p1->type(), p2->type(),
+ errors_are_identical, NULL))
return false;
}
if (p1 != this->methods()->end())
@@ -5720,7 +5720,7 @@ Interface_type::is_compatible_for_assign(const Interface_type* t,
}
std::string subreason;
- if (!Type::are_identical(p->type(), m->type(), &subreason))
+ if (!Type::are_identical(p->type(), m->type(), true, &subreason))
{
if (reason != NULL)
{
@@ -5855,7 +5855,7 @@ Interface_type::implements_interface(const Type* t, std::string* reason) const
Function_type* m_fn_type = m->type()->function_type();
gcc_assert(p_fn_type != NULL && m_fn_type != NULL);
std::string subreason;
- if (!p_fn_type->is_identical(m_fn_type, true, &subreason))
+ if (!p_fn_type->is_identical(m_fn_type, true, true, &subreason))
{
if (reason != NULL)
{
@@ -6887,11 +6887,17 @@ Named_type::do_get_tree(Gogo* gogo)
break;
case TYPE_FUNCTION:
- // Don't recur infinitely if a function type refers to itself.
- // Ideally we would build a circular data structure here, but
- // GENERIC can't handle them.
+ // 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_)
- return ptr_type_node;
+ {
+ 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;
+ }
this->seen_ = true;
t = Type::get_named_type_tree(gogo, this->type_);
this->seen_ = false;
@@ -7568,7 +7574,7 @@ Type::bind_field_or_method(Gogo* gogo, const Type* type, Expression* expr,
const std::string& name,
source_location location)
{
- if (type->is_error_type())
+ if (type->deref()->is_error_type())
return Expression::make_error(location);
const Named_type* nt = type->named_type();
@@ -7758,7 +7764,8 @@ Type::find_field_or_method(const Type* type,
if (!pf->is_anonymous())
continue;
- if (pf->type()->is_error_type() || pf->type()->is_undefined())
+ if (pf->type()->deref()->is_error_type()
+ || pf->type()->deref()->is_undefined())
continue;
Named_type* fnt = pf->type()->deref()->named_type();
@@ -7879,7 +7886,8 @@ Type::is_unexported_field_or_method(Gogo* gogo, const Type* type,
++pf)
{
if (pf->is_anonymous()
- && (!pf->type()->is_error_type() && !pf->type()->is_undefined()))
+ && (!pf->type()->deref()->is_error_type()
+ && !pf->type()->deref()->is_undefined()))
{
Named_type* subtype = pf->type()->deref()->named_type();
gcc_assert(subtype != NULL);
diff --git a/gcc/go/gofrontend/types.h b/gcc/go/gofrontend/types.h
index 43a2708547c..2a713b067d4 100644
--- a/gcc/go/gofrontend/types.h
+++ b/gcc/go/gofrontend/types.h
@@ -503,16 +503,13 @@ class Type
verify()
{ return this->do_verify(); }
- // Return true if two types are identical. If this returns false,
+ // Return true if two types are identical. If ERRORS_ARE_IDENTICAL,
+ // returns that an erroneous type is identical to any other type;
+ // this is used to avoid cascading errors. If this returns false,
// and REASON is not NULL, it may set *REASON.
static bool
- are_identical(const Type* lhs, const Type* rhs, std::string* reason);
-
- // Return true if two types are identical when it comes to putting
- // them in a hash table. This differs from are_identical only in
- // how error types are handled.
- static bool
- are_identical_for_hash_table(const Type*, const Type*);
+ are_identical(const Type* lhs, const Type* rhs, bool errors_are_identical,
+ std::string* reason);
// Return true if two types are compatible for use in a binary
// operation, other than a shift, comparison, or channel send. This
@@ -1110,7 +1107,7 @@ class Type_identical
public:
bool
operator()(const Type* t1, const Type* t2) const
- { return Type::are_identical_for_hash_table(t1, t2); }
+ { return Type::are_identical(t1, t2, false, NULL); }
};
// An identifier with a type.
@@ -1583,7 +1580,7 @@ class Function_type : public Type
// Whether this type is the same as T.
bool
is_identical(const Function_type* t, bool ignore_receiver,
- std::string*) const;
+ bool errors_are_identical, std::string*) const;
// Record that this is a varargs function.
void
@@ -1890,7 +1887,7 @@ class Struct_type : public Type
// Whether this type is identical with T.
bool
- is_identical(const Struct_type* t) const;
+ is_identical(const Struct_type* t, bool errors_are_identical) const;
// Whether this struct type has any hidden fields. This returns
// true if any fields have hidden names, or if any non-pointer
@@ -2009,7 +2006,7 @@ class Array_type : public Type
// Whether this type is identical with T.
bool
- is_identical(const Array_type* t) const;
+ is_identical(const Array_type* t, bool errors_are_identical) const;
// Whether this type has any hidden fields.
bool
@@ -2126,7 +2123,7 @@ class Map_type : public Type
// Whether this type is identical with T.
bool
- is_identical(const Map_type* t) const;
+ is_identical(const Map_type* t, bool errors_are_identical) const;
// Import a map type.
static Map_type*
@@ -2212,7 +2209,7 @@ class Channel_type : public Type
// Whether this type is identical with T.
bool
- is_identical(const Channel_type* t) const;
+ is_identical(const Channel_type* t, bool errors_are_identical) const;
// Import a channel type.
static Channel_type*
@@ -2315,7 +2312,7 @@ class Interface_type : public Type
// Whether this type is identical with T. REASON is as in
// implements_interface.
bool
- is_identical(const Interface_type* t) const;
+ is_identical(const Interface_type* t, bool errors_are_identical) const;
// Whether we can assign T to this type. is_identical is known to
// be false.