@@ -4002,6 +4002,15 @@
expr);
}
+ // If the type of EXPR is a recursive pointer type, then we
+ // need to insert a cast before indirecting.
+ if (TREE_TYPE(TREE_TYPE(expr)) == ptr_type_node)
+ {
+ Type* pt = this->expr_->type()->points_to();
+ tree ind = pt->get_tree(context->gogo());
+ expr = fold_convert_loc(loc, build_pointer_type(ind), expr);
+ }
+
return build_fold_indirect_ref_loc(loc, expr);
}
@@ -8382,6 +8391,16 @@
CALL_EXPR_STATIC_CHAIN(ret) = closure_tree;
}
+ // If this is a recursive function type which returns itself, as in
+ // type F func() F
+ // we have used ptr_type_node for the return type. Add a cast here
+ // to the correct type.
+ if (TREE_TYPE(ret) == ptr_type_node)
+ {
+ tree t = this->type()->get_tree(gogo);
+ ret = fold_convert_loc(location, t, ret);
+ }
+
if (excess_type != NULL_TREE)
{
// Calling convert here can undo our excess precision change.
@@ -781,9 +781,19 @@
{
if (this->tree_ == NULL)
{
- this->tree_ = this->do_get_tree(gogo);
- go_preserve_from_gc(this->tree_);
- }
+ tree t = this->do_get_tree(gogo);
+
+ // For a recursive function or pointer type, we will temporarily
+ // return ptr_type_node during the recursion. We don't want to
+ // record that for a forwarding type, as it may confuse us
+ // later.
+ if (t == ptr_type_node && this->forward_declaration_type() != NULL)
+ return t;
+
+ this->tree_ = t;
+ go_preserve_from_gc(t);
+ }
+
return this->tree_;
}