diff gcc/go/gofrontend/ast-dump.cc @ 145:1830386684a0

gcc-9.2.0
author anatofuz
date Thu, 13 Feb 2020 11:34:05 +0900
parents 84e7813d76e9
children
line wrap: on
line diff
--- a/gcc/go/gofrontend/ast-dump.cc	Thu Oct 25 07:37:49 2018 +0900
+++ b/gcc/go/gofrontend/ast-dump.cc	Thu Feb 13 11:34:05 2020 +0900
@@ -8,6 +8,7 @@
 
 #include <iostream>
 #include <fstream>
+#include <sstream>
 
 #include "gogo.h"
 #include "expressions.h"
@@ -134,11 +135,11 @@
         {
           if (it != res->begin())
             this->ast_dump_context_->ostream() << ",";
-          Named_object* no = (*it);
+          Named_object* rno = (*it);
 
-          this->ast_dump_context_->ostream() << no->name() << " ";
-          go_assert(no->is_result_variable());
-          Result_variable* resvar = no->result_var_value();
+          this->ast_dump_context_->ostream() << rno->name() << " ";
+          go_assert(rno->is_result_variable());
+          Result_variable* resvar = rno->result_var_value();
 
           this->ast_dump_context_->dump_type(resvar->type());
 
@@ -199,7 +200,8 @@
   if (out.fail())
     {
       go_error_at(Linemap::unknown_location(),
-		  "cannot open %s:%m, -fgo-dump-ast ignored", dumpname.c_str());
+		  "cannot open %s:%m; %<-fgo-dump-ast%> ignored",
+		  dumpname.c_str());
       return;
     }
 
@@ -482,7 +484,7 @@
   this->ostream() << s;
 }
 
-// Dump statment to stream.
+// Dump statement to stream.
 
 void
 Ast_dump_context::dump_to_stream(const Statement* stm, std::ostream* out)
@@ -499,3 +501,463 @@
   Ast_dump_context adc(out, false);
   expr->dump_expression(&adc);
 }
