LCOV - code coverage report
Current view: top level - gcc/go/gofrontend - ast-dump.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 0.6 % 514 3
Test Date: 2026-02-28 14:20:25 Functions: 2.4 % 42 1
Legend: Lines:     hit not hit

            Line data    Source code
       1              : // ast-dump.cc -- AST debug dump.    -*- C++ -*-
       2              : 
       3              : // Copyright 2011 The Go Authors. All rights reserved.
       4              : // Use of this source code is governed by a BSD-style
       5              : // license that can be found in the LICENSE file.
       6              : 
       7              : #include "go-system.h"
       8              : 
       9              : #include <iostream>
      10              : #include <fstream>
      11              : #include <sstream>
      12              : 
      13              : #include "gogo.h"
      14              : #include "expressions.h"
      15              : #include "statements.h"
      16              : #include "types.h"
      17              : #include "ast-dump.h"
      18              : #include "go-c.h"
      19              : #include "go-dump.h"
      20              : #include "go-diagnostics.h"
      21              : 
      22              : // The -fgo-dump-ast flag to activate AST dumps.
      23              : 
      24              : Go_dump ast_dump_flag("ast");
      25              : 
      26              : // This class is used to traverse the tree to look for blocks and
      27              : // function headers.
      28              : 
      29            0 : class Ast_dump_traverse_blocks_and_functions : public Traverse
      30              : {
      31              :  public:
      32            0 :   Ast_dump_traverse_blocks_and_functions(Ast_dump_context* ast_dump_context)
      33            0 :       : Traverse(traverse_blocks | traverse_functions | traverse_variables),
      34            0 :       ast_dump_context_(ast_dump_context)
      35              :   { }
      36              : 
      37              :  protected:
      38              :   int
      39              :   block(Block*);
      40              : 
      41              :   int
      42              :   function(Named_object*);
      43              : 
      44              :   int
      45              :   variable(Named_object*);
      46              : 
      47              :  private:
      48              :   Ast_dump_context* ast_dump_context_;
      49              : };
      50              : 
      51              : // This class is used to traverse the tree to look for statements.
      52              : 
      53            0 : class Ast_dump_traverse_statements : public Traverse
      54              : {
      55              :  public:
      56            0 :   Ast_dump_traverse_statements(Ast_dump_context* ast_dump_context)
      57            0 :       : Traverse(traverse_statements),
      58            0 :       ast_dump_context_(ast_dump_context)
      59              :   { }
      60              : 
      61              :  protected:
      62              :   int
      63              :   statement(Block*, size_t* pindex, Statement*);
      64              : 
      65              :  private:
      66              :   Ast_dump_context* ast_dump_context_;
      67              : };
      68              : 
      69              : // For each block we enclose it in brackets.
      70              : 
      71            0 : int Ast_dump_traverse_blocks_and_functions::block(Block * block)
      72              : {
      73            0 :   if (block == NULL)
      74              :     {
      75            0 :       this->ast_dump_context_->ostream() << std::endl;
      76            0 :       return TRAVERSE_EXIT;
      77              :     }
      78              : 
      79            0 :   this->ast_dump_context_->print_indent();
      80            0 :   this->ast_dump_context_->ostream() << "{" << std::endl;
      81            0 :   this->ast_dump_context_->indent();
      82              : 
      83              :   // Dump statememts.
      84            0 :   Ast_dump_traverse_statements adts(this->ast_dump_context_);
      85            0 :   block->traverse(&adts);
      86              : 
      87            0 :   this->ast_dump_context_->unindent();
      88            0 :   this->ast_dump_context_->print_indent();
      89            0 :   this->ast_dump_context_->ostream() << "}" << std::endl;
      90              : 
      91            0 :   return TRAVERSE_SKIP_COMPONENTS;
      92            0 : }
      93              : 
      94              : // Dump each traversed statement.
      95              : 
      96              : int
      97            0 : Ast_dump_traverse_statements::statement(Block* block, size_t* pindex,
      98              :                                         Statement* statement)
      99              : {
     100            0 :   statement->dump_statement(this->ast_dump_context_);
     101              : 
     102            0 :   if (statement->is_block_statement())
     103              :     {
     104            0 :       Ast_dump_traverse_blocks_and_functions adtbf(this->ast_dump_context_);
     105            0 :       statement->traverse(block, pindex, &adtbf);
     106            0 :     }
     107              : 
     108            0 :   return TRAVERSE_SKIP_COMPONENTS;
     109              : }
     110              : 
     111              : // Dump the function header.
     112              : 
     113              : int
     114            0 : Ast_dump_traverse_blocks_and_functions::function(Named_object* no)
     115              : {
     116            0 :   this->ast_dump_context_->ostream() << no->name();
     117              : 
     118            0 :   go_assert(no->is_function());
     119            0 :   Function* func = no->func_value();
     120              : 
     121            0 :   this->ast_dump_context_->ostream() << "(";
     122            0 :   this->ast_dump_context_->dump_typed_identifier_list(
     123              :                               func->type()->parameters());
     124              : 
     125            0 :   this->ast_dump_context_->ostream() << ")";
     126              : 
     127            0 :   Function::Results* res = func->result_variables();
     128            0 :   if (res != NULL && !res->empty())
     129              :     {
     130            0 :       this->ast_dump_context_->ostream() << " (";
     131              : 
     132            0 :       for (Function::Results::const_iterator it = res->begin();
     133            0 :           it != res->end();
     134            0 :           it++)
     135              :         {
     136            0 :           if (it != res->begin())
     137            0 :             this->ast_dump_context_->ostream() << ",";
     138            0 :           Named_object* rno = (*it);
     139              : 
     140            0 :           this->ast_dump_context_->ostream() << rno->name() << " ";
     141            0 :           go_assert(rno->is_result_variable());
     142            0 :           Result_variable* resvar = rno->result_var_value();
     143              : 
     144            0 :           this->ast_dump_context_->dump_type(resvar->type());
     145              : 
     146              :         }
     147            0 :       this->ast_dump_context_->ostream() << ")";
     148              :     }
     149              : 
     150            0 :   this->ast_dump_context_->ostream() << " : ";
     151            0 :   this->ast_dump_context_->dump_type(func->type());
     152            0 :   this->ast_dump_context_->ostream() << std::endl;
     153              : 
     154            0 :   return TRAVERSE_CONTINUE;
     155              : }
     156              : 
     157              : // Dump variable preinits
     158              : 
     159              : int
     160            0 : Ast_dump_traverse_blocks_and_functions::variable(Named_object* no)
     161              : {
     162            0 :   if (!no->is_variable())
     163              :     return TRAVERSE_CONTINUE;
     164              : 
     165            0 :   Variable* var = no->var_value();
     166            0 :   if (var->has_pre_init())
     167              :     {
     168            0 :       this->ast_dump_context_->ostream() << "// preinit block for var "
     169            0 :                                          << no->message_name() << "\n";
     170            0 :       var->preinit()->traverse(this);
     171              :     }
     172              : 
     173              :   return TRAVERSE_CONTINUE;
     174              : }
     175              : 
     176              : 
     177              : 
     178              : // Class Ast_dump_context.
     179              : 
     180            0 : Ast_dump_context::Ast_dump_context(std::ostream* out /* = NULL */,
     181            0 :                                    bool dump_subblocks /* = true */)
     182            0 :   :  indent_(0), dump_subblocks_(dump_subblocks), ostream_(out), gogo_(NULL)
     183              : {
     184            0 : }
     185              : 
     186              : // Dump files will be named %basename%.dump.ast
     187              : 
     188              : const char* kAstDumpFileExtension = ".dump.ast";
     189              : 
     190              : // Dump the internal representation.
     191              : 
     192              : void
     193            0 : Ast_dump_context::dump(Gogo* gogo, const char* basename)
     194              : {
     195            0 :   std::ofstream out;
     196            0 :   std::string dumpname(basename);
     197            0 :   dumpname += ".dump.ast";
     198            0 :   out.open(dumpname.c_str());
     199              : 
     200            0 :   if (out.fail())
     201              :     {
     202            0 :       go_error_at(Linemap::unknown_location(),
     203              :                   "cannot open %s:%m; %<-fgo-dump-ast%> ignored",
     204              :                   dumpname.c_str());
     205            0 :       return;
     206              :     }
     207              : 
     208            0 :   this->gogo_ = gogo;
     209            0 :   this->ostream_ = &out;
     210              : 
     211            0 :   Ast_dump_traverse_blocks_and_functions adtbf(this);
     212            0 :   gogo->traverse(&adtbf);
     213              : 
     214            0 :   out.close();
     215            0 : }
     216              : 
     217              : // Dump a textual representation of a type to the
     218              : // the dump file.
     219              : 
     220              : void
     221            0 : Ast_dump_context::dump_type(const Type* t)
     222              : {
     223            0 :   if (t == NULL)
     224            0 :     this->ostream() << "(nil type)";
     225              :   else
     226            0 :     this->ostream() << "(" << t->message_name() << ")";
     227            0 : }
     228              : 
     229              : // Dump a textual representation of a block to the
     230              : // the dump file.
     231              : 
     232              : void
     233            0 : Ast_dump_context::dump_block(Block* b)
     234              : {
     235            0 :   Ast_dump_traverse_blocks_and_functions adtbf(this);
     236            0 :   b->traverse(&adtbf);
     237            0 : }
     238              : 
     239              : // Dump a textual representation of an expression to the
     240              : // the dump file.
     241              : 
     242              : void
     243            0 : Ast_dump_context::dump_expression(const Expression* e)
     244              : {
     245            0 :   e->dump_expression(this);
     246            0 : }
     247              : 
     248              : // Dump a textual representation of an expression list to the
     249              : // the dump file.
     250              : 
     251              : void
     252            0 : Ast_dump_context::dump_expression_list(const Expression_list* el,
     253              :                                        bool as_pairs /* = false */)
     254              : {
     255            0 :   if (el == NULL)
     256              :     return;
     257              : 
     258            0 :   for (std::vector<Expression*>::const_iterator it = el->begin();
     259            0 :        it != el->end();
     260            0 :        it++)
     261              :     {
     262            0 :       if ( it != el->begin())
     263            0 :         this->ostream() << ",";
     264            0 :       if (*it != NULL)
     265            0 :         (*it)->dump_expression(this);
     266              :       else
     267            0 :         this->ostream() << "NULL";
     268            0 :       if (as_pairs)
     269              :         {
     270            0 :           this->ostream() << ":";
     271            0 :           ++it;
     272            0 :           (*it)->dump_expression(this);
     273              :         }
     274              :     }
     275              : }
     276              : 
     277              : // Dump a textual representation of a typed identifier to the
     278              : // the dump file.
     279              : 
     280              : void
     281            0 : Ast_dump_context::dump_typed_identifier(const Typed_identifier* ti)
     282              : {
     283            0 :   this->ostream() << ti->name() << " ";
     284            0 :   this->dump_type(ti->type());
     285            0 : }
     286              : 
     287              : // Dump a textual representation of a typed identifier list to the
     288              : // the dump file.
     289              : 
     290              : void
     291            0 : Ast_dump_context::dump_typed_identifier_list(
     292              :     const Typed_identifier_list* ti_list)
     293              : {
     294            0 :   if (ti_list == NULL)
     295              :     return;
     296              : 
     297            0 :   for (Typed_identifier_list::const_iterator it = ti_list->begin();
     298            0 :        it != ti_list->end();
     299            0 :        it++)
     300              :     {
     301            0 :       if (it != ti_list->begin())
     302            0 :         this->ostream() << ",";
     303            0 :       this->dump_typed_identifier(&(*it));
     304              :     }
     305              : }
     306              : 
     307              : // Dump a textual representation of a temporary variable to the
     308              : // the dump file.
     309              : 
     310              : void
     311            0 : Ast_dump_context::dump_temp_variable_name(const Statement* s)
     312              : {
     313            0 :   go_assert(s->classification() == Statement::STATEMENT_TEMPORARY);
     314              :   // Use the statement address as part of the name for the temporary variable.
     315            0 :   this->ostream() << "tmp." << (uintptr_t) s;
     316            0 : }
     317              : 
     318              : // Dump a textual representation of a label to the
     319              : // the dump file.
     320              : 
     321              : void
     322            0 : Ast_dump_context::dump_label_name(const Unnamed_label* l)
     323              : {
     324              :   // Use the unnamed label address as part of the name for the temporary
     325              :   // variable.
     326            0 :   this->ostream() << "label." << (uintptr_t) l;
     327            0 : }
     328              : 
     329              : // Produce a textual representation of an operator symbol.
     330              : 
     331              : static const char*
     332            0 : op_string(Operator op)
     333              : {
     334              : // FIXME: This should be in line with symbols that are parsed,
     335              : // exported and/or imported.
     336            0 :   switch (op)
     337              :     {
     338              :     case OPERATOR_PLUS:
     339              :       return "+";
     340            0 :     case OPERATOR_MINUS:
     341            0 :       return "-";
     342            0 :     case OPERATOR_NOT:
     343            0 :       return "!";
     344            0 :     case OPERATOR_XOR:
     345            0 :       return "^";
     346            0 :     case OPERATOR_OR:
     347            0 :       return "|";
     348            0 :     case OPERATOR_AND:
     349            0 :       return "&";
     350            0 :     case OPERATOR_MULT:
     351            0 :       return "*";
     352            0 :     case OPERATOR_OROR:
     353            0 :       return "||";
     354            0 :     case OPERATOR_ANDAND:
     355            0 :       return "&&";
     356            0 :     case OPERATOR_EQEQ:
     357            0 :       return "==";
     358            0 :     case OPERATOR_NOTEQ:
     359            0 :       return "!=";
     360            0 :     case OPERATOR_LT:
     361            0 :       return "<";
     362            0 :     case OPERATOR_LE:
     363            0 :       return "<=";
     364            0 :     case OPERATOR_GT:
     365            0 :       return ">";
     366            0 :     case OPERATOR_GE:
     367            0 :       return ">=";
     368            0 :     case OPERATOR_DIV:
     369            0 :       return "/";
     370            0 :     case OPERATOR_MOD:
     371            0 :       return "%";
     372            0 :     case OPERATOR_LSHIFT:
     373            0 :       return "<<";
     374            0 :     case OPERATOR_RSHIFT:
     375            0 :       return "//";
     376            0 :     case OPERATOR_BITCLEAR:
     377            0 :       return "&^";
     378            0 :     case OPERATOR_CHANOP:
     379            0 :       return "<-";
     380            0 :     case OPERATOR_PLUSEQ:
     381            0 :       return "+=";
     382            0 :     case OPERATOR_MINUSEQ:
     383            0 :       return "-=";
     384            0 :     case OPERATOR_OREQ:
     385            0 :       return "|=";
     386            0 :     case OPERATOR_XOREQ:
     387            0 :       return "^=";
     388            0 :     case OPERATOR_MULTEQ:
     389            0 :       return "*=";
     390            0 :     case OPERATOR_DIVEQ:
     391            0 :       return "/=";
     392            0 :     case OPERATOR_MODEQ:
     393            0 :       return "%=";
     394            0 :     case OPERATOR_LSHIFTEQ:
     395            0 :       return "<<=";
     396            0 :     case OPERATOR_RSHIFTEQ:
     397            0 :       return ">>=";
     398            0 :     case OPERATOR_ANDEQ:
     399            0 :       return "&=";
     400            0 :     case OPERATOR_BITCLEAREQ:
     401            0 :       return "&^=";
     402            0 :     case OPERATOR_PLUSPLUS:
     403            0 :       return "++";
     404            0 :     case OPERATOR_MINUSMINUS:
     405            0 :       return "--";
     406            0 :     case OPERATOR_COLON:
     407            0 :       return ":";
     408            0 :     case OPERATOR_COLONEQ:
     409            0 :       return ":=";
     410            0 :     case OPERATOR_SEMICOLON:
     411            0 :       return ";";
     412            0 :     case OPERATOR_DOT:
     413            0 :       return ".";
     414            0 :     case OPERATOR_ELLIPSIS:
     415            0 :       return "...";
     416            0 :     case OPERATOR_COMMA:
     417            0 :       return ",";
     418            0 :     case OPERATOR_LPAREN:
     419            0 :       return "(";
     420            0 :     case OPERATOR_RPAREN:
     421            0 :       return ")";
     422            0 :     case OPERATOR_LCURLY:
     423            0 :       return "{";
     424            0 :     case OPERATOR_RCURLY:
     425            0 :       return "}";
     426            0 :     case OPERATOR_LSQUARE:
     427            0 :       return "[";
     428            0 :     case OPERATOR_RSQUARE:
     429            0 :       return "]";
     430            0 :     default:
     431            0 :       go_unreachable();
     432              :     }
     433              :   return NULL;
     434              : }
     435              : 
     436              : // Dump a textual representation of an operator to the
     437              : // the dump file.
     438              : 
     439              : void
     440            0 : Ast_dump_context::dump_operator(Operator op)
     441              : {
     442            0 :   this->ostream() << op_string(op);
     443            0 : }
     444              : 
     445              : // Size of a single indent.
     446              : 
     447              : const int Ast_dump_context::offset_ = 2;
     448              : 
     449              : // Print indenting spaces to dump file.
     450              : 
     451              : void
     452            0 : Ast_dump_context::print_indent()
     453              : {
     454            0 :   for (int i = 0; i < this->indent_ * this->offset_; i++)
     455            0 :     this->ostream() << " ";
     456            0 : }
     457              : 
     458              : // Dump a textual representation of the ast to the
     459              : // the dump file.
     460              : 
     461         4646 : void Gogo::dump_ast(const char* basename)
     462              : {
     463         4646 :   if (::ast_dump_flag.is_enabled())
     464              :     {
     465            0 :       Ast_dump_context adc;
     466            0 :       adc.dump(this, basename);
     467              :     }
     468         4646 : }
     469              : 
     470              : // Implementation of String_dump interface.
     471              : 
     472              : void
     473            0 : Ast_dump_context::write_c_string(const char* s)
     474              : {
     475            0 :   this->ostream() << s;
     476            0 : }
     477              : 
     478              : void
     479            0 : Ast_dump_context::write_string(const std::string& s)
     480              : {
     481            0 :   this->ostream() << s;
     482            0 : }
     483              : 
     484              : // Dump statement to stream.
     485              : 
     486              : void
     487            0 : Ast_dump_context::dump_to_stream(const Statement* stm, std::ostream* out)
     488              : {
     489            0 :   Ast_dump_context adc(out, false);
     490            0 :   stm->dump_statement(&adc);
     491            0 : }
     492              : 
     493              : // Dump expression to stream.
     494              : 
     495              : void
     496            0 : Ast_dump_context::dump_to_stream(const Expression* expr, std::ostream* out)
     497              : {
     498            0 :   Ast_dump_context adc(out, false);
     499            0 :   expr->dump_expression(&adc);
     500            0 : }
     501              : 
     502              : // Dump an expression to std::cerr. This is intended to be used
     503              : // from within a debugging session.
     504              : 
     505              : void
     506            0 : debug_go_expression(const Expression* expr)
     507              : {
     508            0 :   if (expr == NULL)
     509            0 :     std::cerr << "<null>";
     510              :   else
     511              :     {
     512            0 :       Ast_dump_context::dump_to_stream(expr, &std::cerr);
     513            0 :       std::string lstr = Linemap::location_to_string(expr->location());
     514            0 :       std::cerr << " // loc " << lstr << std::endl;
     515            0 :     }
     516            0 : }
     517              : 
     518              : // Shallow dump of stmt to std::cerr. This is intended to be used
     519              : // from within a debugging session.
     520              : 
     521              : void
     522            0 : debug_go_statement(const Statement* stmt)
     523              : {
     524            0 :   if (stmt == NULL)
     525            0 :     std::cerr << "<null>\n";
     526              :   else
     527              :     {
     528            0 :       std::string lstr = Linemap::location_to_string(stmt->location());
     529            0 :       Statement *ncstmt = const_cast<Statement*>(stmt);
     530            0 :       Block_statement* bs = ncstmt->block_statement();
     531            0 :       if (bs != NULL)
     532            0 :         std::cerr << "Block " << bs->block()
     533            0 :                   << " // location: " << lstr << std::endl;
     534              :       else
     535            0 :         Ast_dump_context::dump_to_stream(stmt, &std::cerr);
     536            0 :     }
     537            0 : }
     538              : 
     539              : // Deep dump of statement to std::cerr. This is intended to be used
     540              : // from within a debugging session.
     541              : 
     542              : void
     543            0 : debug_go_statement_deep(const Statement* statement)
     544              : {
     545            0 :   Ast_dump_context adc(&std::cerr, true);
     546            0 :   statement->dump_statement(&adc);
     547            0 : }
     548              : 
     549              : // Shallow dump of a block to std::cerr. This is intended to be used
     550              : // from within a debugging session.
     551              : 
     552              : void
     553            0 : debug_go_block(const Block* block)
     554              : {
     555            0 :   if (block == NULL)
     556            0 :     std::cerr << "<null>";
     557              :   else
     558              :     {
     559            0 :       std::cerr << "Block " << block
     560            0 :                 << " (enclosing " << block->enclosing() << "):\n";
     561            0 :       const std::vector<Statement*>* stmts = block->statements();
     562            0 :       if (stmts != NULL)
     563              :         {
     564            0 :           for (size_t i = 0; i < stmts->size(); ++i)
     565              :             {
     566            0 :               debug_go_statement(stmts->at(i));
     567              :             }
     568              :         }
     569              :     }
     570            0 : }
     571              : 
     572              : // Deep dump of a block to std:cerr. This is intended to be used
     573              : // from within a debugging session.
     574              : 
     575              : void
     576            0 : debug_go_block_deep(const Block* block)
     577              : {
     578            0 :   Ast_dump_context adc(&std::cerr, true);
     579            0 :   Block* ncblock = const_cast<Block*>(block);
     580            0 :   adc.dump_block(ncblock);
     581            0 : }
     582              : 
     583              : class Type_dumper
     584              : {
     585              :   typedef Unordered_map(const Type*, unsigned) idx_map;
     586              :  public:
     587            0 :   Type_dumper(const Type* type)
     588            0 :       : top_(type), ntypes_(0)
     589              :   {
     590            0 :     this->worklist_.push_back(type);
     591            0 :   }
     592              : 
     593              :   void visit();
     594              : 
     595            0 :   std::string stringResult() { return ss_.str(); }
     596              : 
     597              :  private:
     598              :   void emitpre(unsigned tag, const Type* addr);
     599              :   void typeref(const char*, const Type*, const char *);
     600              :   void visit_forward_declaration_type(const Forward_declaration_type* fdt);
     601              :   void visit_function_type(const Function_type* ft);
     602              :   void visit_struct_type(const Struct_type* st);
     603              :   void visit_array_type(const Array_type* at);
     604              :   void visit_map_type(const Map_type* mt);
     605              :   void visit_channel_type(const Channel_type* mt);
     606              :   void visit_interface_type(const Interface_type* mt);
     607              :   void visit_methods(const Typed_identifier_list* methods,
     608              :                      const char *tag);
     609              :   std::pair<bool, unsigned> lookup(const Type*);
     610              : 
     611              :   static const unsigned notag = 0xffffffff;
     612              : 
     613              :  private:
     614              :   const Type* top_;
     615              :   idx_map types_;
     616              :   unsigned ntypes_;
     617              :   std::list<const Type*> worklist_;
     618              :   std::ostringstream ss_;
     619              : };
     620              : 
     621              : // Look up a type, installing it in 'types_'. Return is <found, N>
     622              : // where 'found' is true if type had been previously recorded, and N
     623              : // is the index/tag assigned to N.  The input argument is appended to
     624              : // the work list if this is the first time we've seen it.
     625              : 
     626            0 : std::pair<bool, unsigned> Type_dumper::lookup(const Type* t)
     627              : {
     628            0 :   std::pair<const Type*, unsigned> entry = std::make_pair(t, this->ntypes_);
     629            0 :   std::pair<idx_map::iterator, bool> ins = this->types_.insert(entry);
     630            0 :   if (ins.second)
     631              :     {
     632            0 :       this->ntypes_++;
     633            0 :       if (t != this->top_)
     634            0 :         this->worklist_.push_back(t);
     635              :     }
     636            0 :   return std::make_pair(ins.second, ins.first->second);
     637              : }
     638              : 
     639              : // Emit preamble prior to dumping a type, including the type
     640              : // pointer itself and the tag we've assigned it.  If no
     641              : // tag is specified (via special "notag" value) and/or the
     642              : // pointer is null, then just emit an equivalent amount
     643              : // of spaces.
     644              : 
     645            0 : void Type_dumper::emitpre(unsigned tag, const Type* ptr)
     646              : {
     647            0 :   char tbuf[50], pbuf[50], buf[200];
     648              : 
     649            0 :   tbuf[0] = '\0';
     650            0 :   if (tag != notag)
     651            0 :     snprintf(tbuf, sizeof tbuf, "T%u", tag);
     652              : 
     653            0 :   pbuf[0] = '\0';
     654            0 :   if (ptr != NULL)
     655            0 :     snprintf(pbuf, sizeof pbuf, "%p", (const void*) ptr);
     656              : 
     657            0 :   snprintf(buf, sizeof buf, "%8s %16s  ", tbuf, pbuf);
     658            0 :   this->ss_ << buf;
     659            0 : }
     660              : 
     661              : // Emit a reference to a type into the dump buffer. In most cases this means
     662              : // just the type tag, but for named types we also emit the name, and for
     663              : // simple/primitive types (ex: int64) we emit the type itself. If "pref" is
     664              : // non-NULL, emit the string prior to the reference, and if "suf" is non-NULL,
     665              : // emit it following the reference.
     666              : 
     667            0 : void Type_dumper::typeref(const char* pref, const Type* t, const char* suf)
     668              : {
     669            0 :   if (pref != NULL)
     670            0 :     this->ss_ << pref;
     671            0 :   std::pair<bool, unsigned> p = this->lookup(t);
     672            0 :   unsigned tag = p.second;
     673            0 :   switch (t->classification())
     674              :     {
     675            0 :       case Type::TYPE_NAMED:
     676            0 :         {
     677            0 :           const Named_type* nt = t->named_type();
     678            0 :           const Named_object* no = nt->named_object();
     679            0 :           this->ss_ << "'" << no->message_name() << "' -> ";
     680            0 :           const Type* underlying = nt->real_type();
     681            0 :           this->typeref(NULL, underlying, NULL);
     682            0 :           break;
     683              :         }
     684            0 :       case Type::TYPE_POINTER:
     685            0 :         this->typeref("*", t->points_to(), NULL);
     686            0 :         break;
     687            0 :       case Type::TYPE_ERROR:
     688            0 :         this->ss_ << "error_type";
     689            0 :         break;
     690            0 :       case Type::TYPE_INTEGER:
     691            0 :         {
     692            0 :           const Integer_type* it = t->integer_type();
     693            0 :           if (it->is_abstract())
     694            0 :             this->ss_ << "abstract_int";
     695              :           else
     696            0 :             this->ss_ << (it->is_unsigned() ? "u" : "") << "int" << it->bits();
     697              :           break;
     698              :         }
     699            0 :       case Type::TYPE_FLOAT:
     700            0 :         {
     701            0 :           const Float_type* ft = t->float_type();
     702            0 :           if (ft->is_abstract())
     703            0 :             this->ss_ << "abstract_float";
     704              :           else
     705            0 :             this->ss_ << "float" << ft->bits();
     706              :           break;
     707              :         }
     708            0 :       case Type::TYPE_COMPLEX:
     709            0 :         {
     710            0 :           const Complex_type* ct = t->complex_type();
     711            0 :           if (ct->is_abstract())
     712            0 :             this->ss_ << "abstract_complex";
     713              :           else
     714            0 :             this->ss_ << "complex" << ct->bits();
     715              :           break;
     716              :         }
     717            0 :       case Type::TYPE_BOOLEAN:
     718            0 :         this->ss_ << "bool";
     719            0 :         break;
     720            0 :       case Type::TYPE_STRING:
     721            0 :         this->ss_ << "string";
     722            0 :         break;
     723            0 :       case Type::TYPE_NIL:
     724            0 :         this->ss_ << "nil_type";
     725            0 :         break;
     726            0 :     case Type::TYPE_VOID:
     727            0 :         this->ss_ << "void_type";
     728            0 :         break;
     729            0 :     case Type::TYPE_FUNCTION:
     730            0 :     case Type::TYPE_STRUCT:
     731            0 :     case Type::TYPE_ARRAY:
     732            0 :     case Type::TYPE_MAP:
     733            0 :     case Type::TYPE_CHANNEL:
     734            0 :     case Type::TYPE_FORWARD:
     735            0 :     case Type::TYPE_INTERFACE:
     736            0 :       this->ss_ << "T" << tag;
     737            0 :       break;
     738              : 
     739            0 :     default:
     740              :       // This is a debugging routine, so instead of a go_unreachable()
     741              :       // issue a warning/error, to allow for the possibility that the
     742              :       // compiler we're debugging is in a bad state.
     743            0 :       this->ss_ << "<??? " << ((unsigned)t->classification()) << "> "
     744            0 :                 << "T" << tag;
     745              :     }
     746            0 :   if (suf != NULL)
     747            0 :     this->ss_ << suf;
     748            0 : }
     749              : 
     750            0 : void Type_dumper::visit_forward_declaration_type(const Forward_declaration_type* fdt)
     751              : {
     752            0 :   this->ss_ << "forward_declaration_type ";
     753            0 :   if (fdt->is_defined())
     754            0 :     this->typeref("-> ", fdt->real_type(), NULL);
     755              :   else
     756            0 :     this->ss_ << "'" << fdt->name() << "'";
     757            0 :   this->ss_ << "\n";
     758            0 : }
     759              : 
     760            0 : void Type_dumper::visit_function_type(const Function_type* ft)
     761              : {
     762            0 :   this->ss_ << "function\n";
     763            0 :   const Typed_identifier* rec = ft->receiver();
     764            0 :   if (rec != NULL)
     765              :     {
     766            0 :       this->emitpre(notag, NULL);
     767            0 :       this->typeref("receiver ", rec->type(), "\n");
     768              :     }
     769            0 :   const Typed_identifier_list* parameters = ft->parameters();
     770            0 :   if (parameters != NULL)
     771              :     {
     772            0 :       for (Typed_identifier_list::const_iterator p = parameters->begin();
     773            0 :            p != parameters->end();
     774            0 :            ++p)
     775              :         {
     776            0 :           this->emitpre(notag, NULL);
     777            0 :           this->typeref(" param ", p->type(), "\n");
     778              :         }
     779              :     }
     780            0 :   const Typed_identifier_list* results = ft->results();
     781            0 :   if (results != NULL)
     782              :     {
     783            0 :       for (Typed_identifier_list::const_iterator p = results->begin();
     784            0 :            p != results->end();
     785            0 :            ++p)
     786              :         {
     787            0 :           this->emitpre(notag, NULL);
     788            0 :           this->typeref(" result ", p->type(), "\n");
     789              :         }
     790              :     }
     791            0 : }
     792              : 
     793            0 : void Type_dumper::visit_struct_type(const Struct_type* st)
     794              : {
     795            0 :   this->ss_ << "struct\n";
     796            0 :   const Struct_field_list* fields = st->fields();
     797            0 :   if (fields != NULL)
     798              :     {
     799            0 :       for (Struct_field_list::const_iterator p = fields->begin();
     800            0 :            p != fields->end();
     801            0 :            ++p)
     802              :         {
     803            0 :           this->emitpre(notag, NULL);
     804            0 :           this->typeref(" field ", p->type(), "\n");
     805              :         }
     806              :     }
     807            0 : }
     808              : 
     809            0 : void Type_dumper::visit_array_type(const Array_type* at)
     810              : {
     811            0 :   this->ss_ << "array [";
     812            0 :   if (at->length() != NULL)
     813              :     {
     814            0 :       int64_t len = 0;
     815            0 :       if (at->int_length(&len))
     816            0 :         this->ss_ << len;
     817              :     }
     818            0 :   this->typeref("] ", at->element_type(), "\n");
     819            0 : }
     820              : 
     821            0 : void Type_dumper::visit_map_type(const Map_type* mt)
     822              : {
     823            0 :   this->ss_ << "map [";
     824            0 :   this->typeref(NULL, mt->key_type(), NULL);
     825            0 :   this->typeref("] ", mt->val_type(), "\n");
     826            0 : }
     827              : 
     828            0 : void Type_dumper::visit_methods(const Typed_identifier_list* methods,
     829              :                                 const char *tag)
     830              : {
     831            0 :   if (tag != NULL)
     832              :     {
     833            0 :       this->emitpre(notag, NULL);
     834            0 :       this->ss_ << tag << "\n";
     835              :     }
     836            0 :   for (Typed_identifier_list::const_iterator p = methods->begin();
     837            0 :        p != methods->end();
     838            0 :        ++p)
     839              :     {
     840            0 :       this->emitpre(notag, NULL);
     841            0 :       if (p->name().empty())
     842            0 :         this->typeref("  embedded method ", p->type(), "\n");
     843              :       else
     844              :         {
     845            0 :           this->ss_ << "  method '" << p->name() << "' ";
     846            0 :           this->typeref(NULL, p->type(), "\n");
     847              :         }
     848              :     }
     849            0 : }
     850              : 
     851            0 : void Type_dumper::visit_interface_type(const Interface_type* it)
     852              : {
     853            0 :   const Typed_identifier_list* methods =
     854            0 :       (it->methods_are_finalized() ? it->methods() : it->local_methods());
     855            0 :   if (methods == NULL)
     856              :     {
     857            0 :       this->ss_ << "empty_interface\n";
     858            0 :       return;
     859              :     }
     860            0 :   this->ss_ << "interface";
     861            0 :   if (! it->methods_are_finalized())
     862              :     {
     863            0 :       this->ss_ << " [unfinalized]\n";
     864            0 :       visit_methods(it->local_methods(), NULL);
     865              :     }
     866              :   else
     867              :     {
     868            0 :       this->ss_ << "\n";
     869            0 :       visit_methods(it->local_methods(), "[parse_methods]");
     870            0 :       visit_methods(it->methods(), "[all_methods]");
     871              :     }
     872              : }
     873              : 
     874            0 : void Type_dumper::visit_channel_type(const Channel_type* ct)
     875              : {
     876            0 :   this->ss_ << "channel {";
     877            0 :   if (ct->may_send())
     878            0 :     this->ss_ << " send";
     879            0 :   if (ct->may_receive())
     880            0 :     this->ss_ << " receive";
     881            0 :   this->typeref(" } ", ct->element_type(), "\n");
     882            0 : }
     883              : 
     884            0 : void Type_dumper::visit()
     885              : {
     886            0 :   while (! this->worklist_.empty()) {
     887            0 :     const Type* t = this->worklist_.front();
     888            0 :     this->worklist_.pop_front();
     889              : 
     890            0 :     std::pair<bool, unsigned> p = this->lookup(t);
     891            0 :     unsigned tag = p.second;
     892            0 :     this->emitpre(tag, t);
     893              : 
     894            0 :     switch(t->classification())
     895              :       {
     896            0 :         case Type::TYPE_ERROR:
     897            0 :         case Type::TYPE_INTEGER:
     898            0 :         case Type::TYPE_FLOAT:
     899            0 :         case Type::TYPE_COMPLEX:
     900            0 :         case Type::TYPE_BOOLEAN:
     901            0 :         case Type::TYPE_STRING:
     902            0 :         case Type::TYPE_VOID:
     903            0 :         case Type::TYPE_POINTER:
     904            0 :         case Type::TYPE_NIL:
     905            0 :         case Type::TYPE_NAMED:
     906            0 :           this->typeref(NULL, t, "\n");
     907            0 :           break;
     908            0 :         case Type::TYPE_FORWARD:
     909            0 :           this->visit_forward_declaration_type(t->forward_declaration_type());
     910            0 :           break;
     911              : 
     912            0 :         case Type::TYPE_FUNCTION:
     913            0 :           this->visit_function_type(t->function_type());
     914            0 :           break;
     915            0 :         case Type::TYPE_STRUCT:
     916            0 :           this->visit_struct_type(t->struct_type());
     917            0 :           break;
     918            0 :         case Type::TYPE_ARRAY:
     919            0 :           this->visit_array_type(t->array_type());
     920            0 :           break;
     921            0 :         case Type::TYPE_MAP:
     922            0 :           this->visit_map_type(t->map_type());
     923            0 :           break;
     924            0 :         case Type::TYPE_CHANNEL:
     925            0 :           this->visit_channel_type(t->channel_type());
     926            0 :           break;
     927            0 :         case Type::TYPE_INTERFACE:
     928            0 :           this->visit_interface_type(t->interface_type());
     929            0 :           break;
     930            0 :         default:
     931              :           // This is a debugging routine, so instead of a go_unreachable()
     932              :           // issue a warning/error, to allow for the possibility that the
     933              :           // compiler we're debugging is in a bad state.
     934            0 :           this->ss_ << "<unknown/unrecognized classification "
     935            0 :                     << ((unsigned)t->classification()) << ">\n";
     936              :       }
     937              :   }
     938            0 : }
     939              : 
     940              : // Dump a Go type for debugging purposes. This is a deep as opposed
     941              : // to shallow dump; all of the types reachable from the specified
     942              : // type will be dumped in addition to the type itself.
     943              : 
     944            0 : void debug_go_type(const Type* type)
     945              : {
     946            0 :   if (type == NULL)
     947              :     {
     948            0 :       std::cerr << "<NULL type>\n";
     949            0 :       return;
     950              :     }
     951            0 :   Type_dumper dumper(type);
     952            0 :   dumper.visit();
     953            0 :   std::cerr << dumper.stringResult();
     954            0 : }
     955              : 
     956            0 : void debug_go_type(Type* type)
     957              : {
     958            0 :   const Type* ctype = type;
     959            0 :   debug_go_type(ctype);
     960            0 : }
        

Generated by: LCOV version 2.4-beta

LCOV profile is generated on x86_64 machine using following configure options: configure --disable-bootstrap --enable-coverage=opt --enable-languages=c,c++,fortran,go,jit,lto,rust,m2 --enable-host-shared. GCC test suite is run with the built compiler.