Fix order in which recursive structs are converted to GENERIC.
authorIan Lance Taylor <ian@gcc.gnu.org>
Thu, 6 Jan 2011 01:35:19 +0000 (01:35 +0000)
committerIan Lance Taylor <ian@gcc.gnu.org>
Thu, 6 Jan 2011 01:35:19 +0000 (01:35 +0000)
From-SVN: r168534

gcc/go/gofrontend/types.cc
gcc/go/gofrontend/types.h

index a8faa35e0f6d04c593c7074cd631713a76aded00..8bb2b72a5a75d6f4d0beeefdc50927229c3b207d 100644 (file)
@@ -3768,6 +3768,19 @@ Struct_type::fill_in_tree(Gogo* gogo, tree type)
   return type;
 }
 
+// Make sure that all structs which must be converted to the backend
+// representation before this one are in fact converted.
+
+void
+Struct_type::convert_prerequisites(Gogo* gogo)
+{
+  for (std::vector<Named_type*>::const_iterator p
+        = this->prerequisites_.begin();
+       p != this->prerequisites_.end();
+       ++p)
+    (*p)->get_tree(gogo);
+}
+
 // Initialize struct fields.
 
 tree
@@ -5977,20 +5990,44 @@ Interface_type::fill_in_tree(Gogo* gogo, tree type)
 {
   gcc_assert(this->methods_ != NULL);
 
+  // Because the methods may refer to the interface type itself, we
+  // need to build the interface type first, and then update the
+  // method pointer later.
+
+  tree field_trees = NULL_TREE;
+  tree* pp = &field_trees;
+
+  tree name_tree = get_identifier("__methods");
+  tree methods_field = build_decl(this->location_, FIELD_DECL, name_tree,
+                                 ptr_type_node);
+  DECL_CONTEXT(methods_field) = type;
+  *pp = methods_field;
+  pp = &DECL_CHAIN(methods_field);
+
+  name_tree = get_identifier("__object");
+  tree field = build_decl(this->location_, FIELD_DECL, name_tree,
+                         ptr_type_node);
+  DECL_CONTEXT(field) = type;
+  *pp = field;
+
+  TYPE_FIELDS(type) = field_trees;
+
+  layout_type(type);
+
   // Build the type of the table of methods.
 
   tree method_table = make_node(RECORD_TYPE);
 
   // The first field is a pointer to the type descriptor.
-  tree name_tree = get_identifier("__type_descriptor");
+  name_tree = get_identifier("__type_descriptor");
   tree dtype = Type::make_type_descriptor_type()->get_tree(gogo);
   dtype = build_pointer_type(build_qualified_type(dtype, TYPE_QUAL_CONST));
-  tree field = build_decl(this->location_, FIELD_DECL, name_tree, dtype);
+  field = build_decl(this->location_, FIELD_DECL, name_tree, dtype);
   DECL_CONTEXT(field) = method_table;
   TYPE_FIELDS(method_table) = field;
 
   std::string last_name = "";
-  tree* pp = &DECL_CHAIN(field);
+  pp = &DECL_CHAIN(field);
   for (Typed_identifier_list::const_iterator p = this->methods_->begin();
        p != this->methods_->end();
        ++p)
@@ -6010,25 +6047,9 @@ Interface_type::fill_in_tree(Gogo* gogo, tree type)
     }
   layout_type(method_table);
 
-  tree mtype = build_pointer_type(method_table);
-
-  tree field_trees = NULL_TREE;
-  pp = &field_trees;
-
-  name_tree = get_identifier("__methods");
-  field = build_decl(this->location_, FIELD_DECL, name_tree, mtype);
-  DECL_CONTEXT(field) = type;
-  *pp = field;
-  pp = &DECL_CHAIN(field);
-
-  name_tree = get_identifier("__object");
-  field = build_decl(this->location_, FIELD_DECL, name_tree, ptr_type_node);
-  DECL_CONTEXT(field) = type;
-  *pp = field;
-
-  TYPE_FIELDS(type) = field_trees;
-
-  layout_type(type);
+  // Update the type of the __methods field from a generic pointer to
+  // a pointer to the method table.
+  TREE_TYPE(methods_field) = build_pointer_type(method_table);
 
   return type;
 }
@@ -6864,6 +6885,26 @@ Named_type::do_verify()
        return false;
     }
 
+  // If this is a struct, then if any of the fields of the struct
+  // themselves have struct type, then this struct must be converted
+  // to the backend representation before the field's type is
+  // converted.  That may seem backward, but it works because if the
+  // field's type refers to this one, e.g., via a pointer, then the
+  // conversion process will pick up the half-built struct and do the
+  // right thing.
+  if (this->struct_type() != NULL)
+    {
+      const Struct_field_list* fields = this->struct_type()->fields();
+      for (Struct_field_list::const_iterator p = fields->begin();
+          p != fields->end();
+          ++p)
+       {
+         Struct_type* st = p->type()->struct_type();
+         if (st != NULL)
+           st->add_prerequisite(this);
+       }
+    }
+
   return true;
 }
 
@@ -6994,8 +7035,17 @@ Named_type::do_get_tree(Gogo* gogo)
       break;
 
     case TYPE_STRUCT:
+      // If there are structs which must be converted first, do them.
+      if (this->seen_ == 0)
+       {
+         ++this->seen_;
+         this->type_->struct_type()->convert_prerequisites(gogo);
+         --this->seen_;
+       }
+
       if (this->named_tree_ != NULL_TREE)
        return this->named_tree_;
+
       t = make_node(RECORD_TYPE);
       this->named_tree_ = t;
       t = this->type_->struct_type()->fill_in_tree(gogo, t);
index cecf106e448d77333dc504d91c52a9a8f1f6662d..a8d8a0b9ed4a360a6aca9d990f95ee946ed7a226 100644 (file)
@@ -1843,7 +1843,8 @@ class Struct_type : public Type
  public:
   Struct_type(Struct_field_list* fields, source_location location)
     : Type(TYPE_STRUCT),
-      fields_(fields), location_(location), all_methods_(NULL)
+      fields_(fields), location_(location), all_methods_(NULL),
+      prerequisites_()
   { }
 
   // Return the field NAME.  This only looks at local fields, not at
@@ -1938,6 +1939,17 @@ class Struct_type : public Type
   tree
   fill_in_tree(Gogo*, tree);
 
+  // Note that a struct must be converted to the backend
+  // representation before we convert this struct.
+  void
+  add_prerequisite(Named_type* nt)
+  { this->prerequisites_.push_back(nt); }
+
+  // If there are any structs which must be converted to the backend
+  // representation before this one, convert them.
+  void
+  convert_prerequisites(Gogo*);
+
  protected:
   int
   do_traverse(Traverse*);
@@ -1983,6 +1995,16 @@ class Struct_type : public Type
   source_location location_;
   // If this struct is unnamed, a list of methods.
   Methods* all_methods_;
+  // A list of structs which must be converted to the backend
+  // representation before this struct can be converted.  This is for
+  // cases like
+  //   type S1 { p *S2 }
+  //   type S2 { s S1 }
+  // where we must start converting S2 before we start converting S1.
+  // That is because we can fully convert S1 before S2 is complete,
+  // but we can not fully convert S2 before S1 is complete.  If we
+  // start converting S1 first, we won't be able to convert S2.
+  std::vector<Named_type*> prerequisites_;
 };
 
 // The type of an array.