+
+// Dump an expression to std::cerr. This is intended to be used
+// from within a debugging session.
+
+void
+debug_go_expression(const Expression* expr)
+{
+  if (expr == NULL)
+    std::cerr << "<null>";
+  else
+    {
+      Ast_dump_context::dump_to_stream(expr, &std::cerr);
+      std::string lstr = Linemap::location_to_string(expr->location());
+      std::cerr << " // loc " << lstr << std::endl;
+    }
+}
+
+// Shallow dump of stmt to std::cerr. This is intended to be used
+// from within a debugging session.
+
+void
+debug_go_statement(const Statement* stmt)
+{
+  if (stmt == NULL)
+    std::cerr << "<null>\n";
+  else
+    {
+      std::string lstr = Linemap::location_to_string(stmt->location());
+      Statement *ncstmt = const_cast<Statement*>(stmt);
+      Block_statement* bs = ncstmt->block_statement();
+      if (bs != NULL)
+        std::cerr << "Block " << bs->block()
+                  << " // location: " << lstr << std::endl;
+      else
+        Ast_dump_context::dump_to_stream(stmt, &std::cerr);
+    }
+}
+
+// Deep dump of statement to std::cerr. This is intended to be used
+// from within a debugging session.
+
+void
+debug_go_statement_deep(const Statement* statement)
+{
+  Ast_dump_context adc(&std::cerr, true);
+  statement->dump_statement(&adc);
+}
+
+// Shallow dump of a block to std::cerr. This is intended to be used
+// from within a debugging session.
+
+void
+debug_go_block(const Block* block)
+{
+  if (block == NULL)
+    std::cerr << "<null>";
+  else
+    {
+      std::cerr << "Block " << block
+                << " (enclosing " << block->enclosing() << "):\n";
+      const std::vector<Statement*>* stmts = block->statements();
+      if (stmts != NULL)
+        {
+          for (size_t i = 0; i < stmts->size(); ++i)
+            {
+              debug_go_statement(stmts->at(i));
+            }
+        }
+    }
+}
+
+// Deep dump of a block to std:cerr. This is intended to be used
+// from within a debugging session.
+
+void
+debug_go_block_deep(const Block* block)
+{
+  Ast_dump_context adc(&std::cerr, true);
+  Block* ncblock = const_cast<Block*>(block);
+  adc.dump_block(ncblock);
+}
+
+class Type_dumper
+{
+  typedef Unordered_map(const Type*, unsigned) idx_map;
+ public:
+  Type_dumper(const Type* type)
+      : top_(type), ntypes_(0)
+  {
+    this->worklist_.push_back(type);
+  }
+
+  void visit();
+
+  std::string stringResult() { return ss_.str(); }
+
+ private:
+  void emitpre(unsigned tag, const Type* addr);
+  void typeref(const char*, const Type*, const char *);
+  void visit_forward_declaration_type(const Forward_declaration_type* fdt);
+  void visit_function_type(const Function_type* ft);
+  void visit_struct_type(const Struct_type* st);
+  void visit_array_type(const Array_type* at);
+  void visit_map_type(const Map_type* mt);
+  void visit_channel_type(const Channel_type* mt);
+  void visit_interface_type(const Interface_type* mt);
+  void visit_methods(const Typed_identifier_list* methods,
+                     const char *tag);
+  std::pair<bool, unsigned> lookup(const Type*);
+
+  static const unsigned notag = 0xffffffff;
+
+ private:
+  const Type* top_;
+  idx_map types_;
+  unsigned ntypes_;
+  std::list<const Type*> worklist_;
+  std::ostringstream ss_;
+};
+
+// Look up a type, installing it in 'types_'. Return is <found, N>
+// where 'found' is true if type had been previously recorded, and N
+// is the index/tag assigned to N.  The input argument is appended to
+// the work list if this is the first time we've seen it.
+
+std::pair<bool, unsigned> Type_dumper::lookup(const Type* t)
+{
+  std::pair<const Type*, unsigned> entry = std::make_pair(t, this->ntypes_);
+  std::pair<idx_map::iterator, bool> ins = this->types_.insert(entry);
+  if (ins.second)
+    {
+      this->ntypes_++;
+      if (t != this->top_)
+        this->worklist_.push_back(t);
+    }
+  return std::make_pair(ins.second, ins.first->second);
+}
+
+// Emit preamble prior to dumping a type, including the type
+// pointer itself and the tag we've assigned it.  If no
+// tag is specified (via special "notag" value) and/or the
+// pointer is null, then just emit an equivalent amount
+// of spaces.
+
+void Type_dumper::emitpre(unsigned tag, const Type* ptr)
+{
+  char tbuf[50], pbuf[50], buf[200];
+
+  tbuf[0] = '\0';
+  if (tag != notag)
+    snprintf(tbuf, sizeof tbuf, "T%u", tag);
+
+  pbuf[0] = '\0';
+  if (ptr != NULL)
+    snprintf(pbuf, sizeof pbuf, "%p", (const void*) ptr);
+
+  snprintf(buf, sizeof buf, "%8s %16s  ", tbuf, pbuf);
+  this->ss_ << buf;
+}
+
+// Emit a reference to a type into the dump buffer. In most cases this means
+// just the type tag, but for named types we also emit the name, and for
+// simple/primitive types (ex: int64) we emit the type itself. If "pref" is
+// non-NULL, emit the string prior to the reference, and if "suf" is non-NULL,
+// emit it following the reference.
+
+void Type_dumper::typeref(const char* pref, const Type* t, const char* suf)
+{
+  if (pref != NULL)
+    this->ss_ << pref;
+  std::pair<bool, unsigned> p = this->lookup(t);
+  unsigned tag = p.second;
+  switch (t->classification())
+    {
+      case Type::TYPE_NAMED:
+        {
+          const Named_type* nt = t->named_type();
+          const Named_object* no = nt->named_object();
+          this->ss_ << "'" << no->message_name() << "' -> ";
+          const Type* underlying = nt->real_type();
+          this->typeref(NULL, underlying, NULL);
+          break;
+        }
+      case Type::TYPE_POINTER:
+        this->typeref("*", t->points_to(), NULL);
+        break;
+      case Type::TYPE_ERROR:
+        this->ss_ << "error_type";
+        break;
+      case Type::TYPE_INTEGER:
+        {
+          const Integer_type* it = t->integer_type();
+          if (it->is_abstract())
+            this->ss_ << "abstract_int";
+          else
+            this->ss_ << (it->is_unsigned() ? "u" : "") << "int" << it->bits();
+          break;
+        }
+      case Type::TYPE_FLOAT:
+        {
+          const Float_type* ft = t->float_type();
+          if (ft->is_abstract())
+            this->ss_ << "abstract_float";
+          else
+            this->ss_ << "float" << ft->bits();
+          break;
+        }
+      case Type::TYPE_COMPLEX:
+        {
+          const Complex_type* ct = t->complex_type();
+          if (ct->is_abstract())
+            this->ss_ << "abstract_complex";
+          else
+            this->ss_ << "complex" << ct->bits();
+          break;
+        }
+      case Type::TYPE_BOOLEAN:
+        this->ss_ << "bool";
+        break;
+      case Type::TYPE_STRING:
+        this->ss_ << "string";
+        break;
+      case Type::TYPE_NIL:
+        this->ss_ << "nil_type";
+        break;
+    case Type::TYPE_VOID:
+        this->ss_ << "void_type";
+        break;
+    case Type::TYPE_FUNCTION:
+    case Type::TYPE_STRUCT:
+    case Type::TYPE_ARRAY:
+    case Type::TYPE_MAP:
+    case Type::TYPE_CHANNEL:
+    case Type::TYPE_FORWARD:
+    case Type::TYPE_INTERFACE:
+      this->ss_ << "T" << tag;
+      break;
+
+    default:
+      // This is a debugging routine, so instead of a go_unreachable()
+      // issue a warning/error, to allow for the possibility that the
+      // compiler we're debugging is in a bad state.
+      this->ss_ << "<??? " << ((unsigned)t->classification()) << "> "
+                << "T" << tag;
+    }
+  if (suf != NULL)
+    this->ss_ << suf;
+}
+
+void Type_dumper::visit_forward_declaration_type(const Forward_declaration_type* fdt)
+{
+  this->ss_ << "forward_declaration_type ";
+  if (fdt->is_defined())
+    this->typeref("-> ", fdt->real_type(), NULL);
+  else
+    this->ss_ << "'" << fdt->name() << "'";
+  this->ss_ << "\n";
+}
+
+void Type_dumper::visit_function_type(const Function_type* ft)
+{
+  this->ss_ << "function\n";
+  const Typed_identifier* rec = ft->receiver();
+  if (rec != NULL)
+    {
+      this->emitpre(notag, NULL);
+      this->typeref("receiver ", rec->type(), "\n");
+    }
+  const Typed_identifier_list* parameters = ft->parameters();
+  if (parameters != NULL)
+    {
+      for (Typed_identifier_list::const_iterator p = parameters->begin();
+	   p != parameters->end();
+	   ++p)
+        {
+          this->emitpre(notag, NULL);
+          this->typeref(" param ", p->type(), "\n");
+        }
+    }
+  const Typed_identifier_list* results = ft->results();
+  if (results != NULL)
+    {
+      for (Typed_identifier_list::const_iterator p = results->begin();
+	   p != results->end();
+	   ++p)
+        {
+          this->emitpre(notag, NULL);
+          this->typeref(" result ", p->type(), "\n");
+        }
+    }
+}
+
+void Type_dumper::visit_struct_type(const Struct_type* st)
+{
+  this->ss_ << "struct\n";
+  const Struct_field_list* fields = st->fields();
+  if (fields != NULL)
+    {
+      for (Struct_field_list::const_iterator p = fields->begin();
+           p != fields->end();
+           ++p)
+        {
+          this->emitpre(notag, NULL);
+          this->typeref(" field ", p->type(), "\n");
+        }
+    }
+}
+
+void Type_dumper::visit_array_type(const Array_type* at)
+{
+  this->ss_ << "array [";
+  if (at->length() != NULL)
+    {
+      int64_t len = 0;
+      if (at->int_length(&len))
+        this->ss_ << len;
+    }
+  this->typeref("] ", at->element_type(), "\n");
+}
+
+void Type_dumper::visit_map_type(const Map_type* mt)
+{
+  this->ss_ << "map [";
+  this->typeref(NULL, mt->key_type(), NULL);
+  this->typeref("] ", mt->val_type(), "\n");
+}
+
+void Type_dumper::visit_methods(const Typed_identifier_list* methods,
+                                const char *tag)
+{
+  if (tag != NULL)
+    {
+      this->emitpre(notag, NULL);
+      this->ss_ << tag << "\n";
+    }
+  for (Typed_identifier_list::const_iterator p = methods->begin();
+       p != methods->end();
+       ++p)
+    {
+      this->emitpre(notag, NULL);
+      if (p->name().empty())
+        this->typeref("  embedded method ", p->type(), "\n");
+      else
+        {
+          this->ss_ << "  method '" << p->name() << "' ";
+          this->typeref(NULL, p->type(), "\n");
+        }
+    }
+}
+
+void Type_dumper::visit_interface_type(const Interface_type* it)
+{
+  const Typed_identifier_list* methods =
+      (it->methods_are_finalized() ? it->methods() : it->local_methods());
+  if (methods == NULL)
+    {
+      this->ss_ << "empty_interface\n";
+      return;
+    }
+  this->ss_ << "interface";
+  if (! it->methods_are_finalized())
+    {
+      this->ss_ << " [unfinalized]\n";
+      visit_methods(it->local_methods(), NULL);
+    }
+  else
+    {
+      this->ss_ << "\n";
+      visit_methods(it->local_methods(), "[parse_methods]");
+      visit_methods(it->methods(), "[all_methods]");
+    }
+}
+
+void Type_dumper::visit_channel_type(const Channel_type* ct)
+{
+  this->ss_ << "channel {";
+  if (ct->may_send())
+    this->ss_ << " send";
+  if (ct->may_receive())
+    this->ss_ << " receive";
+  this->typeref(" } ", ct->element_type(), "\n");
+}
+
+void Type_dumper::visit()
+{
+  while (! this->worklist_.empty()) {
+    const Type* t = this->worklist_.front();
+    this->worklist_.pop_front();
+
+    std::pair<bool, unsigned> p = this->lookup(t);
+    unsigned tag = p.second;
+    this->emitpre(tag, t);
+
+    switch(t->classification())
+      {
+        case Type::TYPE_ERROR:
+        case Type::TYPE_INTEGER:
+        case Type::TYPE_FLOAT:
+        case Type::TYPE_COMPLEX:
+        case Type::TYPE_BOOLEAN:
+        case Type::TYPE_STRING:
+        case Type::TYPE_VOID:
+        case Type::TYPE_POINTER:
+        case Type::TYPE_NIL:
+        case Type::TYPE_NAMED:
+          this->typeref(NULL, t, "\n");
+          break;
+        case Type::TYPE_FORWARD:
+          this->visit_forward_declaration_type(t->forward_declaration_type());
+          break;
+
+        case Type::TYPE_FUNCTION:
+          this->visit_function_type(t->function_type());
+          break;
+        case Type::TYPE_STRUCT:
+          this->visit_struct_type(t->struct_type());
+          break;
+        case Type::TYPE_ARRAY:
+          this->visit_array_type(t->array_type());
+          break;
+        case Type::TYPE_MAP:
+          this->visit_map_type(t->map_type());
+          break;
+        case Type::TYPE_CHANNEL:
+          this->visit_channel_type(t->channel_type());
+          break;
+        case Type::TYPE_INTERFACE:
+          this->visit_interface_type(t->interface_type());
+          break;
+        default:
+          // This is a debugging routine, so instead of a go_unreachable()
+          // issue a warning/error, to allow for the possibility that the
+          // compiler we're debugging is in a bad state.
+          this->ss_ << "<unknown/unrecognized classification "
+                    << ((unsigned)t->classification()) << ">\n";
+      }
+  }
+}
+
+// Dump a Go type for debugging purposes. This is a deep as opposed
+// to shallow dump; all of the types reachable from the specified
+// type will be dumped in addition to the type itself.
+
+void debug_go_type(const Type* type)
+{
+  if (type == NULL)
+    {
+      std::cerr << "<NULL type>\n";
+      return;
+    }
+  Type_dumper dumper(type);
+  dumper.visit();
+  std::cerr << dumper.stringResult();
+}
+
+void debug_go_type(Type* type)
+{
+  const Type* ctype = type;
+  debug_go_type(ctype);
+}